Computer Science Large Practical: Crash Course in Objective-C Stephen Gilmore School of Informatics Friday 12th October, 2012 Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 1 / 33
Computer Science Large Practical:
Crash Course in Objective-C
Stephen Gilmore
School of Informatics
Friday 12th October, 2012
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 1 / 33
Acknowledgements
We are following Appendix C of
Beginning iOS 5 ApplicationDevelopment
Wei-Meng Lee
John Wiley & Sons, Inc.
2012
www.it-ebooks.info
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 2 / 33
Objective-C sources
Objective-C source code files are contained in two types of files:
.h header files
.m implementation files
Thus a project could contain a file called SomeClass.h
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 3 / 33
Directives
If you observe the content of the SomeClass.h file, you will notice that atthe top of the file is typically an #import statement:
#import <Foundation/Foundation.h>
@interface SomeClass : NSObject {
}
@end
The #import statement is known as a preprocessor directive.(NS stands for ”NeXTStep”, the project which created Objective-C.)
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 4 / 33
Importing your own header files
To import a header file from within your project, you use the quotecharacters, as in the case of the SomeClass.m file:
#import "SomeClass.h"
@implementation SomeClass
@end
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 5 / 33
Classes
To declare a class, you use the @interface compiler directive, like this:
@interface SomeClass : NSObject {
}
This is done in the header file (.h), and the class declaration contains noimplementation. The preceding code declares a class named SomeClass,and this class inherits from the base class named NSObject.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 6 / 33
Classes
To implement a class declared in the header file, you use the@implementation compiler directive, like this:
#import "SomeClass.h"
@implementation SomeClass
@end
This is done in a separate file from the header file. In Objective-C, youdefine your class in an .m file.
Note
Note that the class definition ends with the @end compiler directive.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 7 / 33
Mutual recursion
If your class references another class defined in another file, you needto import the header file of that file before you can use it.
To prevent circular inclusion, Objective-C uses the @class compilerdirective as a forward declaration to inform the compiler that the classyou specified is a valid class.
You usually use the @class compiler directive in the header file; and inthe implementation file, you can use the @import compiler directiveto tell the compiler more about the content of the class you are using.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 8 / 33
Mutual recursion example
// SomeClass.h
#import <Foundation/Foundation.h>
@class AnotherClass; // forward declaration
@interface SomeClass : NSObject {
// an object from AnotherClass
AnotherClass *anotherClass;
}
@end
// AnotherClass.h
#import <Foundation/Foundation.h>
@class SomeClass; // forward declaration
@interface AnotherClass : NSObject {
SomeClass *someClass; // using an instance of SomeClass
}
@end
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 9 / 33
Mutual recursion example
// SomeClass.h
#import <Foundation/Foundation.h>
@class AnotherClass; // forward declaration
@interface SomeClass : NSObject {
// an object from AnotherClass
AnotherClass *anotherClass;
}
@end
// AnotherClass.h
#import <Foundation/Foundation.h>
@class SomeClass; // forward declaration
@interface AnotherClass : NSObject {
SomeClass *someClass; // using an instance of SomeClass
}
@end
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 9 / 33
Class instantiation
To create an instance of a class, you typically use the alloc keyword toallocate memory for the object and then return it to a variable of the classtype:
SomeClass *someClass = [SomeClass alloc];
In Objective-C, you need to prefix an object name with the * characterwhen you declare an object.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 10 / 33
Primitive types
If you are declaring a variable of primitive type (such as float, int, CGRect,NSInteger, and so on), the * character is not required. Here are someexamples:
CGRect frame; // CGRect is a structure
int number; // int is a primitive type
NSString *str; // NSString is a class
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 11 / 33
The id type
Besides specifying the returning class type, you can also use the id type,like this:
id someClass = [SomeClass alloc];
id str;
The id type means that the variable can refer to any type of object; hence,the * is implied.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 12 / 33
Fields
Fields are the data members of objects. For example, the following codeshows that SomeClass has three fields — anotherClass, rate, and name:
// SomeClass.h
#import <Foundation/Foundation.h>
@class AnotherClass; // forward declaration
@interface SomeClass : NSObject {
// an object from AnotherClass
AnotherClass *anotherClass;
float rate;
NSString *name;
}
@end
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 13 / 33
Access Privileges
By default, the access privilege of all fields is @protected. However, theaccess privilege can also be @public or @private. The following listdescribes the various access privileges:
@private Visible only to the class that declares it
@public Visible to all classes
@protected Visible to the class that declares it and inheriting classes
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 14 / 33
Public fields
To make the rate and name visible outside the class, modify theSomeClass.h file by adding the @public compiler directive:
#import <Foundation/Foundation.h>
@class AnotherClass; // forward declaration
@interface SomeClass : NSObject {
AnotherClass *anotherClass;
@public
float rate;
@public
NSString *name;
}
@end
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 15 / 33
Public fields
We can now access the fields ”rate” and ”name” directly (using the ”->”operator).
SomeClass *someClass = [SomeClass alloc];
someClass->rate = 5; // rate is declared public
someClass->name = @"Wei-Meng Lee"; // name is public
Although we can access the fields directly, doing so goes against thedesign principles of object-oriented programming’s rule of encapsulation.
A better way is to encapsulate the two fields we want to expose inproperties, as we will see later.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 16 / 33
Methods
Objective-C supports two types of methods: instance methods and classmethods.
Instance methods can only be called using an instance of the class;and they are prefixed with the minus sign (−) character.
Class methods can be invoked directly using the class name and donot need an instance of the class in order to work. Class methods areprefixed with the plus sign (+) character.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 17 / 33
Methods in interfaces
@interface SomeClass : NSObject {
AnotherClass *anotherClass;
float rate;
NSString *name;
}
// instance methods
-(void) doSomething;
-(void) doSomething:(NSString *) str;
-(void) doSomething:(NSString *) str withAnotherPara:(float)
value;
// class method
+(void) alsoDoSomething;
@end
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 18 / 33
Methods in implementations (1/2)
#import "SomeClass.h"
@implementation SomeClass
// instance methods
-(void) doSomething {
// implementation here
}
-(void) doSomething:(NSString *) str {
// implementation here
}
-(void) doSomething:(NSString *) str withAnotherPara:(float)
value {
// implementation here
}
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 19 / 33
Methods in implementations (2/2)
// class method
+(void) alsoDoSomething {
// implementation here
}
@end
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 20 / 33
Invoking methods
To invoke the three instance methods, you first need to create an instanceof the class and then call them using the instance created:
SomeClass *someClass = [SomeClass alloc];
[someClass doSomething];
[someClass doSomething:@"some text"];
[someClass doSomething:@"some text" withAnotherPara:9.0f];
Class methods can be called directly using the class name, as the followingshows:
[SomeClass alsoDoSomething];
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 21 / 33
Message Sending (Calling Methods)
Strictly speaking, in Objective-C you do not call a method; rather,you send a message to an object.
The message to be passed to an object is resolved during runtime andis not enforced at compile time.
This is why the compiler does not stop you from running yourprogram even though you may have misspelled the method name.
It does warn you that the target object may not respond to yourmessage, though, because the target object will simply ignore themessage (and in most situations result in a runtime exception).
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 22 / 33
Message Sending (Calling Methods)
Strictly speaking, in Objective-C you do not call a method; rather,you send a message to an object.
The message to be passed to an object is resolved during runtime andis not enforced at compile time.
This is why the compiler does not stop you from running yourprogram even though you may have misspelled the method name.
It does warn you that the target object may not respond to yourmessage, though, because the target object will simply ignore themessage (and in most situations result in a runtime exception).
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 22 / 33
Nested method calls
Method calls can also be nested, as the following example shows:
NSString *str =
[[NSString alloc] initWithString:@"Hello World"];
Here, you first call the alloc class method of the NSString class and thencall the initWithString: method of the returning result from the allocmethod, which is of type id, a generic C type that Objective-C uses for anarbitrary object.
Note
In general, you should not nest more than three levels because anythingmore than that makes the code difficult to read.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 23 / 33
Defining properties
Properties enable you to expose the fields in your class so that youcan control how values are set or returned.
In the earlier example we saw that we can directly access the fields ofa class using the ”->” operator.
However, this is not the ideal way; ideally, you should expose yourfields as properties in the interface.
// expose the rate field
-(float) rate; // get the value of rate
-(void) setRate:(float) value; // set the value of rate
// expose the name field
-(NSString *) name; // get the value of name
-(void) setName:(NSString *) value; //set the value of name
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 24 / 33
Getting and setting properties
To set the value of these properties, you need to call the methods prefixedwith the set keyword:
SomeClass *sc = [[SomeClass alloc] init];
[sc setRate:5.0f];
[sc setName:@"Wei-Meng Lee"];
To obtain the values of properties, you can either call the methods.
NSLog([sc name]); // call the method
To make a property read-only, simply remove the method prefixed with theset keyword.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 25 / 33
Initializers
When you create an instance of a class, you often initialize it at the sametime.
SomeClass *sc = [[SomeClass alloc] init];
The alloc keyword allocates memory for the object; and when an object isreturned, the init method is called on the object to initialize the object.The init method is defined in the NSObject class, which is the base classof most classes in Objective-C.
Convention
If you want to create additional initializers, you can define methods thatbegin with the init word (use of the init prefix is more of a norm than ahard-and-fast rule).
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 26 / 33
Memory management
Like most other popular languages, Objective-C supports garbagecollection, which removes unused objects when they go out of scopeand hence releases memory that can be reused.
However, because of the severe overhead involved in garbagecollection, iOS does not support garbage collection.
This leaves the developer to manually allocate and de-allocate thememory of objects when they are no longer needed.
Note
In the CSLP we are not targeting iOS, but still it seems worthwhile tolearn a little about reference counting. Recent versions of Mac OS X andiOS include automatic reference counting, making memory managementthe same on Mac OS X and iOS.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 27 / 33
Reference Counting
To help you allocate and de-allocate memory for objects, iOS uses ascheme known as reference counting to keep track of objects todetermine whether they are still needed or can be disposed of.
Reference counting basically uses a counter for each object; and aseach object is created, the count increases by 1.
When an object is released, the count decreases by 1.
When the count reaches 0, the memory associated with the object isreclaimed by the OS.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 28 / 33
Reference counting example
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 29 / 33
Reference counting example
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 29 / 33
Reference counting example
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 29 / 33
Reference counting example
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 29 / 33
Reference counting example
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 29 / 33
Reference counting example
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 29 / 33
alloc
The alloc keyword allocates memory for an object that you are creating.An example is as follows:
NSString *str = [[NSString alloc] initWithString:@"Hello"];
Here, you are creating an NSString object and instantiating it with adefault string.
When the object is created, the reference count of that object is 1.
Because you are the one creating it, the object belongs to you, and it isyour responsibility to release the memory when you are done with it.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 30 / 33
new
Besides using the alloc keyword to allocate memory for an object, you canalso use the new keyword, like this:
NSString *str = [NSString new];
The new keyword is functionally equivalent to
NSString *str = [[NSString alloc] init];
As with the alloc keyword, using the new keyword makes you the owner ofthe object, so you need to release it when you are done with it.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 31 / 33
retain
The retain keyword increases the reference count of an object by 1.Consider the following example:
NSString *str = [[NSString alloc] initWithString:@"Hello"];
NSString *str2 = str;
Here, you do not own str2 because you do not use the alloc keyword onthe object. When str is released, the str2 pointer will no longer be valid.To ensure that str2 is available even if str is released, you need to use theretain keyword:
NSString *str = [[NSString alloc] initWithString:@"Hello"];
NSString *str2 = str;
[str2 retain]; // str2 now also "owns" the object
[str release]; // str can now be released safely
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 32 / 33
release
When you are done with an object, you need to manually release it byusing the release keyword:
NSString *str = [[NSString alloc] initWithString:@"Hello"];
//...do what you want with the object...
[str release];
When you use the release keyword on an object, it causes the referencecount of that object to decrease by 1.
When the reference count reaches 0, the memory used by the object isreleased.
Stephen Gilmore (School of Informatics) Computer Science Large Practical Friday 12th October, 2012 33 / 33