github twitter email rss
Objective C
0001 Jun 1
37 minutes read

Objective C

Documentation

TODO

- [Window Programming Guide](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/WinPanel/Introduction.html#//apple_ref/doc/uid/10000031i)
- [Threading Programming Guide](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/Introduction/Introduction.html#//apple_ref/doc/uid/10000057i)

- Coding Guidelines for Cocoa

- App Distribution Guide(https://developer.apple.com/Library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40012582-CH1-SW1)

- User Interface Preservation https://developer.apple.com/library/mac/documentation/General/Conceptual/MOSXAppProgrammingGuide/CoreAppDesign/CoreAppDesign.html#//apple_ref/doc/uid/TP40010543-CH3-SW26

- Mac Technology Overview
  + Media Layer https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/OSX_Technology_Overview/MediaLayer/MediaLayer.html#//apple_ref/doc/uid/TP40001067-CH273
  + Kernel and Device Drivers Layer

- Cocoa Core Competencies
  + Block object(https://developer.apple.com/library/mac/documentation/General/Conceptual/DevPedia-CocoaCore/Block.html#//apple_ref/doc/uid/TP40008195-CH3-SW1)
  + Message(https://developer.apple.com/library/mac/documentation/General/Conceptual/DevPedia-CocoaCore/Message.html#//apple_ref/doc/uid/TP40008195-CH59-SW1)
  + Enumeration(https://developer.apple.com/library/mac/documentation/General/Conceptual/DevPedia-CocoaCore/Enumeration.html#//apple_ref/doc/uid/TP40008195-CH17-SW1)
  + bundle
  + property list file 
  + code signing
  + framework
  + Model-View-Controller
  + Delegation
  + protocol
  + responder chain
  + first responder
  + Target-action
  + Block object
  + Notification
  + Key-value observing (KVO)
  + Key-value coding
  + Dynamic binding
  + responder object
  + class method
  + Xcode Project
  + Xcode Workspace
  + Xcode Target
  + Xcode Scheme
  + Information property list
  + Nib file

- [Daemons and Services Programming Guide](https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/Introduction.html#//apple_ref/doc/uid/10000172i)

- [Keychain Services Programming Guide]()

- File System Programming Guide.

- HIG(https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/index.html#//apple_ref/doc/uid/20000957)

- Cocoa Event Handling Guide https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/Introduction/Introduction.html#//apple_ref/doc/uid/10000060i

- Core Animation Programming Guide https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreAnimation_guide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40004514
- Quick Look Programming Guide https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/Quicklook_Programming_Guide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40005020

- Document-Based App Programming Guide for Mac https://developer.apple.com/library/mac/documentation/DataManagement/Conceptual/DocBasedAppProgrammingGuideForOSX/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011179

- Key-Value Observing Programming Guide

- [Archives and Serializations Programming Guide](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Archiving/Archiving.html#//apple_ref/doc/uid/10000047i)
- Introduction to Core Foundation Design Concepts
- Memory Management Programming Guide for Core Foundation
- Advanced Memory Management Programming Guide
- Transitioning to ARC Release Notes

- Cocoa Event Handling Guide
- Basic Programming Concepts for Cocoa and Cocoa Touch
- Mac App Programming Guide
- Notification Programming Topics
- Predicate Programming Guide
- Core Data Programming Guide
- Cocoa Bindings Programming Topics
- Collections Programming Topics
- Collections Programming Topics for Core Foundation
- Collection View Programming Guide
- Bundle Programming Guide
    + Accessing a Bundle’s Contents 
- Resource Programming Guide
- Cocoa Core Competencies

- Threading Programming Guide
- Cocoa Scripting Guide
- High Resolution Guidelines for OS X
    + Optimizing for High Resolution
- Core Animation Programming Guide
    + Animating Multiple Changes Together
- Core Animation Cookbook

- Automating Version and Build Numbers Using agvtool

Main classes

NSApplication.sharedApplication()

Automatic Termination

  • NSSupportsAutomaticTermination key (with the value YES) in the app’s Info.plist
  • NSProcessInfo

Autosave

  • NSDocument override autosavesInPlace return YES
  • Approopriate places to save data
    • applicationWillTerminate:
    • applicationWillResignActive:
    • applicationWillHide:
    • user makes a valid change to data

Sudden Termination

  • NSSupportsSuddenTermination YES in Info.plist
  • Keep enabled and when need disable to prevent data loss, NSProcessInfo disableSuddenTermination and enableSuddenTermination

Automatic relauch

  • disableRelaunchOnLogin
  • enableRelaunchOnLogin


UI

MainMenu.xib

UI Preservation

doc.

  • NSWindow setRestorable, setRestorationClass:
  • NSWindow, NSView, window controller impl encodeRestorableStateWithCoder: overr restorableStateKeyPaths
  • NSWindowDelegate impl window:willEncodeRestorableState:
  • invalidateRestorableState

    Restoring at Launch Time

  • restoreWindowWithIdentifier:state:completionHandler:

  • window:didDecodeRestorableState:

Drawing, NSView

docs: Cocoa Drawing Guide

  • Native drawing technologies (such as Core Graphics and AppKit)
    • implement a drawRect: method.
    • setNeedsDisplay: or setNeedsDisplayInRect:
  • OpenGL

docs: Application Menu and Pop-up List Programming Topics
docs: Designing User Interfaces in Xcode

  • NSMenu NSMenuItem
  • NSMenuValidation protocol

Text

docs: Cocoa Text Architecture Guide

Number Formatter

High resolution

docs: [High Resolution Guidelines for OS X]()

  • circle.png circle@2x.png.
  • Xcode option Combine High Resolution Artwork to Yes in Target Build Settings under Deployment.
  • icon.iconset folder -> iconutil -> .icns
  • NSImage imageNamed:
  • NSBundle imageForResource:
  • NSImage initWithCGImage:size: specifying the image size in points
  • NSCursor initWithImage:hotSpot: multirepresentation TIFF

Dock

docs: [Dock Tile Programming Guide]

  • override applicationDockMenu:

User Notification Center, NSUserNotificationCenter, Today extensions

docs: [App Extension Programming Guide]()
NSUserNotificationCenter, NSUserNotification
host app,

Extensions points

Today (widget)

NCWidgetProviding
NCWidgetProvidingPresentationStyles
NSExtensionContext openURL:completionHandler:
NSExtensionAdditions


Name:
InfoPlist.strings
CFBundleDisplayName
widget.description

Share

Action

Cocoa Auto Layout

docs: [Auto Layout Guide]()

Constraints

Popovers

NSPopover

Vibrancy

NSVisualEffectView
NSAppearanceNameAqua

Preferences and Settings

docs: [Preferences and Settings Programming Guide]()

  • NSUserDefaults
  • NSUserDefaultsController for binding views to defaults stored in NSUserDefaults

Spotlight

docs: [Spotlight Importer Programming Guide]()
docs: [File Metadata Search Programming Guide]()
docs: [Spotlight Overview]()

  • NSMetadataQuery

    Search Kit

Ink Kit

docs: [Using Ink Services]()

Automator

docs: [Automator Programming Guide]()

Services

docs: [Services Implementation Guide]()

Daemons

docs: Daemons and Services Programming Guide

Types

| Type | Managed by launchd? | Run in which context? | Can present UI? |
+—————————————————————————————————————–+
| Login item | No* | User | Yes |
| XPC service | Yes | User | No (Except in a very limited way using IOSurface) |
| Launch Daemon | Yes | System | No |
| Launch Agent | Yes | User | Not recommended |

Communication

Login Items

Service Management framework

are not visible in System Preferences
Helper app stored in Contents/Library/LoginItems with LSUIElement or LSBackgroundOnly key in the Info.plist
SMLoginItemSetEnabled:

shared file list

Launch Services Reference
LSSharedFileList.h
http://rhult.github.io/articles/preference-to-launch-on-login/
http://rhult.github.io/articles/sandboxed-launch-on-login/
http://stackoverflow.com/questions/23625255/how-can-i-make-program-automatically-startup-on-login

XPC

XPC service is a bundle in the Contents/XPCServices

XPC Services C API

Low level xpc.c connection.h

NSXPCConnection API

Use with Foundation and Mac OS X v10.8 and later

Preference Panes

docs: [Preference Pane Programming Guide]()

Frameworks

A type of bundle that packages a dynamic shared library with the resources and header files that support that library.
docs: [Framework Programming Guide]()

Cocoa Umbrella Framework

AppKit

Foundation

Core Data

Application Services Umbrella Framework

Core Graphics

Quartz Umbrella Framework

QuartzCore

Core Image

docs: [Core Image Programming Guide]()
docs: [Core Image Filter Reference]()

  • CoreVideo
  • CoreAnimation

QuartzComposer

docs: [Quartz Composer Programming Guide]()

QuartzFilters

PDFKit

ImageKit

QuickLookUI

Accelerate umbrella framework

docs: [vImage Programming Guide ]()
docs: [vImage Reference Collection]()
docs: [vecLib Reference]()

vecLib

vImage

Disk Arbitration

  • GameKit
  • PreferencePanes
  • ScreenSaver
  • Security Interface

Accounts

Social

iCloud

CloudKit

Core Services

Launch Services

docs: [ Launch Services Programming Guide]()
LSCopyApplicationURLsForURL, LSCopyDefaultHandlerForURLScheme

Metadata

Search Kit

Web Services Core

Dictionary Services

docs: [Dictionary Services Programming Guide]()

Event Kit

Store Kit

docs: [In-App Purchase Programming Guide]()

WebKit

docs: [WebKit Objective-C Programming Guide]()

Core data

docs: Core Data Programming Guide
docs: [Optimizing Core Data with Instruments.]()

managed object context <-> persistent store coordinator <-> persistent object store
managed object model

Core Animation, Layers

docs: [Core Animation Programming Guide]()

QuartzCore/QuartzCore.h
CALayer* myLayer = [CALayer layer];
myLayer.bounds = CGRectMake(0,0,w,h);
myLayer.position = CGPointMake(x,y);
myLayer.content = familyImage;
[view.layer addSubLayer:myLayer];

CALayer

  (CGPoint)position
  (CGRect = {CGSize, CGPoint})bounds
  anchorPoint
  frame

  position
  scale
  rotation 
  perspective

   delegate method -drawLayer:inContext:
   overridden -drawInContext: 

CATransaction

duration
timing function

layer’s position on the screen

    aLayer.position = CGPointMake(20,20);

    [CATransaction begin];
    [CATransaction setValue:[NSNumber numberWithFloat:10.0f]
        forKey:kCATransactionAnimationDuration];
    aLayer.position = CGPointMake(20,20);
    [CATransaction commit];

Game Center

docs: [Game Center Programming Guide]()

Core Drawing

docs: Cocoa Drawing Guide

Core Graphics (Quartz 2D)

docs: [Quartz 2D Programming Guide]()

AlphaFirst => The Alpha channel is next to the Red channel
(ARGB and BGRA are both Alpha First formats)

AlphaLast => The Alpha channel is next to the Blue channel
(RGBA and ABGR are both Alpha Last formats)

LittleEndian => Blue comes before Red 
(BGRA and ABGR are Little endian formats)

BigEndian => Red comes before Blue 
(ARGB and RGBA are Big endian formats).

If you are working with RGBA images you use kCGBitmapByteOrder32Big combined with kCGImageAlphaLast or kCGImageAlphaPremultipliedLast or kCGImageAlphaNoneSkipLast.

If you are working with BGRA images you use kCGBitmapByteOrder32Little combined with kCGImageAlphaFirst or kCGImageAlphaPremultipliedFirst or kCGImageAlphaNoneSkipFirst.

Core Text

docs: [Core Text Programming Guide]()
docs: [Core Text Reference Collection]()

Image I/O

docs: [Image I/O Programming Guide]()

Image Kit

docs: [ImageKit Programming Guide]()

SpriteKit

SceneKit

OpenGL

docs: [OpenGL Programming Guide]()

GLKit

OpenCL

  • c like language
  • runtime api
  • descovery
  • setup
  • execution

Image Capture Core

AV Foundation

docs: [AV Foundation Programming Guide]()
AVAsset, AVAudioPlayer

QTKit

Quick Time

OpenAL

Core Audio

docs: [Core Audio Overview]()
docs: [Core Audio Framework Reference]()

Core Audio Kit

Audio Toolbox

Audio Unit

Core MIDI

AVKit

Core Media

Core Video

XML Parsing

docs: [Event-Driven XML Programming Guide]()
docs: [Tree-Based XML Programming Guide]()
NSXML, NSXMLParser

Distributed Notifications

docs: [Notification Programming Topics]()
CFNotificationCenter, NSDistributedNotificationCenter

Sharing

NSSharingService, NSSharingServicePicker

Caching API

libcache, NSCache

Multiple User Environment, Fast User Switching

docs: [Multiple User Environment Programming Topics]()

App Store

docs: [App Store Resource Center]()
docs: App Distribution Guide
docs: [App Distribution Quick Start]()

XCode

docs: Xcode Overview
docs: [Xcode Build System Guide]()

  • Dead Code Stripping
  • Generate Debug Symbols

Information Property List

only can contains NSArray, NSDictionary, NSNumber, NSString, NSDate, NSData
docs: Information Property List Key Reference.
docs: [Property List Programming Guide]()
docs: [Property List Programming Topics for Core Foundation]()
```
(void)writeToFile:(NSString *)path atomically:(BOOL)atom; // NSDictionary
```


Instruments

docs: Instruments User Guide

Bundle

docs: [Resource Programming Guide]()
docs: [Bundle Programming Guide]()

  • NSBundle mainBundle

Internationalization

docs: [Internationalization and Localization Guide.]()
docs: [Data Formatting Guide for Core Foundation]()

  • .lproj dir
  • language code ISO 639-1
  • regional code ISO 3166-1

Performance, Responsiveness

  • small awakeFromNib
  • for heavy stuff applicationDidFinishLaunching:
  • simple main .nib

Memory

docs: Memory Usage Performance Guidelines

  • avoid global variables, in frameworks particularly


Concurrency, Parallelism, Threads, Grand Central Dispatch (GCD)

docs: Concurrency Programming Guide

  • Threads, NSThread
  • Operation objects, NSOperation
  • Grand Central Dispatch (GCD)

  • first-in, first-out

  • serial dispatch queue

  • concurrent dispatch queue

  • function or a block object.

NSThread

Operation Queue (Cocoa)

NSOperationQueue

operations in a first-in-first-out order

NSOperationQueue* mainQueue = [NSOperationQueue mainQueue];

  [mainQueue addOperationWithBlock:^{
      // Add code here

}];

// Getting the main queue (will run on the main thread)
NSOperationQueue* mainQueue = [NSOperationQueue mainQueue];

// Creating a new queue (will run on a background thread, probably)
NSOperationQueue* newQueue = [[NSOperationQueue alloc] init];

[mainQueue addOperationWithBlock:^{

NSLog(@"This operation ran on the main queue!");

}];

[newQueue addOperationWithBlock:^{

NSLog(@"This operation ran on another queue!");

}];

[newQueue addOperationWithBlock:^{

// Do some work in the background

// Schedule a block on the main queue
[mainQueue addOperationWithBlock:^{
  // GUI work can safely be done here.
}]; 

}];

NSOperation - is a task

NSInvocationOperation

@implementation MyCustomClass
- (NSOperation*)taskWithData:(id)data {
    NSInvocationOperation* theOp = [[NSInvocationOperation alloc] initWithTarget:self
                    selector:@selector(myTaskMethod:) object:data];

   return theOp;
}

// This is the method that does the actual work of the task.
- (void)myTaskMethod:(id)data {
    // Perform the task.
}
@end

NSBlockOperation

NSBlockOperation* theOp = [NSBlockOperation blockOperationWithBlock: ^{

    NSLog(@"Beginning operation.\n");
    // Do some work.
 }];

addExecutionBlock:

NSLock

NSRecursiveLock

NSConditionLock NSCondition

NSMachPort NSMessagePort NSSocketPort

Dispatch Sources

Timers
Signal handlers
Descriptor-related events
Process-related events
Mach port events
Custom events that you trigger

enumerate the tasks your application performs and the objects or data structures associated with each task.

performSelectorInBackground:(SEL)aSelector withObject:(id)arg

ComputeMethodForThread {

@autoreleasepool {
    // Code that creates autoreleased objects.
}

}

NSRunLoop

Accessibility

docs: Carbon accessibility Reference https://developer.apple.com/library/mac/documentation/Accessibility/Reference/AccessibilityCarbonRef/Reference/reference.html
docs: https://developer.apple.com/library/mac/documentation/accessibility/reference/accessibilitylowlevel/_index.html
docs: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Protocols/NSAccessibility_Protocol/Reference/Reference.html#//apple%5Fref/doc/uid/20000945-DontLinkElementID%5F287

// Get the process ID of the frontmost application.
NSRunningApplication* app = [[NSWorkspace sharedWorkspace]
                              frontmostApplication];
pid_t pid = [app processIdentifier];

// See if we have accessibility permissions, and if not, prompt the user to
// visit System Preferences.
NSDictionary *options = @{(id)kAXTrustedCheckOptionPrompt: @YES};
Boolean appHasPermission = AXIsProcessTrustedWithOptions(
                             (__bridge CFDictionaryRef)options);
if (!appHasPermission) {
   return; // we don't have accessibility permissions

// Get the accessibility element corresponding to the frontmost application.
AXUIElementRef appElem = AXUIElementCreateApplication(pid);
if (!appElem) {
  return;
}

// Get the accessibility element corresponding to the frontmost window
// of the frontmost application.
AXUIElementRef window = NULL;
if (AXUIElementCopyAttributeValue(appElem, 
      kAXFocusedWindowAttribute, (CFTypeRef*)&window) != kAXErrorSuccess) {
  CFRelease(appElem);
  return;
}

// Finally, get the title of the frontmost window.
CFStringRef title = NULL;
AXError result = AXUIElementCopyAttributeValue(window, kAXTitleAttribute,
                   (CFTypeRef*)&title);

// At this point, we don't need window and appElem anymore.
CFRelease(window);
CFRelease(appElem);

if (result != kAXErrorSuccess) {
  // Failed to get the window title.
  return;
}

// Success! Now, do something with the title, e.g. copy it somewhere.

// Once we're done with the title, release it.
CFRelease(title);

I've been unable to subscribe to current window changes, but you can ask the accessibility API for the current application, and the current applications most foreground window.  

Imagine you have a class called CurrentAppData, with the following data:

    @interface CurrentAppData : NSObject {
        NSString* _title;
        AXUIElementRef _systemWide;
        AXUIElementRef _app;
        AXUIElementRef _window;
    }

The code to find the current application looks something like this:

    -(void) updateCurrentApplication {
       // get the currently active application  
       _app = (AXUIElementRef)[CurrentAppData
                               valueOfExistingAttribute:kAXFocusedApplicationAttribute 
                                            ofUIElement:_systemWide];

       // Get the window that has focus for this application
       _window = (AXUIElementRef)[CurrentAppData 
                                  valueOfExistingAttribute:kAXFocusedWindowAttribute 
                                               ofUIElement:_app];
    
       NSString* appName = [CurrentAppData descriptionOfValue:_window
                                                 beingVerbose:TRUE];    
    
       [self setTitle:appName];
    }

In this example the _systemWide variable is initialized in the classes init function as:
    _system = AXUIElementCreateSystemWide();


The class function valueOfExistingAttribute looks like this:

    // -------------------------------------------------------------------------------
    //  valueOfExistingAttribute:attribute:element
    //
    //  Given a uiElement and its attribute, return the value of an accessibility
    //  object's attribute.
    // -------------------------------------------------------------------------------
    + (id)valueOfExistingAttribute:(CFStringRef)attribute ofUIElement:(AXUIElementRef)element
    {
        id result = nil;
        NSArray *attrNames;
    
        if (AXUIElementCopyAttributeNames(element, (CFArrayRef *)&attrNames) == kAXErrorSuccess) 
        {
            if ( [attrNames indexOfObject:(NSString *)attribute] != NSNotFound
                    &&
              AXUIElementCopyAttributeValue(element, attribute, (CFTypeRef *)&result) == kAXErrorSuccess
            ) 
            {
                [result autorelease];
            }
            [attrNames release];
        }
        return result;
    }


The previous function was taken from the Apple [UIElementInspector][1] example, which is also a great resource for learning about the Accessibility API.


[1]:http://developer.apple.com/samplecode/UIElementInspector/index.html








You would need to use the Accessibility APIs, which are plain-C, located inside the ApplicationServices framework. For instance:

First you create an application object:

    AXUIElementRef app = AXUIElementCreateApplication( targetApplicationProcessID );

Then you get the window from this. You can request the window list and enumerate, or you can get the frontmost window (look in AXAttributeConstants.h for all the attribute names you'd use).

    AXUIElementRef frontWindow = NULL;
    AXError err = AXUIElementCopyAttributeValue( app, kAXMainWindowAttribute, &frontWindow );
    if ( err != kAXErrorSuccess )
        // it failed -- maybe no main window (yet)

Now you can request notification via a C callback function when a property of this window changes. This is a four-step process:

First you need a callback function to receive the notifications:

    void MyAXObserverCallback( AXObserverRef observer, AXUIElementRef element,
                               CFStringRef notificationName, void * contextData )
    {
        // handle the notification appropriately
        // when using ObjC, your contextData might be an object, therefore you can do:
        SomeObject * obj = (SomeObject *) contextData;
        // now do something with obj
    }

Next you need an AXObserverRef, which manages the callback routine. This requires the same process ID you used to create the 'app' element above:

    AXObserverRef observer = NULL;
    AXError err = AXObserverCreate( applicationProcessID, MyObserverCallback, &observer );
    if ( err != kAXErrorSuccess )
        // handle the error

Having got your observer, the next step is to request notification of certain things. See AXNotificationConstants.h for the full list, but for window changes you'll probably only need these two:

    AXObserverAddNotification( observer, frontWindow, kAXMovedNotification, self );
    AXObserverAddNotification( observer, frontWindow, kAXResizedNotification, self );

Note that the last parameter there is passing an assumed 'self' object as the contextData. This is not retained, so it's important to call `AXObserverRemoveNotification` when this object goes away.

Having got your observer and added notification requests, you now want to attach the observer to your runloop so you can be sent these notifications in an asynchronous manner (or indeed at all):

    CFRunLoopAddSource( [[NSRunLoop currentRunLoop] getCFRunLoop],
                        AXObserverGetRunLoopSource(observer),
                        kCFRunLoopDefaultMode );

`AXUIElementRef`s are CoreFoundation-style objects, so you need to use `CFRelease()` to dispose of them cleanly. For cleanliness here, for example, you would use `CFRelease(app)` once you've obtained the frontWindow element, since you'll no longer need the app.

A note about Garbage-Collection: To keep an AXUIElementRef as a member variable, declare it like so:

    __strong AXUIElementRef frontWindow;

This instructs the garbage collector to keep track of this reference to it. When assigning it, for compatibility with GC and non-GC, use this:

    frontWindow = (AXUIElementRef) CFMakeCollectable( CFRetain(theElement) );

Quartz Display Services

docs: http://developer.apple.com/mac/library/documentation/Carbon/Reference/CGWindow_Reference/Reference/Functions.html#//apple_ref/doc/uid/TP40008073-CH2-SW1

CGRegisterScreenRefreshCallback
CGWindowListCreateDescriptionFromArray(). See CGWindow.h
This gives you an array of dictionaries. The following information will probably be useful to you:
position and size: kCGWindowBounds
name: kCGWindowName

Feature availability

docs: [Mach-O Programming Topics]()
docs: [OS X ABI Dynamic Loader Reference]()
docs: [Code Loading Programming Topics]()
docs: dlopen man page

MyLoadedClass *loadedClass = [[NSClassFromString (@«MyClass») alloc] init];

Binary File Architecture

docs: [Mach-O Programming Topics]()
docs: [OS X ABI Mach-O File Format Reference]()
docs: [The DWARF Debugging Standard]()
docs: dyld man page

Security

Code Signing Guide
Secure Coding Guide

CommonCrypto

Security Transforms

Sandboxing

docs: App Sandbox Design Guide
docs: Common app sandboxing issues
docs: Entitlement Key Reference

display

codesign -dvvv --entitlements :- exec

verify verbose

codesign -vv iTunes.app

replace a code signature with an ad-hoc signature, which also disables sandboxing (-fs is –force –sign)

sudo codesign -fs - /Applications/Chess.app/

display the plist for entitlements

codesign -d --entitlements - /Applications/iTunes.app

  • Select file or folder
  • -(NSData)bookmarkDataWithOptions:
  • URLByResolvingBookmarkData

{start,stop}AccessingSEcurityScopedResource

  • container directories
  • entitlements
  • user-determined permissions
  • privilege separation
  • kernel enforcement

security-scoped bookmarks

  • app-scoped bookmarks, which allow your application to retain access to a file across launches
  • document-scoped bookmarks


enable app-scoped bookmarks

open the Entitlements file and add the following entitlement:

com.apple.security.files.bookmarks.app-scope. YES.

// Get the location in which to put the bookmark
NSURL* bookmarkStorageURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory

                                    inDomains:NSUserDomainMask] lastObject];

create and save bookmark data

bookmarkStorageURL = [bookmarkStorageURL URLByAppendingPathComponent:@«saved_bookmark.bookmark»];

// Create the bookmark data itself
NSError* error = nil;
NSData* bookmarkData = [panel.URL

  bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
  includingResourceValuesForKeys:nil relativeToURL:nil error:&error];

// Save the bookmark data
[bookmarkData writeToURL:bookmarkStorageURL atomically:YES];

retrieve a stored bookmark

// Get the location for where the bookmark was created
NSURL* bookmarkStorageURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory

                                inDomains:NSUserDomainMask] lastObject];

bookmarkStorageURL = [bookmarkStorageURL URLByAppendingPathComponent:@«saved_bookmark.bookmark»];

// Load the bookmark data
NSData* bookmarkData = [NSData dataWithContentsOfURL:bookmarkStorageURL];
NSURL* bookmark = nil;

if (bookmarkData)
{

// Get the URL for the bookmark
BOOL isStale = NO;
NSError* error = nil;

bookmark = [NSURL URLByResolvingBookmarkData:bookmarkData
                   options:NSURLBookmarkResolutionWithSecurityScope
                 relativeToURL:nil 
             bookmarkDataIsStale:&isStale 
                     error:&error];

[[NSUserDefaults standardUserDefaults] setURL:bookmark 
                     forKey:@"path"];

}

access file

[bookmarkStorageURL startAccessingSecurityScopedResource];
[bookmarkStorageURL stopAccessingSecurityScopedResource];

Gatekeeper

docs: [Tools Workflow Guide for Mac]()

IPC and Notification Mechanisms

File System Events

docs: [File System Events Programming Guide]()

Kernel queues and kernel events

docs: kqueue and kevent man pages

BSD notifications.

docs: [Mac Notification Overview]() or the notify man page

Sockets and ports

docs: CFSocket

Streams

docs: CFNetwork

Pipes

docs: pipe

Shared memory

docs: shm_open, shm_unlink, and mmap man pages

Apple event

docs: [Apple Events Programming Guide]()

XPC

Mach RPC

Distributed Objects

FileSystem

URLsForDirectory:inDomains:
Application directory - NSBundle
NSHomeDirectory
NSLibraryDirectory NSUserDomainMask
NSApplicationSupportDirectory NSLocalDomainMask
NSApplicationSupportDirectory NSUserDomainMask
NSCachesDirectory
NSTemporaryDirectory
NSURL over NSString
NSFileManager
NSURL getResourceValue:forKey:error:
FSEvents
NSOpenPanel
NSSavePanel

App Store Checklist

Memory Rules

  • You own any object you create
    You create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy).
  • You can take ownership of an object using retain

    • In the implementation of an accessor method or an init method, to take ownership of an object you want to store as a property value.
    • To prevent an object from being invalidated as a side-effect of some other operation.

  • “parent” object should maintain strong references to its “children,” and that the children should have weak references to their parents.

Value Types

NSString, NSData, NSDate, NSNumber, NSValue

int n = 5; // Value assigned to primitive type
NSNumber *numberObject = [NSNumber numberWithInt:n]; // Value object created from primitive type
int y = [numberObject intValue]; // Encapsulated value obtained from value object (y == n)

Objective-C

class declaration

Class declaration, .h

@interface MyClass : NSObject 
{ 
  // instance variables
  int count;
  id data;
  NSString* name;  
}

// properties and method declarations

@property (strong, nonatomic) NSObject* myProperty;

- (id) initWithString:(NSString)aName;
+ (MyClass)createMyClassWithString:(NSString)aName;
- (void) launchPlane;
- (void) launchPlane:(NSString*)planeName fuelCapacity:(int)litresOfFuel;
@end

// functions, constants, or data types

Class implementation, .m

#import "MyClass.h"

@implementation MyClass
 
@synthesize myProperty = _myCustomVariableName;

- (id)initWithString:(NSString *)aName
{
    // code goes here
}
 
+ (MyClass *)myClassWithString:(NSString *)aName
{
    // code goes here
}
@end

Modules

@import iAd.ADBannerView

Methods, Messaging

Method declaration

  • method returns
    • zero if primitive type
    • nil if object
    • undefined if struct

Class methods +

create instance, share, get information.
Invoke class methods [[SomeClass] method] or [[self class] method]

+(id)alloc;
+(Ship *)motherShip;
+(NSString *)stringWithFormat: ...

Instance methods -

- (BOOL)dropBoom:(Bomb *)bomb
    at:(CGPoint)position
    from:(double)altitude;

Properties, Acessor methods

@property (copy) MyModelObject *theObject;  // Copy the object during assignment.
@property (readonly) NSView *rootView;      // Declare only a getter method.
@property (weak) id delegate;               // Declare delegate as a weak reference

@synthesize enabled = _isEnabled; // 

@property (assign, getter=isEnabled) BOOL enabled; // Assign new value, change name of getter method

Variables

Literals

NSString
@«»
NSArray
@[]
NSDictionary
@{}
NSNumber
@()

NSNumber *value;
value = @'X';
value = @12345;
value = @12345ul;
value = @12345ll;
value = @123.45f;
value = @123.45;
value = @YES;

@""

array = @[];
array = @[ a ];
array = @[ a, b, c ];

dict = @{};
dict = @{ k1 : o1 };
dict = @{ k1 : o1, k2 : o2, k3 : o3 };


@implementation MyClass
static NSArray *thePlanets;
+ (void)initialize {
  if (self == [MyClass class]) {
    thePlanets = @[
      @"Mercury", @"Venus", @"Earth",
      @"Mars", @"Jupiter", @"Saturn",
      @"Uranus", @"Neptune"
    ];
} }

Protocols

  @protocol SomeProtocol
      [ method declarations ]
  @end


  @interface SomeObject : NSObject <SomeProtocol>
  @end

  id <SomeProtocol> someObjectConformingToAProtocol = [[SomeObject alloc] init];

Class Extension (Private category)

  @interface SomeClass() 
  {
    [ additional properties ]
    [ additional instance variables ]
  }
      [ additional instance or class method declarations ]
  @end

Named class extensions (Categories)

  @interface SomeClass (SomeCategory)
  @end

  @implementation
  @end

Memory qualifiers

Variables

MyClass * __weak myWeakReference;
MyClass * __unsafe_unretained myUnsafeReference;
__strong is the default.
An object remains “alive” as long as there is a strong pointer to it.

__weak
specifies a reference that does not keep the referenced object alive. A weak reference is set to nil when there are no strong references to the object.

__unsafe_unretained
specifies a reference that does not keep the referenced object alive and is not set to nil when there are no strong references to the object. If the object it references is deallocated, the pointer is left dangling.

__autoreleasing
is used to denote arguments that are passed by reference (id *) and are autoreleased on return.

Properties

In ARC strong is default.

@property(strong) MyClass *myObject;
@property(weak) MyClass *myObject;
strong
This property is a strong (owning) reference to an object; Using strong and weak properties controls whether the object referred to by the property stays in memory or not.

weak
This property is a weak (nonowning) reference to an object. When the object referred to by this property is deallocated, this property is automatically set to nil.

assign
This property’s setter method simply assigns the property’s variable to whatever is passed in, and performs no memory management. In ARC use weak instead.

copy
This property’s setter copies any object passed to it, creating a duplicate object.

retain
In ARC use strong instead.

readwrite
This property generates both getter and setter methods. (This attribute is set by default—you need to explicitly use it only when overriding a superclass’s property.)

readonly
This property does not generate a setter method, rendering the property read-only by other classes. (Your class’s implementation code can still modify the property’s variable, however.)

nonatomic
This property’s setter and getter do not attempt to get a lock before making changes to the variable, rendering it thread-safe.

тип доступа
readwrite
readonly
writeonly

тип указателя
strong
weak

поточность
atomic
nonatomic


Introspection

  • Whether it’s an instance of a particular class or subclass
  • Whether it responds to a message
  • Whether it conforms to a protocol
    ```
    isKindOfClass: returns whether an object is that kind of class (inheritance included)
    isMemberOfClass: returns whether an object is that kind of class (no inheritance)
    respondsToSelector: returns whether an object responds to a given method
    conformsToProtocol: Whether an Object Conforms to a Protocol

if ([obj isKindOfClass:[NSString class]]) {
NSString *s = [(NSString *)obj stringByAppendingString:@”xyzzy”];
}

if ([obj respondsToSelector:@selector(shoot)]) {

[obj shoot];

} else if ([obj respondsToSelector:@selector(shootAt:)]) {

[obj shootAt:target];

}

SEL shootSelector = @selector(shoot);
SEL shootAtSelector = @selector(shootAt:);
SEL moveToSelector = @selector(moveTo:withPenColor:);
SEL aSelector = NSSelectorFromString(@«methodName»);

[obj performSelector:shootSelector];
[obj performSelector:shootAtSelector withObject:coordinate];

[array makeObjectsPerformSelector:shootSelector]; // cool, huh?
[array makeObjectsPerformSelector:shootAtSelector withObject:target]; // target is an id

[button addTarget:self action:@selector(digitPressed:) …];

  • (void) setDelegate:(id __weak) obj {
    NSParameterAssert([obj conformsToProtocol:
    @protocol(SubviewTableViewControllerDataSourceProtocol)]);
    delegate = obj;
    }
    ```

Nullability (10.11+)

nonull
nullable
null_resettable // can be set to nil but never return nil but default value
null_unspecified

Generics (10.11+)

@property (copy) NSArray *recentSearhches;
@property (copy) NSArray *recentSearhches;
@property (copy) NSArray<__kindof NSString *> *recentSearhches;

Foundation

NSString

// Create the string "My String" plus carriage return.
NSString *myString = @"My String\n";
// Create the formatted string "1 String".
NSString *anotherString = [NSString stringWithFormat:@"%d %@", 1, @"String"];
// Create an Objective-C string from a C string.
NSString *fromCString = [NSString stringWithCString:"A C string" encoding:NSASCIIStringEncoding];

Dates and Times, NSDate

NSCalendar, NSDateComponents, NSTimeZone, NSLocale, NSDateFormatter

NSDate *now = [NSDate date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[calendar setTimeZone:[NSTimeZone systemTimeZone]];
NSDateComponents *dc = [calendar components:(NSHourCalendarUnit|NSMinuteCalendarUnit|
    NSSecondCalendarUnit) fromDate:now];
NSLog(@"The time is %d:%d:%d", [dc hour], [dc minute], [dc second]);

Collections

NSArray, NSMutableArray

// Compose a static array of string objects
NSString *objs[3] = {@"One", @"Two", @"Three"};
// Create an array object with the static array
NSArray *arrayOne = [NSArray arrayWithObjects:&(*objs) count:3];
// Create an array with a nil-terminated list of objects
NSArray *arrayTwo = [[NSArray alloc] initWithObjects:@"One", @"Two", @"Three", nil];

NSArray *myArray = @[ @"Hello World", @67, [NSDate date] ];

- lastObject, 
- firstObjectCommonWithArray:
- indexOfObjectPassingTest:

NSString *theString = [arrayTwo objectAtIndex:1]; // returns second object in array
id theObject = myArray[1];

NSArray *myArray = // get array
for (NSString *cityName in myArray) {
    if ([cityName isEqualToString:@"Cupertino"]) {
        NSLog(@"We're near the mothership!");
        break;
    }
}

NSArray *myArray = // get array
[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    if ([obj isEqual:@"Cupertino"]) {
        NSLog(@"We're near the mothership!");
        *stop = YES;
    }
}];

NSMutableArray *myMutableArray = [NSMutableArray arrayWithCapacity:1];
NSDate *today = [NSDate date];
myMutableArray[0] = today;

NSDictionary, NSMutableDictionary

+ dictionaryWithObjects:forKeys: 
+ dictionaryWithObjectsAndKeys:
- (void)setObject:(id)anObject forKey:(id)key;
- (void)removeObjectForKey:(id)key;
- (void)removeAllObjects;
- (void)addEntriesFromDictionary:(NSDictionary *)otherDictionary;

// First create an array of keys and a complementary array of values
NSArray *keyArray = [NSArray arrayWithObjects:@"IssueDate", @"IssueName", @"IssueIcon", nil];
NSArray *valueArray = [NSArray arrayWithObjects:[NSDate date], @"Numerology Today",
    self.currentIssueIcon, nil];
// Create a dictionary, passing in the key array and value array
NSDictionary *dictionaryOne = [NSDictionary dictionaryWithObjects:valueArray forKeys:keyArray];
// Create a dictionary by alternating value and key and terminating with nil
NSDictionary *dictionaryTwo = [[NSDictionary alloc] initWithObjectsAndKeys:[NSDate date],
    @"IssueDate", @"Numerology Today", @"IssueName", self.currentIssueIcon, @"IssueIcon", nil];

NSDictionary *myDictionary = @{
   @"name" : NSUserName(),
   @"date" : [NSDate date],
   @"processInfo" : [NSProcessInfo processInfo]
};


NSDictionary *myDictionary = ...;
for (id key in myDictionary) {
  // do something with key here
  id value = [myDictionary objectForKey:key];
  // do something with value here 
}

NSSet, NSMutableSet

Notification Center, NSNotificationCenter

if a delegate implements the windowDidMove: method, it is handling the notification NSWindowDidMoveNotification.

  [[NSNotificationCenter defaultCenter] addObserver:self 
                       selector:@selector(applicationEnteredBackground:) 
  UIApplicationDidEnterBackgroundNotification object:nil];

  - (void) applicationEnteredBackground:(NSNotification*)notification { 
    // Application entered background, so do something about it!
  }

  [[NSNotificationCenter defaultCenter] removeObserver:self]

  postNotification:

NSNotificationQueue

  enqueueNotification:postingStyle: 
  enqueueNotification:postingStyle:coalesceMask:forModes:

NSNotification

  addObserver:selector:name:object: 
  - (void)myNotificationHandler:(NSNotification *)notif;

  NSString *AMMyNotification = @"AMMyNotication";
  postNotificationName:object:userInfo: 

Target-Actions

target action

Core Foundation

Opaque Types

Polymorphic functions

  • CFType, CFTypeRef
  • CFRetain, CFRelease, CFEqual, CFHash

Characteristics

  • immutable and fixed size
  • mutable and fixed size
  • mutable and variable size

Bridged Types

developer.apple.com
Data types that can be used interchangeably are also referred to as toll-free bridged data types.

__bridge transfers a pointer between Objective-C and Core Foundation with no transfer of ownership.
__bridge_retained or CFBridgingRetain casts an Objective-C pointer to a Core Foundation pointer and also transfers ownership to you.
You are responsible for calling CFRelease or a related function to relinquish ownership of the object.
__bridge_transfer or CFBridgingRelease moves a non-Objective-C pointer to Objective-C and also transfers ownership to ARC.
ARC is responsible for relinquishing ownership of the object.

NSLocale *gbNSLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"];
CFLocaleRef gbCFLocale = (__bridge CFLocaleRef)gbNSLocale;
CFStringRef cfIdentifier = CFLocaleGetIdentifier(gbCFLocale);
NSLog(@"cfIdentifier: %@", (__bridge NSString *)cfIdentifier);
// Logs: "cfIdentifier: en_GB"
 
CFLocaleRef myCFLocale = CFLocaleCopyCurrent();
NSLocale *myNSLocale = (NSLocale *)CFBridgingRelease(myCFLocale);
NSString *nsIdentifier = [myNSLocale localeIdentifier];
CFShow((CFStringRef)[@"nsIdentifier: " stringByAppendingString:nsIdentifier]);
// Logs identifier for current locale
The next example shows the use of Core Foundation memory management functions where dictated by the Core Foundation memory management rules:

- (void)drawRect:(CGRect)rect {
 
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
    CGFloat locations[2] = {0.0, 1.0};
    NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]];
    [colors addObject:(id)[[UIColor lightGrayColor] CGColor]];
    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);
    CGColorSpaceRelease(colorSpace);  // Release owned Core Foundation object.
 
    CGPoint startPoint = CGPointMake(0.0, 0.0);
    CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds));
    CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint,
                                kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
    CGGradientRelease(gradient);  // Release owned Core Foundation object.
}

- (void)logFirstNameOfPerson:(ABRecordRef)person {
 
    NSString *name = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
    NSLog(@"Person's first name: %@", name);
}
Allocators

opaque objects that allocate and deallocate memory for you.
You pass allocators into functions that create objects; these functions have “Create” embedded in their names, for example, CFStringCreateWithPascalString. The creation functions use the allocators to allocate memory for the objects they create.

Owner if

  • Create
  • Copy

Not Owner if

  • Get

If Owner

  • must release (CFRelease) CFRelease(myString);

If Not Owner

  • To prevent Disposal must Retain (CFRetain) myString = (CFStringRef)CFRetain(myString);

CFIndex count = CFGetRetainCount(myString);

Copy

Fucntion with words CreateCopy, CreateMutableCopy

  • Shallow CFArray, CFSet
  • Deep CFPropertyListCreateDeepCopy


Documentation

  • appledoc
  • doxygen

Cocoapods

Diagnostics

  • Cocoa Lumberjack
  • DCIntrospector
  • PonyDebugger
  • SimPholder
  • Spark Inspector, Reveal

UI Design

  • Mocks
  • Briefs
  • Acorn
  • Sketch

Core data

  • Mogenerator
  • Base
  • Core data editor

Deployment

  • Deploymate
  • Cupertino
  • Hockey App
  • TestFlight
  • Crashlytics








Objective-C

class MyGroovySongList : NSObject
 - (Song *)objectAtIndexedSubscript:(NSUInteger)idx;
 - (void)setObject:(Song *)song atIndexedSubscript:(NSUInteger)idx;
 @end
 @implementation MyGroovySongList {
   NSMutableArray *mySongs;
 }
 - (Song *)objectAtIndexedSubscript:(NSUInteger)idx {
   return (Song *)mySongs[idx];
 }
 - (void)setObject:(Song *)song atIndexedSubscript:(NSUInteger)idx {
   mySongs[idx] = song;
 }

NSArray *people = CFBridgingRelease(

                ABAddressBookCopyPeopleWithName(addressBook,
                                              CFSTR("Appleseed")));

enums

###Enum with Fixed Underlying Type

typedef enum NSNumberFormatterStyle : NSUInteger {
    NSNumberFormatterNoStyle,
    NSNumberFormatterDecimalStyle,
    NSNumberFormatterCurrencyStyle,
    NSNumberFormatterPercentStyle,
    NSNumberFormatterScientificStyle,
    NSNumberFormatterSpellOutStyle
} NSNumberFormatterStyle;

typedef NS_ENUM(NSUInteger, NSNumberFormatterStyle) {
    NSNumberFormatterNoStyle,
    NSNumberFormatterDecimalStyle,
    NSNumberFormatterCurrencyStyle,
    NSNumberFormatterPercentStyle,
    NSNumberFormatterScientificStyle,
    NSNumberFormatterSpellOutStyle
};

Use bitwise AND (&) to test:

if ( pinkColor & kRed )
{
   // do something
}

isPink = ((pinkColor & kRed) == kRed);

-Wconversion
-Wswitch

Tips

- (NSString *)description is a useful method to override (it’s %@ in NSLog()).

Cocoa inspection

Input Sources

  • Keyboard Layout
    com.apple.keylayout.US
    org.sil.ukelele.keyboardlayout.t.russian- ilya birman typography

– Keyboard Input Method
com.apple.inputmethod.Kotoeri

— Keyboard Input Mode
com.apple.inputmethod.Kotoeri.Japanese.lastname
com.apple.inputmethod.Kotoeri.Japanese

bundle id == parent source id

Object creation

Initialization

- (id)init 
{
    self = [super init];  // Call a designated initializer here.
    if (self != nil) 
    {
        // Initialize object  ...
        if (someError) 
        {
            [self release];
            self = nil; 
        }
    }
    return self;    
}


- (id)initWithAccountID:(NSString *)identifier {
    if ( self = [super init] ) 
    {
        Account *ac = [accountDictionary objectForKey:identifier];
        if (ac) 
        { // object with that ID already exists
            [self release];
            return [ac retain];
        }
        if (identifier) {
            accountID = [identifier copy]; // accountID is instance variable
            [accountDictionary setObject:self forKey:identifier];
            return self;
        } 
        else 
        {
            [self release];
            return nil; 
        }
    } 
    else
        return nil;
}

Compare Objects

Identity

equality operator (==)

Equality

isEqual: method

- (BOOL)isEqual:(id)other {
    if (other == self)
        return YES;
    if (!other || ![other isKindOfClass:[self class]])
        return NO;
    return [self isEqualToInputSource:other];
}

- (BOOL)isEqualToInputSource:(DWInputSource *)aInputSource {
    if (self == aInputSource)
        return YES;
    if (![(id) [self id] isEqualToString:[aInputSource id]])
        return NO;
    return YES;
}

Singleton

static MyGizmoClass *sharedGizmoManager = nil;

+ (MyGizmoClass*)sharedManager
{
    if (sharedGizmoManager == nil) {
        sharedGizmoManager = [[super allocWithZone:NULL] init];
}
    return sharedGizmoManager;
}
+ (id)allocWithZone:(NSZone *)zone
{
    return [[self sharedManager] retain];
}
- (id)copyWithZone:(NSZone *)zone
{
    return self;
}
- (id)retain
{
    return self;
}
- (NSUInteger)retainCount
{
    return NSUIntegerMax;  //denotes an object that cannot be released
}
- (void)release
{
    //do nothing
}
- (id)autorelease
{
    return self;
}

Class clusters

Subclass

#import <foundation/foundation.h>

@interface MonthArray : NSArray
{
}
+ monthArray;
- (unsigned)count;
- (id)objectAtIndex:(unsigned)index;
@end


#import "MonthArray.h"
@implementation MonthArray

static MonthArray *sharedMonthArray = nil;
static NSString *months[] = { @"January", @"February", @"March",
                                @"April", @"May", @"June", @"July", @"August", @"September",
                                @"October", @"November", @"December" };

+ monthArray
{
    if (!sharedMonthArray) {
        sharedMonthArray = [[MonthArray alloc] init];
    }
    return sharedMonthArray;
}

- (unsigned)count
{
    return 12; 
}

- objectAtIndex:(unsigned)index
{
    if (index >= [self count])
        [NSException    raise:NSRangeException 
                        format:@"***%s: index (%d) beyond bounds (%d)", sel_getName(_cmd), index, [self count] - 1];
    else
        return months[index];
}
@end

Composite

#import <foundation/foundation.h>

@interface ValidatingArray : NSMutableArray
    {
        NSMutableArray *embeddedArray;
    }
    + validatingArray;
    - init;
    - (unsigned)count;
    - objectAtIndex:(unsigned)index;
    - (void)addObject:object;
    - (void)replaceObjectAtIndex:(unsigned)index withObject:object;
    - (void)removeLastObject;
    - (void)insertObject:object atIndex:(unsigned)index;
    - (void)removeObjectAtIndex:(unsigned)index;
@end


#import "ValidatingArray.h"

@implementation ValidatingArray

    - init {
        self = [super init];
        if (self) {
            embeddedArray = [[NSMutableArray allocWithZone:[self zone]] init];
        }
        return self;
    }
    + validatingArray
    {
        return [[[self alloc] init] autorelease];
    }
    - (unsigned)count
    {
        return [embeddedArray count];
    }
    - objectAtIndex:(unsigned)index
    {
        return [embeddedArray objectAtIndex:index];
    }
    - (void)addObject:object
    {
        if (/* modification is valid */) {
            [embeddedArray addObject:object];
        } 
    }
    - (void)replaceObjectAtIndex:(unsigned)index withObject:object;
    {
        if (/* modification is valid */) {
            [embeddedArray replaceObjectAtIndex:index 
                                     withObject:object];
        } 
    }
    - (void)removeLastObject;
    {
        if (/* modification is valid */) {
            [embeddedArray removeLastObject];
        } 
    }
    - (void)insertObject:object atIndex:(unsigned)index;
    {
        if (/* modification is valid */) {
            [embeddedArray insertObject:object atIndex:index];
        } 
    }
    - (void)removeObjectAtIndex:(unsigned)index;
    {
        if (/* modification is valid */) {
            [embeddedArray removeObjectAtIndex:index];
        } 
    }

Events

[icon.deleteButton addTarget:self action:@selector(delete:) forControlEvents:UIControlEventTouchUpInside];

Instantiation

Object *pointer = [[NSObject alloc] init];
UIView *myView = [[UIView alloc] initWithFrame:thePerfectFrame];

Block object

docs: [Blocks Programming Topics]()
Block syntax

// As a local variable:
returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};

// As a property:
@property (nonatomic, copy) returnType (^blockName)(parameterTypes);

// As a method parameter:
- (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;

// As an argument to a method call:
[someObject someMethodThatTakesABlock:^returnType (parameters) {...}];

// As a typedef:
typedef returnType (^TypeName)(parameterTypes);
TypeName blockName = ^returnType(parameters) {...};
	void(^myBlockVariable)(void);
	void(^myBlockVariable)();

	void(^myBlockVariable)(BOOL booleanParameter, NSString* objectParameter);
	
	float (^aBlock)(const int*, int, float);

	void(^myBlockVariable)(BOOL parameter);
	
	myBlockVariable = ^(BOOL parameter) { 
		// Code goes here.
	};

	int (^oneFrom)(int);

	oneFrom = ^(int anInt) {
	    return anInt - 1;
	};

	int i = 53;
	void (^someCode)() = ^{
		NSLog(@"The value of i is %i", i); ̃
	};


	// Filter an array of strings down to only strings that begin with the word
	// "Apple"
	NSPredicate* filterPredicate = [NSPredicate predicateWithBlock:^(id anObject) { 
		NSString* theString = anObject;
		return [theString hasPrefix:@"Apple"];
	}];
	NSArray* filteredArray = [someArray filteredArrayWithPredicate:filterPredicate];	

Self in blocks

__block typeof(self) tmpSelf = self;
[self methodThatTakesABlock:^ {
    [tmpSelf doSomething];
}];

Modifying Local Variables from Inside Blocks

	__block BOOL found = NO;
	NSSet *aSet = [NSSet setWithObjects: @"Alpha", @"Beta", @"Gamma", @"X", nil];
	NSString *string = @"gamma";
	 
	[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
	    if ([obj localizedCaseInsensitiveCompare:string] == NSOrderedSame) {
	        *stop = YES;
	        found = YES;
	    }
	}];
	 
	// At this point, found == YES

Example

NSURL* location = [NSURL URLWithString:@"http://www.example.com/test.txt"];
NSURLRequest* request = [NSURLRequest requestWithURL:location];

[NSURLConnection sendAsynchronousRequest:request
                                   queue:[NSOperationQueue mainQueue]
                       completionHandler:^(NSURLResponse* response,
                                           NSData* loadedData,
                                           NSError* error) {
                // This code runs when the data has completed downloading.
                // The NSURLResponse contains information from the server
                // about the request, the NSData contains the raw downloaded
                //  bytes, and the NSError contains any error information, if
                // anything went wrong.
}];

block as method parameter

declaration

- (void) someMethod:(void(^)(BOOL aParameter)) handler;

implementation

- (void) someMethod:(void(^)(BOOL aParameter)) handler { 
    // Call the passed-in block:
    handler(YES);
}

calling

[anObject someMethod:^(BOOL aParameter) {
    // The called method will call this method
}];

Store blocks in heap

// myBlockProperty is a property of this class that can store the block.
void(^myBlockVariable)() = ^{ 
    // code goes here
};

self.myBlockProperty = myBlockVariable; // INCORRECT! The block
// won't exist after this function returns, and calling it will crash.

self.myBlockProperty = [myBlockVariable copy]; // SAFE. The
// block will be copied and stored on the heap, and stick around.

block data type

// somewhere in your source code, outside of a function or method:
typedef void(^ABlockType)(BOOL aParameter);

- (void) someMethod:(ABlockType)handler;

// and later, in a function:
ABlockType myBlock = ^(BOOL aParameter) { 
    // do some work
};

Blocks implementation

http://clang.llvm.org/docs/Block-ABI-Apple.html

struct Block_literal_1 {
    void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
    int flags;
    int reserved;
    void (*invoke)(void *, ...);
    struct Block_descriptor_1 {
    unsigned long int reserved;         // NULL
        unsigned long int size;         // sizeof(struct Block_literal_1)
        // optional helper functions
        void (*copy_helper)(void *dst, void *src);     // IFF (1<<25)
        void (*dispose_helper)(void *src);             // IFF (1<<25)
        // required ABI.2010.3.16
        const char *signature;                         // IFF (1<<30)
    } *descriptor;
    // imported variables
};

enum {
    BLOCK_HAS_COPY_DISPOSE =  (1 << 25),
    BLOCK_HAS_CTOR =          (1 << 26), // helpers have C++ code
    BLOCK_IS_GLOBAL =         (1 << 28),
    BLOCK_HAS_STRET =         (1 << 29), // IFF BLOCK_HAS_SIGNATURE
    BLOCK_HAS_SIGNATURE =     (1 << 30),
};

[33554432, 67108864, 268435456, 536870912, 1073741824]
['0x2000000', '0x4000000', '0x10000000', '0x20000000', '0x40000000']

GC enabled

@interface MyClass : NSObject {

NSString *name;
NSNumber *accountID;
}

@property (copy) NSString *name;
@property (readonly) NSNumber *accountID;

@end

@implementation MyClass

@synthesize name, accountID;

@end

example

@interface MyClass : NSObject {
    NSHost *currentHost;
    Boolean *hidden;
}

@property (retain, nonatomic) NSHost *currentHost;
@property (getter=isHidden, nonatomic) Boolean *hidden;

@end

@implementation MyClass

@synthesize currentHost, hidden;

@end

example

@interface MyClass : NSObject {
    NSImage *previewImage;
}

@property (readonly) NSImage *previewImage;

@end

@implementation MyClass

@dynamic previewImage;

- (NSImage *)previewImage {
    if (previewImage == nil) {
        // lazily load image and assign to ivar
        NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"Foo" ofType:@"jpg"];
        if (!imagePath) 
            return nil;
        previewImage = [[NSImage alloc] initWithContentsOfFile:imagePath];
    }
   return previewImage;
}
@end

glossary

application A specific style of program that displays a graphical interface to the user.

asynchronous design approach The principle of organizing an application around blocks of code that can be run concurrently with an application’s main thread or other threads of execution. Asynchronous tasks are started by one thread but actually run on a different thread, taking advantage of additional processor resources to finish their work more quickly.

block object A C construct for encapsulating inline code and data so that it can be performed later. You use blocks to encapsulate tasks you want to perform, either inline in the current thread or on a separate thread using a dispatch queue. For more information, see .

concurrent operation An operation object that does not perform its task in the thread from which its start method was called. A concurrent operation typically sets up its own thread or calls an interface that sets up a separate thread on which to perform the work.

condition A construct used to synchronize access to a resource. A thread waiting on a condition is not allowed to proceed until another thread explicitly signals the condition.

critical section A portion of code that must be executed by only one thread at a time.

custom source A dispatch source used to process application-defined events. A custom source calls your custom event handler in response to events that your application generates.

descriptor An abstract identifier used to access a file, socket, or other system resource.

dispatch queue A Grand Central Dispatch (GCD) structure that you use to execute your application’s tasks. GCD defines dispatch queues for executing tasks either serially or concurrently.

dispatch source A Grand Central Dispatch (GCD) data structure that you create to process system-related events.

descriptor dispatch source A dispatch source used to process file-related events. A file descriptor source calls your custom event handler either when file data is available for reading or writing or in response to file system changes.

dynamic shared library A binary executable that is loaded dynamically into an application’s process space rather than linked statically as part of the application binary.

global dispatch queue A dispatch queue provided to your application automatically by Grand Central Dispatch (GCD). You do not have to create global queues yourself or retain or release them. Instead, you retrieve them using the system-provided functions.

Grand Central Dispatch (GCD) A technology for executing asynchronous tasks concurrently. GCD is available in OS X v10.6 and later and iOS 4.0 and later.

input source A source of asynchronous events for a thread. Input sources can be port based or manually triggered and must be attached to the thread’s run loop.

joinable thread A thread whose resources are not reclaimed immediately upon termination. Joinable threads must be explicitly detached or be joined by another thread before the resources can be reclaimed. Joinable threads provide a return value to the thread that joins with them.

library A UNIX feature for monitoring low-level system events. For more information see the kqueue man page.

Mach port dispatch source A dispatch source used to process events arriving on a Mach port.

main thread A special type of thread created when its owning process is created. When the main thread of a program exits, the process ends.

mutex A lock that provides mutually exclusive access to a shared resource. A mutex lock can be held by only one thread at a time. Attempting to acquire a mutex held by a different thread puts the current thread to sleep until the lock is finally acquired.

Open Computing Language (OpenCL) A standards-based technology for performing general-purpose computations on a computer’s graphics processor. For more information, see OpenCL Programming Guide for Mac.

operation object An instance of the NSOperation class. Operation objects wrap the code and data associated with a task into an executable unit.

operation queue An instance of the NSOperationQueue class. Operation queues manage the execution of operation objects.

private dispatch queue A dispatch queue that you create, retain, and release explicitly.

process The runtime instance of an application or program. A process has its own virtual memory space and system resources (including port rights) that are independent of those assigned to other programs. A process always contains at least one thread (the main thread) and may contain any number of additional threads.

process dispatch source A dispatch source used to handle process-related events. A process source calls your custom event handler in response to changes to the process you specify.

program A combination of code and resources that can be run to perform some task. Programs need not have a graphical user interface, although graphical applications are also considered programs.

reentrant Code that can be started on a new thread safely while it is already running on another thread.

run loop An event-processing loop, during which events are received and dispatched to appropriate handlers.

run loop mode A collection of input sources, timer sources, and run loop observers associated with a particular name. When run in a specific “mode,” a run loop monitors only the sources and observers associated with that mode.

run loop object An instance of the NSRunLoop class or CFRunLoopRef opaque type. These objects provide the interface for implementing an event-processing loop in a thread.

run loop observer A recipient of notifications during different phases of a run loop’s execution.

semaphore A protected variable that restricts access to a shared resource. Mutexes and conditions are both different types of semaphore.

signal A UNIX mechanism for manipulating a process from outside its domain. The system uses signals to deliver important messages to an application, such as whether the application executed an illegal instruction. For more information see the signal man page.

signal dispatch source A dispatch source used to process UNIX signals. A signal source calls your custom event handler whenever the process receives a UNIX signal.

task A quantity of work to be performed. Although some technologies (most notably Carbon Multiprocessing Services) use this term differently, the preferred usage is as an abstract concept indicating some quantity of work to be performed.

thread A flow of execution in a process. Each thread has its own stack space but otherwise shares memory with other threads in the same process.

timer dispatch source A dispatch source used to process periodic events. A timer source calls your custom event handler at regular, time-based intervals.

http://stackoverflow.com/questions/11221902/objective-c-nsstack-and-nsqueue
NSMutableArray

addObject 
objectAtIndex and removeObjectAtIndex.

NSFileManager

NSFileManager* fileManager = [NSFileManager defaultManager];


NSFileManager* newFileManager = [[NSFileManager alloc] init]; 
// we can now set a delegate on this new file manager to be 

// notified when operations are complete 
newFileManager.delegate = self;

contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error:
- URLsForDirectory:inDomains:


NSURL* folderURL = [NSURL fileURLWithPath:@"/Applications/"];
NSFileManager* fileManager = [NSFileManager defaultManager];
NSError* error = nil;
NSArray* folderContents = [fileManager contentsOfDirectoryAtURL:folderURL
                            includingPropertiesForKeys:nil
                            options:0
                            error:error];


// Pass in an NSArray containing the attributes you want to know about
NSArray* attributes = [NSArray arrayWithObjects:NSURLFileSizeKey, NSURLContentModificationDateKey, nil];

// In this case, we don't care about any potential errors, so we
// pass in 'nil' for the error parameter.
NSDictionary* attributesDictionary = [anURL resourceValuesForKeys:attributes 
                                                            error:nil];

// We can now get the file size out of the dictionary:
NSNumber* fileSizeInBytes = [attributesDictionary objectForKey:NSURLFileSizeKey];

// And the date it was last modified:
NSDate* lastModifiedDate = [attributesDictionary objectForKey:NSURLContentModificationDateKey];


NSArray* attributes = [NSArray arrayWithObjects:NSURLFileSizeKey, NSURLContentModificationDateKey, nil];
NSArray* folderContents = [fileManager contentsOfDirectoryAtURL:folderURL
                                     includingPropertiesForKeys:attributes
                                                        options:0
                                                          error:error];

[fileManager createDirectoryAtURL:anURL
      withIntermediateDirectories:YES
                       attributes:nil
                            error:nil];

[fileManager createFileAtPath:aPath contents:someData attributes:nil];

[fileManager removeItemAtURL:anURL error:nil];

[file moveItemAtURL:sourceURL toURL:destinationURL error:nil];

[file copyItemAtURL:sourceURL toURL:destinationURL error:nil];

Documents directory path

NSArray* URLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];

NSURL

-resourceValuesForKeys:error:

NSBundle

NSHomeDirectory

NSLibraryDirectory search path key with the NSUserDomainMask
NSCachesDirectory 



NSFileManager* fileManager = [NSFileManager defaultManager];
NSURL* appSupportDir = nil;

NSArray *urls = [fileManager URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask];
if ([paths count] > 0) {
   appSupportDir = [[urls objectAtIndex:0] URLByAppendingPathComponent:@"com.example.MyApp"];
}


NSDocument
NSUrl
     getResourceValue:forKey:error:

NSOpenPanel

NSOpenPanel* panel         = [NSOpenPanel openPanel];
    panel.canChooseFiles       = NO;
    panel.canChooseDirectories = YES;
    [panel beginWithCompletionHandler:^(NSInteger result) {
NSURL* chosenDirectory = panel.URL;
// the application may now do something with chosenDirectory
}];

NSArrayController

???

NSObjectController

???

view window saving state

 implement the encodeRestorableStateWithCoder: method
  implement the window:willEncodeRestorableState:

window restoring state

 restoreWindowWithIdentifier:state:completionHandler:
 window:didDecodeRestorableState:
 restoreStateWithCoder

+ (void)restoreWindowWithIdentifier:(NSString *)identifier
        state:(NSCoder *)state
        completionHandler:(void (^)(NSWindow *, NSError *))completionHandler
{
   // Get the window from the window controller,
   // which is stored as an outlet by the delegate.
   // Both the app delegate and window controller are
   // created when the main nib file is loaded.
   MyAppDelegate* appDelegate = (MyAppDelegate*)[[NSApplication sharedApplication] delegate];
   NSWindow* mainWindow = [appDelegate.windowController window];

   // Pass the window to the provided completion handler.
   completionHandler(mainWindow, nil);
}

Key-Value Binding KVB

establishes bindings between objects and also removes and advertises those bindings

Key-Value Coding KVC

NSKeyValueCoding informal protocol
valueForKey: and setValue:forKey:

+ (Product*) productWithDictionary:(NSDictionary*)dictionary { 
    Product* aProduct = [[Product alloc] init];

    for (NSString* key in dictionary) {
        NSObject* theValue = [dictionary objectForKey:key]; 
        [aProduct setValue:theValue forKey:key];
    }

    return aProduct; 
}


// aProduct is a Product object
NSString* productName = [aProduct valueForKey:@"productName"]; 

// This is exactly the same as:
NSString* productName = aProduct.productName; 

// Which is also the same as:
NSString* productName = [aProduct productName];

Key-Value Observing, KVO : Notifying an Observer When a Value Changes

KVO

NSKeyValueObserving informal protocol

  • the object that should be notified when the property changes,
  • the name of the property that should be observed
  • the information the observer should be told about when a change happens

    // aProduct is a Product object
    // Make this current object (self) be notified when the product
    // changes its price; we want to be notified of both the old
    // value and the new value
    [aProduct addObserver:self

           forKeyPath:@"productName"
              options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
              context:nil];
    
    • (void)observeValueForKeyPath:(NSString *)keyPath

                    ofObject:(id)object 
                      change:(NSDictionary *)change 
                     context:(void *)context
      

      {
      if ([keyPath isEqualToString:@«productName»]) {

      NSString* newName = [change objectForKey:NSKeyValueChangeNewKey];
      
      // tell the appropriate view to update, based on the newName variable.
      

      }
      }

    • (void) setProductName:(NSString*)newProductName {
      [self willChangeValueForKey:@«productName»];
      productName = newProductName;
      [self didChangeValueForKey:@«productName»];
      }

call

addObserver:forKeyPath:options:context:

implement

observeValueForKeyPath:ofObject:change:context:

multiple users

Incorporate session ID information into the name of any entity that appears in a global namespace, including file names, shared memory regions, semaphores, and named pipes.

app store

create an explicit app ID, create provisioning profiles, and enable the correct entitlements for your application.
LSApplicationCategoryType

controls

blogs

NSTableView

Provide data programmatically to View based

  • NSTableViewDataSource protocol
    • numberOfRowsInTableView:
  • NSTableViewDelegate protocol
    • tableView:viewForTableColumn:row:

Drawing

  • Coordinate space (Unit = 172 inch)
    • User
    • System
    • local coordinate lower-left

NSAffineTransform

NSRect

NSPoint
`NSSize` bottom-left

NSView

drawRect:    
frame - location, size in superview    
initWithFrame:
bounds - interior coordinate system
visiableRect
- superview
- subviews
- window

NSWindow

- contentView

Mouse Events

Mouse movement

  • addTrackingRect:owner:userData:assumeInside:




AppleScript

docs: [AppleScript Overview]()
docs: [Scripting Additions for OS X]()

Ruby , Python

docs: [Ruby and Python Programming Topics for Mac]()

Device Drivers

docs: [IOKit Fundamentals]()
special type of kernel extensions to communicate with hardware

Kernel Extensions

docs: [Kernel Programming Guide]()

Views NSView

NSWindow

Content view

Cocoa views are initialized using their initWithCoder: method.
Custom views are initialized using their initWithFrame: method. (Designated Initializer)
Custom classes that have been instantiated in the nib are initialized using their init method.

awakeFromNib:

Layers


Back to posts


comments powered by Disqus