Hillegass
Chapter 1 Cocoa: What is it?
Objective C reference on Apple site: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html
Chapter 2 Let’s Get Started
- Outlet - instance variable which is a pointer to another object
- Action - method that can be triggered by user interface objects
- Set the outlet of an object - control drag from the object that needs to know to the object it needs to know about
- Navigate -> Jump to Next Counterpart command, Control-Command-UpArrow, flips the editor between corresponding
.h
and.m
files.
Chapter 3 Objective-C
Allocating memory
Create a new instance of NSMutableArray
by sending the message
alloc
to the NSMutableArray
class:
[NSMutableArray alloc];
Sending messages
Send the message init to the object foo points to, “foo is the receiver of the message init”:
[foo init];
Messages can be nested. The method init returns the newly initialised object, so message sends must always be initialised like this:
foo = [[NSMutableArray alloc] init];
To differentiate between constant C strings and constant NSString
s, you
must put @
before the opening quote of a constant NSString
:
NSLog(@"The number at index %d is %@", i, numberToPrint);
Arguments are specified using a colon:
[foo addObject:bar];
Multiple arguments use different parts of the selector (or method name). In this case the selector is insertObject:atIndex:
[foo insertObject:bar atIndex:5];
NSArray
List of pointers to other objects, indexed by integers, cannot contain nil, is immutable (NSString and NSNumber are also immutable.) One array can hold objects of different classes. It can’t hold C primitive types e.g. int, float.
Initialisers
- 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 designated initialiser.
If a class initialiser always requires an argument, override the base class init method to throw an exception.
- (id)init
{
@throw [NSException exceptionWithName:@"BNRBadInitCall"
reason:@"Initialize Lawsuit with initWithDefendant:"
userInfo:nil];
return nil;
}
The debugger
A handy feature is the “print object” po
. Calling po
on an object will send the message description
to the object.
po newEntry
The debugger can be configured to stop whenever an exception is thrown by “adding an exception breakpoint” from the breakpoint navigator.
Use NSAssert()
to throw an exception as soon as the program is in an unstable state e.g. a variable is unexpectedly nil. Note: this only works in Objective-C methods. Use NSCAssert()
in C methods.
Set the preprocessor macro for release mode NS_BLOCK_ASSERTIONS
to ensure an exception is not thrown in release mode.
Static Analyzer
The static analyzer (Product > Analyze) shows potential problems with the code over and above compiler warnings and errors.
Chapter 4 Memory Management
When an object is no longer used i.e. no longer has any pointers to it, the memory can be reused. Working out which memory is available for reuse is tricky.
Three solutions (with advantages and disadvantages) are:
- Manual reference counting or retain counts. Every object has a retain count which is the number of objects with pointers to it. When the retain count of an object is 0 it is deallocated.
- Requires explicit programming statements.
- Retain cycles possible (two objects reference each other but not referenced by anything else).
- Garbage collection. Unreachable objects are automatically deallocated.
- Performance cost - poorer or uneven performance while the GC scans the object collection
- Cannot manage manually allocated memory e.g. allocated with
malloc
- GC not supported on Mac OS X < 10.5 or iOS
- ARC - automatic reference counting. Retain count mechanism is used, but is managed by the compiler rather than explicitly by programmers.
- Doesn’t require explicit programming statements to manage retain counts
- Doesn’t have GC performance hit
- Still needs work to avoid retain cycles
- Doesn’t manage manually allocated memory
Manual reference counting
When an object is created using alloc, the retain count is 1. Retain count is incremented by sending the retain
message and deallocated by sending the release
message.
NSDate *now = [[NSDate alloc] init];
/* lines of code which use the variable now */
[now release]
When creating objects and adding them to an array, the array stores a pointer to the object and sends it a message retain
. The retain count is incremented. When the array is deallocated it sends release
messages to the objects it contains. The object’s retain counts are decremented, but will still be 1. Therefore the objects should be sent a release
message after adding to the array.
Cat \*cat = [[Cat alloc] initWithBreed:breed];
[array addObject:cat];
[cat release];
The array
now has ownership of cat
.
Objects will often retain
objects they hold references to. If an object is passed into a constructor the retain
message will be sent to it and similarly a release
message sent in the destructor dealloc
.
If overriding the dealloc
method, call [super dealloc]
at the end.
Autoreleasing objects
When a method creates and object and returns a pointer to that object we don’t want to retain
the object. But if we release
it before returning, there will be no object to return. To resolve this use the autorelease pool by sending the object the autorelease
message. The release message is sent to all objects in the autorelease pool when the pool is drained. In Cocoa an autorelease pool is created before an event and drained after the event has been handled. Autorelease pools can also be created explicitly in non-event driven applications, or to more explicitly manage memory.
Many methods return autoreleased objects. e.g. NSString initWithFormat
doesn’t, but the class method NSString stringWithFormat
does.
From stackoverflow http://stackoverflow.com/questions/1378206/do-all-class-methods-return-an-autoreleased-object:
Class methods, just like instance methods, should adhere to the standard Cocoa memory management rules.
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it.
Presumably they are returning an autoreleased object, or a reference to a singleton or something like that. Either way, you need not release the object unless it started with “alloc” or “new” or contained “copy”. You need not retain it unless you’re looking to keep it around past the scope of the current autorelease pool, by storing it in an iVar or something like that.
The retain count rules
- If you create an object by using a method whose name starts with
alloc
ornew
or containscopy
, you have taken ownership of it. - An object created through any other means, such as a convenience method, is not owned by you.
- If you don’t own an object and want to ensure its continued existence, take ownership by sending it the message
retain
. - When you own an object and no longer need it, send it the message
release
orautorelease
. - As long as it has at least one owner, an object will continue to exist.
Finally, think locally and trust that all other code is doing the right thing
Strong and weak references
By default all references are strong. ARC will take care of releasing strong references.
Retain cycles need to be managed properly by strategically using weak references. A typical example is where a class holds references to both parents and children. The pattern commonly used in Objective-C is to leave the parent-child relationship strong, but make the child-parent relationship weak:
@interface Person : NSObject {
__weak Person *parent; // Good! No strong reference cycle.
NSMutableArray *children;
}
@end
ARC
Under ARC it is an error to use the manual retain count functionality. That is, you can’t send the messages retain
, release
, autorelease
, dealloc
.
Chapter 5 Target/Action
Chapter 6 Helper Objects
Functionality of objects in the Cocoa framework are often extended using helper objects. For example a table view is supplied with a helper object to supply the data.
Delegates
Many classes in the Cocoa framework have an instance variable called delegate
to point to a helper object. If your class is to be the delegate, then change the class declaration to refer to this protocol:
@interface SpeakLineAppDelegate : NSObject <NSApplicationDelegate, NSSpeechSynthesizerDelegate> {
Additionally set the delegate outlet of the speech synthesizer with [_speechSynth setDelegate:self]
in init
.
NSTableView and its dataSource
NSTableView
has a helper object called dataSource
. The NSTableView dataSource object needs to conform to the NSTableDataSource informal protocol i.e. has to have some methods to give data. NSTableView
also has a helper object called delegate
.
Finding delegate methods at runtime
If you wanted to see the checks for the existence of the delegate methods, you could override respondsToSelector: in your delegate object:
- (BOOL)respondsToSelector:(SEL)aSelector{
NSString *methodName = NSStringFromSelector(aSelector);
NSLog(@"respondsToSelector:%@", methodName);
return [super respondsToSelector:aSelector];
}
Chapter 7 Key-Value Coding and Key-Value Observing
Key-value coding (or KVC) is a mechanism that allows you to set and get the value of any variable by its name. Alternatively you can declare getter and setter methods. These will use the KVC methods as long as the naming convention for getters and setters is followed.
Bindings
Graphical objects can be bound to keys - the view will automatically keep the values in sync.
If the value of the object is changed directly, any observers are not notified of the change. Explicityly trigger the notification of the observers with:
[self willChangeValueForKey:@"fido"];
// action
[self didChangeValueForKey:@"fido"];
Properties
If simple setters and getters are required, properties can be declared instead:
@property (readwrite, assign) int fido;
in the header file;@synthesize fido
in the implementation file
Attributes of a property
readwrite
orreadonly
assign
,strong
,weak
orcopy
whereassign
is used for non-pointer typesnonatomic
can be used to explicitly eliminate the overhead of using locks to ensure atomic setters
Key paths
NSString *mn;
mn = [selectedPerson valueForKeyPath:@"spouse.scooter.modelName"];
NSNumber *theAverage;
theAverage = [employees valueForKeyPath:@"@avg.expectedRaise"];
Other commonly used operators:
- @avg
- @count
- @max
- @min
- @sum
Chapter 8 NSArray Controller
Controller classes in the MVC design pattern are usually application specific and used with more general-purpose Views and Models.
NSController
is an abstract class, with NSObjectController
displaying the content of an object. NSArrayController
further derives from this to display the contents of an array.
Model classes need only import Foundation/Foundation.h
Chapters 9 to 38
TODO
- Next →
Groovy