basics of iOS and OS X API’s


The structure of OS X and iOS native* API’s is very straight forward/minimalistic, typically one does not need to know about anything that goes below the Foundation API however taking a look at the headers can help understanding it better and clearing common confusions between Foundation and CoreFoundation or what exactly constitutes CocoaTouch and Cocoa since the later is a explicit framework while the former is just a naming convention.

All the API’s are present as binary frameworks under /System/Library/Frameworks (with resources but without headers) and under your Xcode toolchain SDK (with headers but without resources) , the objc binary is at /usr/lib/libobjc.A.dylib while the headers are under /usr/include/objc/ and your Xcode toolchain.

I
Now let’s dig right into it, at the lowest level there is CoreFoundation and objc, they are independent of each other :

<objc/objc.h>
objc_class,objc_object,objc_selector etc

<objc/runtime.h>
objc_getClass,objc_getProtocol,class_conformsToProtocol etc

<objc/message.h>
super_class,objc_super,objc_msgSend,objc_msgSendSuper etc

(you can include all the above with #import <objc/objc-class.h>)

<CoreFoundation/CoreFoundation.h>
CFString,CFNumber,CFArray,CFRunLoop,CFStream etc (this is just C, there is no Objective-C syntax or anything at this level)

II
On top of these and including (relying on both) is Foundation, as the name implies you typically never use any API’s below foundation directly.

<Foundation/Foundation.h>
NSString,NSNumber,NSArray,NSRunLoop,NSStream etc, much of it is toll-free bridged to CoreFoundation

III
on top of Foundation there is AppKit for OS X or UIKit for iOS
(on OS X you typically include Foundation, AppKit and CoreData with #import <Cocoa/Cocoa.h>, there is no corresponding CocoaTouch shell framework on iOS)

<AppKit/AppKit.h>
NSView,NSButton,NSColor,NSEvent etc

<UIKit/UIKit.h>
UIView,UIButton,UIColor,UIEvent etc

This is pretty much all there is, from this on there are multiple optional frameworks you can use for specific cases, but the basics are just in the headers above, most API’s are Cocoa but there is still a big chunk of C API’s especially on the OS X side.

It’s worth nothing that there are two types of frameworks : private and public , the private ones are not safe to be used and not allowed in the Mac App Store , the public ones are safe to be used as long as they have headers in the SDK (they could be present in /System/Library/Frameworks but not in the SDK) typically such disparity is a rare occasion nowadays and it was more common prior to 10.6.

One more note is that public frameworks with headers might not have all their methods/classes documented, nevertheless using them should be pretty safe but the lack of documentation is a indication that they are more likely to change/go away than the documented ones.

*OS X and IOS also have the low level BSD API’s (found in /usr/include) most of which are cross-platform and outside the scope of this post.

iOS and vectorial artwork

Any conscious iOS developer wants his artwork to look as good as possible, and with the retina display for example we were told to upgrade our artwork to higher resolution, which involved alternative @2x versions for each file and gets daunting fast if you have a lot of artwork files, and especially if a lot of your artwork is vectorial and you could just use it directly.

A popular vectorial format is PDF, and Apple has implemented a lot of the resolution independent artwork in their OSX apps as PDF, unfortunately there is no straightforward way to do that, the iOS SDK does not yet have the PDFKit.framework that exists on OSX (Interface Builder does still accept pdf files as images but they will not show on iOS) so what is there to do ?

Well the only way to do it currently is to set your artwork images in code, after rendering the PDF file into a UIImage, there are a couple of approaches to this and i am going to show you the one i use :

#include <dlfcn.h>

-(UIImage *)UIImageFromPDF:(NSString*)fileName size:(CGSize)size{
    CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), (CFStringRef)fileName, NULL, NULL);
    if (pdfURL) {
        CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL(pdfURL);
        CFRelease(pdfURL);
        //create context with scaling 0.0 as to get the main screen's if iOS4+
        if (dlsym(RTLD_DEFAULT,"UIGraphicsBeginImageContextWithOptions") == NULL) {
            UIGraphicsBeginImageContext(size);
        }else {
            UIGraphicsBeginImageContextWithOptions(size,NO,0.0);
        }
        CGContextRef context = UIGraphicsGetCurrentContext();
        //translate the content
        CGContextTranslateCTM(context, 0.0, size.height);
        CGContextScaleCTM(context, 1.0, -1.0);
        CGContextSaveGState(context);
        //scale to our desired size
        CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);
        CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page,kCGPDFCropBox,CGRectMake(0,0,size.width,size.height),0,true);
        CGContextConcatCTM(context, pdfTransform);
        CGContextDrawPDFPage(context, page);
        CGContextRestoreGState(context);
        //return autoreleased UIImage
        UIImage *ret = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        CGPDFDocumentRelease(pdf);
        return ret;
    }else {
        NSLog(@"Could not load %@",fileName);
    }
    return nil;
}

Typically you would use it like this : [someButton setImage:[self UIImageFromPDF:@”search.pdf” size:CGSizeMake(20,20)] forState:UIControlStateNormal];

The best thing about this is that it not only makes your artwork compatible with the current form and scaling factors, but most likely with further ones as well.

This is compatible with iOS 3.0+ and has been tested on iPhone and iPad, it is compatible with any resolution scaling (retina display has 2.0 for example) , i have also attached 4 pdf icons to get you started (created with Photoshop, exported with no layers or color profiles).

If for some reason you do not want to #include dlfcn.h and use dlsym() you can weak link UIKit and just check if UIGraphicsBeginImageContextWithOptions is NULL, or obviously if you are not supporting anything before iOS4 remove the conditional altogether.

NOTE: technically on IOS 4  you can currently exploit a bug and load a pdf file from [UIImage imageNamed:@”filename”] by stripping the extension, however the default size of the artwork in the pdf has to be exactly the size of the UIImage you want, if it gets scaled significant pixelation occurs basically making this shortcut unfeasible, plus it could stop working altogether at any time.

how to make your iOS device read stuff

Here is a little handy tip to make your device speak textual content with almost acceptable computer voice:

Go to Settings > General > Accessibility > Triple-click home to “Toggle VoiceOver” or “Ask” if you want to get a dialog asking wether to turn it On/Off (remember that tapping is done by double-tapping when voiceover is on).

Optionally go into Settings > General > Accessibility > Voiceover and set the “Speaking Rate” slider to around 20%, i found that speed to work best for me when reading papers.

Now go to your book or webpage or anything you want read and triple-click home and behold the machine start speaking your currently selected element,

Remember to turn voiceover off when you are done or else you will have to interact with the phone interface in a a whole different way (if by any chance you lock the device as i did you can unlock it by tapping the swipe bar to select it then tapping it again to unlock).

The major pitfalls besides the surprisingly hard to perform triple-tap home is that you have to select any text blocks you want read, and while this might be acceptable for pdf books where you can select a whole page in basically everything else you have to select individual paragraphs, even sentences, so do not expect a audiobook experience, and do not expect it to speak the contents of apps that do not have selectable text like WSJ, NYT etc (BBC/Reuters/AP work).

It is a shame Apple did not make it possible for this to be implemented as a book/content speaker with a consistent behavior and without relying on voiceover tricks, as it will even support reading in a lot of other languages than English, (for the full list see this for iPad and this for the other devices)

Voiceover is only available on iPhone 3GS, 4, iPad and 3rd generation iPod touch.