-
The @ symbol is not used in the C programming language. To minimize conflicts between C code and Objective-C code, Objective-C keywords are prefixed by @. Here are a few other Objective-C keywords:
@end, @implementation, @class, @selector, @protocol, @property, and @synthesize
. -
When the process is started, it runs the
NSApplicationMain
function, which creates an instance ofNSApplication
. The application object reads the main NIB file and unarchives the objects inside. The objects are all sent the messageawakeFromNib
. Then the application object checks for events. When it receives an event from the keyboard mouse, the window server puts the event data into the event queue for the appropriate application.The application object reads the event data from its queue and forwards it to a user interface object, such as a button, and your code gets triggered. If your code changes the data in a view, the view is redisplayed. Then the application object checks its event queue for another event. This process of checking for events and reacting to them constitutes the main event loop.When the user chooses Quit from the menu,NSApp
is sent theterminate:
message. This ends the process, and all your objects are destroyed. -
You can convert between C strings and NSStrings.
const char *foo = "Blah blah";
NSString *bar;
// Create an NSString from a C string
bar = [NSString stringWithUTF8String:foo];
// Create a C string from an NSString
foo = [bar UTF8String];
Because NSString can hold Unicode strings, you will need to deal with the mul- tibyte characters correctly in your C strings, and this can be quite difficult and time consuming. (Besides the multibyte problem, you will have to wrestle with the fact that some languages read from right to left.) Whenever possible, you should use NSString instead of C strings.
- You cannot put a nil in an NSArray. (This means that there are no “holes” in an NSArray, which may confuse some programmers who are used to Java’s Object[].) Sometimes, you will want to put an object into an array to represent nothingness. The NSNull class exists for exactly this purpose. There is exactly one instance of NSNull, so if you want to put a placeholder for nothing into an array, use NSNull like this:
[myArray addObject:[NSNull null]];
-
Conventions for Creating Initializers (rules that Cocoa programmers try to follow regarding initializers):
- You do not have to create any initializer in your class if the superclass’s initializers are sufficient.
- If you decide to create an initializer, you must override the superclass’s designated initializer.
- If you create multiple initializers, only one does the work—the designated initializer. All other initializers call the designated initializer.
- The designated initializer of your class will call its superclass’s desig- nated initializer.
-
One of the challenging things about debugging Cocoa programs is that they will often limp along in a broken state for quite a while. Using the macro
NSAssert()
, you can get the program to throw an exception as soon as the train leaves the track.NSAssert()
works only inside Objective-C methods. If you need to check an assertion in a C function, useNSCAssert()
. -
To block assertion checking in the Release configuration,bring up the build settings by selecting the lottery project in the project navigator (topmost item). Then select the target, change to the Build Settings tab, and find the Preprocessor Macros item. A quick way to find it is to use the search field at the top of the Build Settings panel. The Preprocessor Macros item will have one item beneath it for each build configuration: Debug and Release. Set the Release item value to
NS_BLOCK_ASSERTIONS
. -
You can change your current build configuration to Release by opening the scheme editor (in the Product menu, click Edit Scheme...). Select the Run action; on the Info panel, change Build Configuration to Release. Now when you build and run your application, it will be built using the Release configuration.
-
As mentioned earlier, an object is like a C struct. NSObject declares an instance variable called isa. Because NSObject is the root of the entire class inheritance tree, every object has an isa pointer to the class structure that created the object. The class structure includes the names and types of the instance variables for the class. It also has the implementation of the class’s methods. The class structure has a pointer to the class structure for its superclass.
- The methods are indexed by the selector. The selector is of type
SEL
. Although SEL is defined to bechar *
, it is most useful to think of it as an int. Each method name is mapped to a unique int. For example, the method nameaddObject:
might map to the number 12. When you look up methods, you will use the selector, not the string @"addObject:".As part of the Objective-C data structures, a table maps the names of methods to their selectors. - At compile time, the compiler looks up the selectors wherever it sees a message send.Thus,
[myObject addObject:yourObject]
; becomes (assuming that the selector for addObject: is 12)objc_msgSend(myObject, 12, yourObject)
; Here,objc_msgSend()
looks at myObject’s isa pointer to get to its class structure and looks for the method associated with 12. If it does not find the method, it follows the pointer to the superclass. If the superclass does not have a method for 12, it continues searching up the tree. If it reaches the top of the tree without finding a method, the function throws an exception.Clearly, this is a very dynamic way of handling messages. These class structures can be changed at runtime. In particular, using theNSBundle
class makes it relatively easy to add classes and methods to your program while it is running. This very powerful technique has been used to create applications that can be extended by other developers.
- The methods are indexed by the selector. The selector is of type
-
Apple has come up with three solutions for Memory Management
- The first is manual reference counting, or retain counts: Every object has a retain count, which should represent the number of other objects that have pointers to it. If the color is the favorite of two people, the retain count of that color should be 2. When the retain count of an object goes to zero, it is deallocated.An object’s retain count should represent how many other objects have references to it. When the retain count becomes zero, this indicates that no one cares about it any more. It is deallocated so that the memory it was occupying can be reused.
- Then, in Mac OS 10.5, Apple introduced garbage collection for Objec- tive-C. The garbage collector babysits the entire object graph, looking for objects that can’t be reached from the variables that are in scope. The unreachable objects are automatically deallocated.
- The new solution, introduced in Mac OS 10.7 and iOS 5, is automatic reference counting, more commonly known as ARC. ARC relies on the original retain-count mechanism but with a twist: The compiler man- ages the bookkeeping of retain counts for you. 
-
An array does not make a copy of an object when it is added. Instead, the array stores a pointer to the object and sends it the message retain. When the array is deallocated, the objects in the array are sent the message release. (Also, if an object is removed from an array, it is sent release.)
-
The problem, then, is that you need to return a string, but you do not want to retain it. This is a common problem throughout the frameworks, which leads us to the final piece of the retain-count puzzle: the autorelease pool. Autorelease pools simplify releasing objects. You can add an object to the current autorelease pool simply by sending it the message autorelease. Adding an object to an autorelease pool marks it to be sent a release message at some point in the future.The release message is sent once the pool is drained. In a Cocoa application, an autorelease pool is created before every event is handled and is drained after the event has been handled. Thus, unless the objects in the autorelease pool are being retained, they will be destroyed as soon as the event has been handled.Note that if you autorelease an object n times, it will be sent release n times once the pool is drained.Because you will frequently need objects that you are not retaining, many classes have class methods that return autoreleased objects. NSString, for example, has stringWithFormat:.
-
In these rules, we use the word “you” to mean “an instance of whatever class you are currently working on.” It is a useful form of empathy: You imagine that you are the object you are writing. So, for example, “If you retain the string, it will not be deallocated” really means “If an instance of the class that you are currently working on retains the string, it will not be deallocated.”
-
If you create an object by using a method whose name starts with alloc or new or contains copy, you have taken ownership of it. (That is, assume that the new object has a retain count of 1 and is not in the autorelease pool.) You have a responsibility to release the object when you no longer need it. Some of the common methods that convey ownership are alloc (which is always followed by an init method), copy, and mutableCopy.
-
An object created through any other means, such as a convenience method, is not owned by you. (That is, assume that it has a retain count of 1 and is already in the autorelease pool and thus doomed unless it is retained before the autorelease pool is drained.)
-
If you don’t own an object and want to ensure its continued existence, take ownership by sending it the message retain. (This increments the retain count.)
-
When you own an object and no longer need it, send it the message release or autorelease. (The message release decrements the retain count immediately; autorelease causes the message release to get sent when the autorelease pool is drained.)
-
As long as it has at least one owner, an object will continue to exist. (When its retain count goes to zero, it is sent the message dealloc.)
-
-
In the common idioms of Objective-C, a method prefixed with get takes an address where data can be copied. For example, if you have an NSColor object and you want its red, green, blue, and alpha components, you would call getRed:green:blue:alpha: as follows:
float r, g, b, a;
[myFavoriteColor getRed:&r green:&g blue:&b alpha:&a];
-
ARC is a compiler feature, based on the same technology that powers the static analyzer. When you compile your application, your use of Objective-C object pointers (references) is examined by the compiler, which then applies the same rules we described earlier in this chapter, retaining, releasing, and autoreleasing to ensure that the objects live as long as necessary and are deallocated when they are no longer needed.
-
In fact, when using ARC, it is an error to call retain, release, or autorelease. With ARC, you will think less about retain counts and focus more on object relationships. Relationships are defined by references, which are simply object pointers.There are two types of references: strong and weak.
-
Weak references are similar to the old manual reference-counted pointers: There is no implicit retain; the pointer value is simply changed in memory. Such references have long been an area ripe for causing crashes, however. If the pointer is not retained, the object can be deallocated, leaving a bad pointer to cause a crash when it is used. ARC addresses this by automatically setting weak references to nil when the object they point to has been deallocated. This is known as a “zeroing weak reference.”When would you want to use a weak pointer? Recall the retain-cycle issue we touched on before, where two objects are retaining each other and thus are never deallocated. In ARC, this is referred to as a strong reference cycle. By using weak references strategically, we can avoid these cycles altogether. Consider the following class definition:
@interface Person : NSObject {
Person *parent; // Bad! This causes a strong reference cycle!
NSMutableArray *children;
} @end
Because references are strong by default, a class like this would quickly result in a strong reference cycle. Person has a strong reference to both parent and children; the children array has strong references to objects it contains. We can use the __weak
qualifier to fix this problem and make parent a weak reference:
@interface Person : NSObject {
__weak Person *parent; // Good! No strong reference cycle.
NSMutableArray *children;
} @end
This pattern is commonly used in Objective-C: The parent-to-child relationship is strong, whereas the child-to-parent relationship is weak.
Note that only classes compiled with ARC can have weak references made to them. An exception will be thrown if you try to make an assignment to a __weak
variable and the class does not support weak references. You can use the __unsafe_unretained
qualifier in place of __weak in cases like this. The object will not be retained, but this reference will not be set to nil when the object is deallocated.
-
Xcode provides a migration tool to convert existing projects to ARC. This tool can be found in the Edit menu, under
Refactor -> Convert to Objective-C Automatic Reference Counting
. -
Although Objective-C can be intermixed with plain C in most cases, ARC does not allow C structures to contain object pointers.Property names may not begin with new.Under ARC it is an error to call retain, release, autorelease, or dealloc (such as with [super dealloc]). Additionally, you cannot override retain, release, or autorelease.
-
To understand the AppKit framework, a good place to start is with the class NSControl. NSButton, NSSlider, NSTextView, and NSColorWell are all subclasses of NSControl. A control has a target and an action. The target is simply a pointer to another object. The action is a message (a selector) to send to the target.
-
To better understand NSControl, you should become acquainted with its ancestors: NSControl inherits from NSView, which inherits from NSResponder, which inherits from NSObject. Each member of the family tree adds some capabilities .
-
At the top of the class hierachy is NSObject. All classes inherit from NSObject, and this is where they get the basic methods: retain, release, dealloc, and init. NSResponder is a subclass of NSObject. Responders have the ability to handle events with such methods as mouseDown: and keyDown:. NSView is a subclass of NSResponder and has a place on a window, where it draws itself. You can create subclasses of NSView to display graphs and allow the user to drag and drop data. NSControl inherits from NSView and adds the target and the action.
-
Instances of
NSButton
can have appearances: oval, square, check box. They can also have various behaviors when clicked: toggle (like a check box) or momentarily on (like most other buttons). Buttons can have icons and sounds associated with them. Here are three messages that you will frequently send to buttons.-
- (void)setEnabled:(BOOL)yn
Enabled buttons can be clicked by the user. Disabled buttons are grayed out. -
- (NSInteger)state
ReturnsNSOnState
(which is 1) if the button is on, orNSOffState
(which is 0) if the button is off. This method allows you to see whether a check box is checked or unchecked. -
``- (void)setState:(NSInteger)aState` This method turns the button on or off. It allows you to check or uncheck a check box programmatically. Set the state to NSOnState to check the check box and to NSOffState to uncheck it.
-
-
Instances of
NSSlider
can be vertical or horizontal. They can send the action to the target continuously while being changed, or they can wait to send the action until the user releases the mouse button. A slider can have markers, and it can prevent users from choosing values between the markers .Circular sliders are also possible.Here are two methods ofNSSlider
that you will use frequently:- (void)setFloatValue:(float)x
Moves the slider to x.- (float)floatValue
Returns the current value of the slider.
-
An instance of
NSTextField
can allow a user to type a single line of text. Text fields may or may not be editable. Uneditable text fields are commonly used as labels on a window. Compared to buttons and sliders, text fields are relatively complex. Text fields have a placeholder string. When the text field is empty, the placeholder string is displayed in gray.NSSecureTextField
is a subclass ofNSTextField
and is used for such things as passwords. As the user types, bullets appear instead of the typed characters. You cannot copy or cut from anNSSecureTextField
.Here are a few of the most commonly used NSTextField methods:- (NSString *)stringValue
- (void)setStringValue:(NSString *)aString
- Allow you to get and set the string data being displayed in the text field.
- (NSObject *)objectValue
- (void)setObjectValue:(NSObject *)obj
Allow you to get and set the data being displayed in the text field as an arbitrary object type. This behavior is helpful if you are using a formatter. NSFormatters are responsible for converting a string into another type, and vice versa. If no formatter is present, these methods use the description method.
- Debug.Hints
- Application crashes. If you send a message to an object that has been deallocated, it will crash your program. (This is difficult to do if you are using ARC or the garbage collector.) Hunting these crashers can be difficult; after all, the problem object has already been deallocated. One way to hunt them down is to ask the frameworks to turn your objects into “zombies” instead of deallocating them. When you send a message to a zombie, it throws a descriptive exception that says something like, “You tried to send the message -count to a freed instance of the class Fido.” This will stop the debugger on that line.To turn on zombies, open the
Product
menu and selectEdit Scheme
…. Select theRun (application name).app
action and switch to theDiagnostics
tab. CheckEnable Zombie Objects
.
- Application crashes. If you send a message to an object that has been deallocated, it will crash your program. (This is difficult to do if you are using ARC or the garbage collector.) Hunting these crashers can be difficult; after all, the problem object has already been deallocated. One way to hunt them down is to ask the frameworks to turn your objects into “zombies” instead of deallocating them. When you send a message to a zombie, it throws a descriptive exception that says something like, “You tried to send the message -count to a freed instance of the class Fido.” This will stop the debugger on that line.To turn on zombies, open the