learnxinyminutes-docs/objective-c.html.markdown

811 lines
31 KiB
Markdown
Raw Normal View History

2013-08-13 12:32:20 +00:00
---
2013-08-13 12:38:39 +00:00
language: Objective-C
contributors:
- ["Eugene Yagrushkin", "www.about.me/yagrushkin"]
- ["Yannick Loriot", "https://github.com/YannickL"]
- ["Levi Bostian", "https://github.com/levibostian"]
- ["Clayton Walker", "https://github.com/cwalk"]
2015-11-01 00:48:44 +00:00
- ["Fernando Valverde", "http://visualcosita.xyz"]
2013-08-13 12:38:39 +00:00
filename: LearnObjectiveC.m
2013-08-13 12:32:20 +00:00
---
2013-08-13 12:45:49 +00:00
Objective-C is the main programming language used by Apple for the OS X and iOS operating systems and their respective frameworks, Cocoa and Cocoa Touch.
2015-10-08 03:11:24 +00:00
It is a general-purpose, object-oriented programming language that adds Smalltalk-style messaging to the C programming language.
2013-08-13 12:32:20 +00:00
```objective-c
2013-08-13 12:32:20 +00:00
// Single-line comments start with //
/*
Multi-line comments look like this
2013-08-13 12:32:20 +00:00
*/
// XCode supports pragma mark directive that improve jump bar readability
#pragma mark Navigation Functions // New tag on jump bar named 'Navigation Functions'
#pragma mark - Navigation Functions // Same tag, now with a separator
2013-08-13 12:56:09 +00:00
// Imports the Foundation headers with #import
2014-01-11 18:27:47 +00:00
// Use <> to import global files (in general frameworks)
// Use "" to import local files (from project)
2013-08-13 12:56:09 +00:00
#import <Foundation/Foundation.h>
2013-08-13 14:50:22 +00:00
#import "MyClass.h"
2013-08-13 12:56:09 +00:00
2014-01-11 18:27:47 +00:00
// If you enable modules for iOS >= 7.0 or OS X >= 10.9 projects in
// Xcode 5 you can import frameworks like that:
@import Foundation;
2013-08-13 12:56:09 +00:00
// Your program's entry point is a function called
// main with an integer return type
2013-08-13 12:56:09 +00:00
int main (int argc, const char * argv[])
{
2013-08-13 14:04:20 +00:00
// Create an autorelease pool to manage the memory into the program
2013-08-13 12:56:09 +00:00
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// If using automatic reference counting (ARC), use @autoreleasepool instead:
@autoreleasepool {
2013-08-13 13:25:47 +00:00
// Use NSLog to print lines to the console
2013-08-13 13:50:09 +00:00
NSLog(@"Hello World!"); // Print the string "Hello World!"
2015-10-08 03:11:24 +00:00
2013-08-13 14:04:20 +00:00
///////////////////////////////////////
// Types & Variables
///////////////////////////////////////
2015-10-08 03:11:24 +00:00
2013-08-13 14:04:20 +00:00
// Primitive declarations
2013-08-13 14:09:38 +00:00
int myPrimitive1 = 1;
long myPrimitive2 = 234554664565;
2015-10-08 03:11:24 +00:00
2013-08-13 14:04:20 +00:00
// Object declarations
// Put the * in front of the variable names for strongly-typed object declarations
2013-08-13 14:09:38 +00:00
MyClass *myObject1 = nil; // Strong typing
id myObject2 = nil; // Weak typing
2013-08-13 13:50:09 +00:00
// %@ is an object
2013-08-13 14:07:58 +00:00
// 'description' is a convention to display the value of the Objects
NSLog(@"%@ and %@", myObject1, [myObject2 description]); // prints => "(null) and (null)"
2015-10-08 03:11:24 +00:00
2013-08-13 14:04:20 +00:00
// String
NSString *worldString = @"World";
2015-10-08 03:11:24 +00:00
NSLog(@"Hello %@!", worldString); // prints => "Hello World!"
// NSMutableString is a mutable version of the NSString object
2013-12-22 16:37:02 +00:00
NSMutableString *mutableString = [NSMutableString stringWithString:@"Hello"];
[mutableString appendString:@" World!"];
NSLog(@"%@", mutableString); // prints => "Hello World!"
2015-10-08 03:11:24 +00:00
2013-08-13 13:50:09 +00:00
// Character literals
2013-08-13 13:52:11 +00:00
NSNumber *theLetterZNumber = @'Z';
2013-12-22 16:37:02 +00:00
char theLetterZ = [theLetterZNumber charValue]; // or 'Z'
2013-08-13 13:52:11 +00:00
NSLog(@"%c", theLetterZ);
2013-08-13 12:56:09 +00:00
// Integral literals
2013-08-13 13:50:09 +00:00
NSNumber *fortyTwoNumber = @42;
2013-12-22 16:37:02 +00:00
int fortyTwo = [fortyTwoNumber intValue]; // or 42
2013-08-13 13:50:09 +00:00
NSLog(@"%i", fortyTwo);
2015-10-08 03:11:24 +00:00
2013-08-13 13:50:09 +00:00
NSNumber *fortyTwoUnsignedNumber = @42U;
2013-12-22 16:37:02 +00:00
unsigned int fortyTwoUnsigned = [fortyTwoUnsignedNumber unsignedIntValue]; // or 42
2013-08-13 13:50:09 +00:00
NSLog(@"%u", fortyTwoUnsigned);
2015-10-08 03:11:24 +00:00
2013-08-13 14:04:20 +00:00
NSNumber *fortyTwoShortNumber = [NSNumber numberWithShort:42];
2013-12-22 16:37:02 +00:00
short fortyTwoShort = [fortyTwoShortNumber shortValue]; // or 42
2013-08-13 14:04:20 +00:00
NSLog(@"%hi", fortyTwoShort);
2013-12-22 16:37:02 +00:00
NSNumber *fortyOneShortNumber = [NSNumber numberWithShort:41];
unsigned short fortyOneUnsigned = [fortyOneShortNumber unsignedShortValue]; // or 41
NSLog(@"%u", fortyOneUnsigned);
2015-10-08 03:11:24 +00:00
2013-08-13 13:50:09 +00:00
NSNumber *fortyTwoLongNumber = @42L;
2013-12-22 16:37:02 +00:00
long fortyTwoLong = [fortyTwoLongNumber longValue]; // or 42
2013-08-13 13:50:09 +00:00
NSLog(@"%li", fortyTwoLong);
NSNumber *fiftyThreeLongNumber = @53L;
unsigned long fiftyThreeUnsigned = [fiftyThreeLongNumber unsignedLongValue]; // or 53
2013-12-22 16:37:02 +00:00
NSLog(@"%lu", fiftyThreeUnsigned);
2013-08-13 13:50:09 +00:00
// Floating point literals
NSNumber *piFloatNumber = @3.141592654F;
2013-12-22 16:37:02 +00:00
float piFloat = [piFloatNumber floatValue]; // or 3.141592654f
NSLog(@"%f", piFloat); // prints => 3.141592654
NSLog(@"%5.2f", piFloat); // prints => " 3.14"
2015-10-08 03:11:24 +00:00
2013-08-13 13:50:09 +00:00
NSNumber *piDoubleNumber = @3.1415926535;
double piDouble = [piDoubleNumber doubleValue]; // or 3.1415926535
2013-08-13 13:50:09 +00:00
NSLog(@"%f", piDouble);
2013-12-22 16:37:02 +00:00
NSLog(@"%4.2f", piDouble); // prints => "3.14"
// NSDecimalNumber is a fixed-point class that's more precise then float or double
2013-12-22 16:37:02 +00:00
NSDecimalNumber *oneDecNum = [NSDecimalNumber decimalNumberWithString:@"10.99"];
NSDecimalNumber *twoDecNum = [NSDecimalNumber decimalNumberWithString:@"5.002"];
// NSDecimalNumber isn't able to use standard +, -, *, / operators so it provides its own:
2015-10-08 03:11:24 +00:00
[oneDecNum decimalNumberByAdding:twoDecNum];
2013-12-22 16:37:02 +00:00
[oneDecNum decimalNumberBySubtracting:twoDecNum];
[oneDecNum decimalNumberByMultiplyingBy:twoDecNum];
[oneDecNum decimalNumberByDividingBy:twoDecNum];
NSLog(@"%@", oneDecNum); // prints => 10.99 as NSDecimalNumber is immutable
2013-08-13 12:32:20 +00:00
2013-08-13 13:25:47 +00:00
// BOOL literals
2013-08-13 13:50:09 +00:00
NSNumber *yesNumber = @YES;
NSNumber *noNumber = @NO;
2013-12-22 16:37:02 +00:00
// or
BOOL yesBool = YES;
BOOL noBool = NO;
2013-12-22 16:37:02 +00:00
NSLog(@"%i", yesBool); // prints => 1
2013-08-13 13:50:09 +00:00
// Array object
// May contain different data types, but must be an Objective-C object
2013-08-13 13:50:09 +00:00
NSArray *anArray = @[@1, @2, @3, @4];
NSNumber *thirdNumber = anArray[2];
NSLog(@"Third number = %@", thirdNumber); // prints => "Third number = 3"
2015-10-08 03:11:24 +00:00
// NSMutableArray is a mutable version of NSArray, allowing you to change
// the items in the array and to extend or shrink the array object.
// Convenient, but not as efficient as NSArray.
2013-12-22 16:37:02 +00:00
NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:2];
[mutableArray addObject:@"Hello"];
[mutableArray addObject:@"World"];
[mutableArray removeObjectAtIndex:0];
NSLog(@"%@", [mutableArray objectAtIndex:0]); // prints => "World"
2013-08-13 13:50:09 +00:00
// Dictionary object
NSDictionary *aDictionary = @{ @"key1" : @"value1", @"key2" : @"value2" };
NSObject *valueObject = aDictionary[@"A Key"];
NSLog(@"Object = %@", valueObject); // prints => "Object = (null)"
// NSMutableDictionary also available as a mutable dictionary object
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithCapacity:2];
[mutableDictionary setObject:@"value1" forKey:@"key1"];
[mutableDictionary setObject:@"value2" forKey:@"key2"];
[mutableDictionary removeObjectForKey:@"key1"];
2015-11-01 00:48:44 +00:00
// Change types from Mutable To Immutable
//In general [object mutableCopy] will make the object mutable whereas [object copy] will make the object immutable
NSMutableDictionary *aMutableDictionary = [aDictionary mutableCopy];
NSDictionary *mutableDictionaryChanged = [mutableDictionary copy];
2015-11-01 00:48:44 +00:00
2013-12-22 16:37:02 +00:00
// Set object
NSSet *set = [NSSet setWithObjects:@"Hello", @"Hello", @"World", nil];
NSLog(@"%@", set); // prints => {(Hello, World)} (may be in different order)
// NSMutableSet also available as a mutable set object
NSMutableSet *mutableSet = [NSMutableSet setWithCapacity:2];
[mutableSet addObject:@"Hello"];
[mutableSet addObject:@"Hello"];
NSLog(@"%@", mutableSet); // prints => {(Hello)}
2013-12-22 16:37:02 +00:00
2013-08-13 14:04:20 +00:00
///////////////////////////////////////
// Operators
///////////////////////////////////////
2015-10-08 03:11:24 +00:00
2013-08-13 14:22:40 +00:00
// The operators works like in the C language
// For example:
2013-08-13 14:32:16 +00:00
2 + 5; // => 7
4.2f + 5.1f; // => 9.3f
2013-08-13 14:22:40 +00:00
3 == 2; // => 0 (NO)
3 != 2; // => 1 (YES)
1 && 1; // => 1 (Logical and)
0 || 1; // => 1 (Logical or)
~0x0F; // => 0xF0 (bitwise negation)
0x0F & 0xF0; // => 0x00 (bitwise AND)
0x01 << 1; // => 0x02 (bitwise left shift (by 1))
///////////////////////////////////////
// Control Structures
///////////////////////////////////////
// If-Else statement
if (NO)
{
NSLog(@"I am never run");
} else if (0)
{
NSLog(@"I am also never run");
} else
{
NSLog(@"I print");
}
// Switch statement
2013-08-13 14:32:16 +00:00
switch (2)
{
2013-08-13 14:22:40 +00:00
case 0:
{
NSLog(@"I am never run");
} break;
case 1:
{
NSLog(@"I am also never run");
} break;
default:
{
NSLog(@"I print");
} break;
}
2015-10-08 03:11:24 +00:00
2013-08-13 14:32:16 +00:00
// While loops statements
2013-08-13 14:22:40 +00:00
int ii = 0;
while (ii < 4)
{
NSLog(@"%d,", ii++); // ii++ increments ii in-place, after using its value
2015-10-08 03:11:24 +00:00
} // prints => "0,"
2013-08-13 14:34:12 +00:00
// "1,"
// "2,"
// "3,"
2013-08-13 14:22:40 +00:00
2013-08-13 14:32:16 +00:00
// For loops statements
2013-08-13 14:22:40 +00:00
int jj;
for (jj=0; jj < 4; jj++)
{
NSLog(@"%d,", jj);
2015-10-08 03:11:24 +00:00
} // prints => "0,"
2013-08-13 14:34:12 +00:00
// "1,"
// "2,"
// "3,"
2015-10-08 03:11:24 +00:00
// Foreach statements
2013-08-13 14:22:40 +00:00
NSArray *values = @[@0, @1, @2, @3];
for (NSNumber *value in values)
{
NSLog(@"%@,", value);
2015-10-08 03:11:24 +00:00
} // prints => "0,"
2013-08-13 14:34:12 +00:00
// "1,"
// "2,"
// "3,"
2013-08-13 14:04:20 +00:00
// Object for loop statement. Can be used with any Objective-C object type
2015-10-08 03:11:24 +00:00
for (id item in values) {
NSLog(@"%@,", item);
} // prints => "0,"
// "1,"
// "2,"
// "3,"
2013-08-13 14:32:16 +00:00
// Try-Catch-Finally statements
@try
{
// Your statements here
2013-08-13 17:30:44 +00:00
@throw [NSException exceptionWithName:@"FileNotFoundException"
reason:@"File Not Found on System" userInfo:nil];
2015-10-08 03:11:24 +00:00
} @catch (NSException * e) // use: @catch (id exceptionName) to catch all objects.
2013-08-13 14:32:16 +00:00
{
NSLog(@"Exception: %@", e);
} @finally
{
2014-01-09 03:27:42 +00:00
NSLog(@"Finally. Time to clean up.");
} // prints => "Exception: File Not Found on System"
2014-01-09 03:27:42 +00:00
// "Finally. Time to clean up."
2015-10-08 03:11:24 +00:00
// NSError objects are useful for function arguments to populate on user mistakes.
2014-01-09 03:27:42 +00:00
NSError *error = [NSError errorWithDomain:@"Invalid email." code:4 userInfo:nil];
2015-10-08 03:11:24 +00:00
2013-08-13 14:49:23 +00:00
///////////////////////////////////////
// Objects
///////////////////////////////////////
2015-10-08 03:11:24 +00:00
// Create an object instance by allocating memory and initializing it
// An object is not fully functional until both steps have been completed
2013-08-13 14:49:23 +00:00
MyClass *myObject = [[MyClass alloc] init];
2015-10-08 03:11:24 +00:00
2013-08-13 17:30:44 +00:00
// The Objective-C model of object-oriented programming is based on message
// passing to object instances
// In Objective-C one does not simply call a method; one sends a message
2013-08-13 17:30:44 +00:00
[myObject instanceMethodWithParameter:@"Steve Jobs"];
2013-08-13 14:49:23 +00:00
2013-08-13 13:25:47 +00:00
// Clean up the memory you used into your program
[pool drain];
// End of @autoreleasepool
}
2015-10-08 03:11:24 +00:00
2013-08-13 14:04:20 +00:00
// End the program
2013-08-13 13:25:47 +00:00
return 0;
}
2013-08-13 12:32:20 +00:00
2013-08-13 13:25:47 +00:00
///////////////////////////////////////
// Classes And Functions
///////////////////////////////////////
2013-08-13 12:32:20 +00:00
// Declare your class in a header file (MyClass.h):
// Class declaration syntax:
2013-08-13 14:58:13 +00:00
// @interface ClassName : ParentClassName <ImplementedProtocols>
2013-08-13 14:46:16 +00:00
// {
// type name; <= variable declarations;
2013-08-13 14:46:16 +00:00
// }
// @property type name; <= property declarations
// -/+ (type) Method declarations; <= Method declarations
2013-08-13 14:46:16 +00:00
// @end
2014-01-07 14:41:07 +00:00
@interface MyClass : NSObject <MyProtocol> // NSObject is Objective-C's base object class.
2013-08-13 13:25:47 +00:00
{
// Instance variable declarations (can exist in either interface or implementation file)
2015-10-08 03:11:24 +00:00
int count; // Protected access by default.
@private id data; // Private access (More convenient to declare in implementation file)
2015-10-08 03:11:24 +00:00
NSString *name;
2013-08-13 12:32:20 +00:00
}
// Convenient notation for public access variables to auto generate a setter method
// By default, setter method name is 'set' followed by @property variable name
2014-01-08 19:03:31 +00:00
@property int propInt; // Setter method name = 'setPropInt'
@property (copy) id copyId; // (copy) => Copy the object during assignment
// (readonly) => Cannot set value outside @interface
@property (readonly) NSString *roString; // Use @synthesize in @implementation to create accessor
// You can customize the getter and setter names instead of using default 'set' name:
@property (getter=lengthGet, setter=lengthSet:) int length;
2015-10-08 03:11:24 +00:00
2013-08-13 14:46:16 +00:00
// Methods
+/- (return type)methodSignature:(Parameter Type *)parameterName;
2013-08-13 12:32:20 +00:00
2014-01-08 19:03:31 +00:00
// + for class methods:
2013-08-13 13:25:47 +00:00
+ (NSString *)classMethod;
+ (MyClass *)myClassFromHeight:(NSNumber *)defaultHeight;
2013-08-13 12:32:20 +00:00
2014-01-08 19:03:31 +00:00
// - for instance methods:
2013-09-04 11:56:58 +00:00
- (NSString *)instanceMethodWithParameter:(NSString *)string;
2013-08-13 14:46:16 +00:00
- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number;
2013-08-13 17:30:44 +00:00
// Constructor methods with arguments:
- (id)initWithDistance:(int)defaultDistance;
// Objective-C method names are very descriptive. Always name methods according to their arguments
@end // States the end of the interface
// To access public variables from the implementation file, @property generates a setter method
// automatically. Method name is 'set' followed by @property variable name:
MyClass *myClass = [[MyClass alloc] init]; // create MyClass object instance
2015-10-08 03:11:24 +00:00
[myClass setCount:10];
NSLog(@"%d", [myClass count]); // prints => 10
// Or using the custom getter and setter method defined in @interface:
[myClass lengthSet:32];
NSLog(@"%i", [myClass lengthGet]); // prints => 32
// For convenience, you may use dot notation to set and access object instance variables:
myClass.count = 45;
NSLog(@"%i", myClass.count); // prints => 45
2014-01-08 19:03:31 +00:00
// Call class methods:
NSString *classMethodString = [MyClass classMethod];
MyClass *classFromName = [MyClass myClassFromName:@"Hello"];
// Call instance methods:
MyClass *myClass = [[MyClass alloc] init]; // Create MyClass object instance
2014-01-08 19:03:31 +00:00
NSString *stringFromInstanceMethod = [myClass instanceMethodWithParameter:@"Hello"];
// Selectors
2014-01-08 19:03:31 +00:00
// Way to dynamically represent methods. Used to call methods of a class, pass methods
// through functions to tell other classes they should call it, and to save methods
// as a variable
// SEL is the data type. @selector() returns a selector from method name provided
2014-01-07 04:18:54 +00:00
// methodAParameterAsString:andAParameterAsNumber: is method name for method in MyClass
2015-10-08 03:11:24 +00:00
SEL selectorVar = @selector(methodAParameterAsString:andAParameterAsNumber:);
if ([myClass respondsToSelector:selectorVar]) { // Checks if class contains method
// Must put all method arguments into one object to send to performSelector function
2014-01-07 04:18:54 +00:00
NSArray *arguments = [NSArray arrayWithObjects:@"Hello", @4, nil];
[myClass performSelector:selectorVar withObject:arguments]; // Calls the method
2014-01-07 04:18:54 +00:00
} else {
// NSStringFromSelector() returns a NSString of the method name of a given selector
2014-01-07 04:18:54 +00:00
NSLog(@"MyClass does not have method: %@", NSStringFromSelector(selectedVar));
}
2013-08-13 12:32:20 +00:00
2013-08-13 14:50:22 +00:00
// Implement the methods in an implementation (MyClass.m) file:
@implementation MyClass {
long distance; // Private access instance variable
NSNumber height;
}
2013-08-13 12:32:20 +00:00
2014-01-07 14:41:07 +00:00
// To access a public variable from the interface file, use '_' followed by variable name:
_count = 5; // References "int count" from MyClass interface
// Access variables defined in implementation file:
distance = 18; // References "long distance" from MyClass implementation
2014-01-07 04:18:54 +00:00
// To use @property variable in implementation, use @synthesize to create accessor variable:
@synthesize roString = _roString; // _roString available now in @implementation
// Called before calling any class methods or instantiating any objects
2015-10-08 03:11:24 +00:00
+ (void)initialize
{
if (self == [MyClass class]) {
distance = 0;
}
}
// Counterpart to initialize method. Called when an object's reference count is zero
2013-08-13 14:58:13 +00:00
- (void)dealloc
{
2015-10-08 03:11:24 +00:00
[height release]; // If not using ARC, make sure to release class variable objects
[super dealloc]; // and call parent class dealloc
2013-08-13 14:58:13 +00:00
}
// Constructors are a way of creating instances of a class
// This is a default constructor which is called when the object is initialized.
2013-08-13 14:46:16 +00:00
- (id)init
{
if ((self = [super init])) // 'super' used to access methods from parent class
2013-08-13 14:46:16 +00:00
{
self.count = 1; // 'self' used for object to call itself
2013-08-13 14:46:16 +00:00
}
return self;
}
// Can create constructors that contain arguments:
2015-10-08 03:11:24 +00:00
- (id)initWithDistance:(int)defaultDistance
{
distance = defaultDistance;
return self;
}
2013-08-13 14:46:16 +00:00
2013-08-13 13:25:47 +00:00
+ (NSString *)classMethod
{
2015-08-11 21:38:17 +00:00
return @"Some string";
2013-08-13 12:32:20 +00:00
}
2015-10-08 03:11:24 +00:00
+ (MyClass *)myClassFromHeight:(NSNumber *)defaultHeight
{
height = defaultHeight;
return [[self alloc] init];
}
2013-09-04 11:56:58 +00:00
- (NSString *)instanceMethodWithParameter:(NSString *)string
2013-08-13 12:32:20 +00:00
{
2013-08-13 13:25:47 +00:00
return @"New string";
2013-08-13 12:32:20 +00:00
}
2013-08-13 13:25:47 +00:00
- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number
2013-08-13 12:32:20 +00:00
{
2013-08-13 13:25:47 +00:00
return @42;
2013-08-13 12:32:20 +00:00
}
2013-08-13 13:25:47 +00:00
2015-10-08 03:11:24 +00:00
// Objective-C does not have private method declarations, but you can simulate them.
// To simulate a private method, create the method in the @implementation but not in the @interface.
- (NSNumber *)secretPrivateMethod {
return @72;
}
[self secretPrivateMethod]; // Calls private method
2013-08-13 14:58:13 +00:00
// Methods declared into MyProtocol
- (void)myProtocolMethod
{
// statements
}
@end // States the end of the implementation
2013-08-13 12:32:20 +00:00
///////////////////////////////////////
// Categories
///////////////////////////////////////
// A category is a group of methods designed to extend a class. They allow you to add new methods
2015-10-08 03:11:24 +00:00
// to an existing class for organizational purposes. This is not to be mistaken with subclasses.
// Subclasses are meant to CHANGE functionality of an object while categories instead ADD
// functionality to an object.
// Categories allow you to:
// -- Add methods to an existing class for organizational purposes.
// -- Allow you to extend Objective-C object classes (ex: NSString) to add your own methods.
2015-10-08 03:11:24 +00:00
// -- Add ability to create protected and private methods to classes.
// NOTE: Do not override methods of the base class in a category even though you have the ability
// to. Overriding methods may cause compiler errors later between different categories and it
// ruins the purpose of categories to only ADD functionality. Subclass instead to override methods.
// Here is a simple Car base class.
@interface Car : NSObject
@property NSString *make;
@property NSString *color;
- (void)turnOn;
- (void)accelerate;
@end
// And the simple Car base class implementation:
#import "Car.h"
@implementation Car
@synthesize make = _make;
@synthesize color = _color;
- (void)turnOn {
NSLog(@"Car is on.");
}
- (void)accelerate {
NSLog(@"Accelerating.");
}
@end
// Now, if we wanted to create a Truck object, we would instead create a subclass of Car as it would
2015-10-08 03:11:24 +00:00
// be changing the functionality of the Car to behave like a truck. But lets say we want to just add
// functionality to this existing Car. A good example would be to clean the car. So we would create
// a category to add these cleaning methods:
// @interface filename: Car+Clean.h (BaseClassName+CategoryName.h)
#import "Car.h" // Make sure to import base class to extend.
@interface Car (Clean) // The category name is inside () following the name of the base class.
- (void)washWindows; // Names of the new methods we are adding to our Car object.
- (void)wax;
2013-08-13 14:58:13 +00:00
@end
// @implementation filename: Car+Clean.m (BaseClassName+CategoryName.m)
#import "Car+Clean.h" // Import the Clean category's @interface file.
@implementation Car (Clean)
- (void)washWindows {
NSLog(@"Windows washed.");
}
- (void)wax {
NSLog(@"Waxed.");
}
2015-10-08 03:11:24 +00:00
@end
// Any Car object instance has the ability to use a category. All they need to do is import it:
#import "Car+Clean.h" // Import as many different categories as you want to use.
#import "Car.h" // Also need to import base class to use it's original functionality.
int main (int argc, const char * argv[]) {
@autoreleasepool {
Car *mustang = [[Car alloc] init];
mustang.color = @"Red";
mustang.make = @"Ford";
[mustang turnOn]; // Use methods from base Car class.
[mustang washWindows]; // Use methods from Car's Clean category.
}
2015-10-08 03:11:24 +00:00
return 0;
}
// Objective-C does not have protected method declarations but you can simulate them.
// Create a category containing all of the protected methods, then import it ONLY into the
// @implementation file of a class belonging to the Car class:
@interface Car (Protected) // Naming category 'Protected' to remember methods are protected.
- (void)lockCar; // Methods listed here may only be created by Car objects.
@end
//To use protected methods, import the category, then implement the methods:
#import "Car+Protected.h" // Remember, import in the @implementation file only.
2015-10-08 03:11:24 +00:00
@implementation Car
- (void)lockCar {
NSLog(@"Car locked."); // Instances of Car can't use lockCar because it's not in the @interface.
}
@end
///////////////////////////////////////
// Extensions
///////////////////////////////////////
// Extensions allow you to override public access property attributes and methods of an @interface.
// @interface filename: Shape.h
@interface Shape : NSObject // Base Shape class extension overrides below.
@property (readonly) NSNumber *numOfSides;
- (int)getNumOfSides;
@end
// You can override numOfSides variable or getNumOfSides method to edit them with an extension:
// @implementation filename: Shape.m
#import "Shape.h"
2015-10-08 03:11:24 +00:00
// Extensions live in the same file as the class @implementation.
@interface Shape () // () after base class name declares an extension.
@property (copy) NSNumber *numOfSides; // Make numOfSides copy instead of readonly.
-(NSNumber)getNumOfSides; // Make getNumOfSides return a NSNumber instead of an int.
-(void)privateMethod; // You can also create new private methods inside of extensions.
@end
// The main @implementation:
2015-10-08 03:11:24 +00:00
@implementation Shape
@synthesize numOfSides = _numOfSides;
-(NSNumber)getNumOfSides { // All statements inside of extension must be in the @implementation.
return _numOfSides;
}
-(void)privateMethod {
NSLog(@"Private method created by extension. Shape instances cannot call me.");
}
@end
// Starting in Xcode 7.0, you can create Generic classes,
// allowing you to provide greater type safety and clarity
2015-11-01 00:48:44 +00:00
// without writing excessive boilerplate.
@interface Result<__covariant A> : NSObject
- (void)handleSuccess:(void(^)(A))success
failure:(void(^)(NSError *))failure;
@property (nonatomic) A object;
@end
// we can now declare instances of this class like
Result<NSNumber *> *result;
Result<NSArray *> *result;
// Each of these cases would be equivalent to rewriting Result's interface
// and substituting the appropriate type for A
@interface Result : NSObject
- (void)handleSuccess:(void(^)(NSArray *))success
failure:(void(^)(NSError *))failure;
@property (nonatomic) NSArray * object;
@end
@interface Result : NSObject
- (void)handleSuccess:(void(^)(NSNumber *))success
failure:(void(^)(NSError *))failure;
@property (nonatomic) NSNumber * object;
@end
2015-11-01 00:48:44 +00:00
// It should be obvious, however, that writing one
// Class to solve a problem is always preferable to writing two
// Note that Clang will not accept generic types in @implementations,
// so your @implemnation of Result would have to look like this:
@implementation Result
- (void)handleSuccess:(void (^)(id))success
failure:(void (^)(NSError *))failure {
// Do something
}
@end
///////////////////////////////////////
// Protocols
///////////////////////////////////////
// A protocol declares methods that can be implemented by any class.
// Protocols are not classes themselves. They simply define an interface
// that other objects are responsible for implementing.
2014-01-09 03:27:42 +00:00
// @protocol filename: "CarUtilities.h"
@protocol CarUtilities <NSObject> // <NSObject> => Name of another protocol this protocol includes.
@property BOOL engineOn; // Adopting class must @synthesize all defined @properties and
- (void)turnOnEngine; // all defined methods.
@end
2015-10-08 03:11:24 +00:00
// Below is an example class implementing the protocol.
#import "CarUtilities.h" // Import the @protocol file.
@interface Car : NSObject <CarUtilities> // Name of protocol goes inside <>
// You don't need the @property or method names here for CarUtilities. Only @implementation does.
- (void)turnOnEngineWithUtilities:(id <CarUtilities>)car; // You can use protocols as data too.
@end
2015-10-08 03:11:24 +00:00
// The @implementation needs to implement the @properties and methods for the protocol.
@implementation Car : NSObject <CarUtilities>
@synthesize engineOn = _engineOn; // Create a @synthesize statement for the engineOn @property.
- (void)turnOnEngine { // Implement turnOnEngine however you would like. Protocols do not define
_engineOn = YES; // how you implement a method, it just requires that you do implement it.
}
// You may use a protocol as data as you know what methods and variables it has implemented.
2015-10-08 03:11:24 +00:00
- (void)turnOnEngineWithCarUtilities:(id <CarUtilities>)objectOfSomeKind {
[objectOfSomeKind engineOn]; // You have access to object variables
2015-10-08 03:11:24 +00:00
[objectOfSomeKind turnOnEngine]; // and the methods inside.
[objectOfSomeKind engineOn]; // May or may not be YES. Class implements it however it wants.
}
2013-08-13 14:58:13 +00:00
@end
2015-10-08 03:11:24 +00:00
// Instances of Car now have access to the protocol.
Car *carInstance = [[Car alloc] init];
2015-02-01 02:38:24 +00:00
[carInstance setEngineOn:NO];
[carInstance turnOnEngine];
if ([carInstance engineOn]) {
NSLog(@"Car engine is on."); // prints => "Car engine is on."
}
// Make sure to check if an object of type 'id' implements a protocol before calling protocol methods:
if ([myClass conformsToProtocol:@protocol(CarUtilities)]) {
NSLog(@"This does not run as the MyClass class does not implement the CarUtilities protocol.");
} else if ([carInstance conformsToProtocol:@protocol(CarUtilities)]) {
NSLog(@"This does run as the Car class implements the CarUtilities protocol.");
}
// Categories may implement protocols as well: @interface Car (CarCategory) <CarUtilities>
// You may implement many protocols: @interface Car : NSObject <CarUtilities, CarCleaning>
// NOTE: If two or more protocols rely on each other, make sure to forward-declare them:
#import "Brother.h"
@protocol Brother; // Forward-declare statement. Without it, compiler would through error.
@protocol Sister <NSObject>
- (void)beNiceToBrother:(id <Brother>)brother;
2013-08-13 14:58:13 +00:00
2014-01-09 03:27:42 +00:00
@end
// See the problem is that Sister relies on Brother, and Brother relies on Sister.
#import "Sister.h"
2015-10-08 03:11:24 +00:00
@protocol Sister; // These lines stop the recursion, resolving the issue.
@protocol Brother <NSObject>
2015-10-08 03:11:24 +00:00
- (void)beNiceToSister:(id <Sister>)sister;
@end
2013-08-13 14:58:13 +00:00
2014-01-09 03:27:42 +00:00
///////////////////////////////////////
// Blocks
///////////////////////////////////////
2015-10-08 03:11:24 +00:00
// Blocks are statements of code, just like a function, that are able to be used as data.
2014-01-09 03:27:42 +00:00
// Below is a simple block with an integer argument that returns the argument plus 4.
2015-10-08 03:11:24 +00:00
int (^addUp)(int n); // Declare a variable to store the block.
void (^noParameterBlockVar)(void); // Example variable declaration of block with no arguments.
2014-01-09 03:27:42 +00:00
// Blocks have access to variables in the same scope. But the variables are readonly and the
2015-10-08 03:11:24 +00:00
// value passed to the block is the value of the variable when the block is created.
2014-01-09 03:27:42 +00:00
int outsideVar = 17; // If we edit outsideVar after declaring addUp, outsideVar is STILL 17.
__block long mutableVar = 3; // __block makes variables writable to blocks, unlike outsideVar.
2015-10-08 03:11:24 +00:00
addUp = ^(int n) { // Remove (int n) to have a block that doesn't take in any parameters.
2014-01-09 03:27:42 +00:00
NSLog(@"You may have as many lines in a block as you would like.");
NSSet *blockSet; // Also, you can declare local variables.
mutableVar = 32; // Assigning new value to __block variable.
2015-10-08 03:11:24 +00:00
return n + outsideVar; // Return statements are optional.
2014-01-09 03:27:42 +00:00
}
int addUp = addUp(10 + 16); // Calls block code with arguments.
2014-01-09 03:27:42 +00:00
// Blocks are often used as arguments to functions to be called later, or for callbacks.
2015-10-08 03:11:24 +00:00
@implementation BlockExample : NSObject
2014-01-09 03:27:42 +00:00
- (void)runBlock:(void (^)(NSString))block {
NSLog(@"Block argument returns nothing and takes in a NSString object.");
block(@"Argument given to block to execute."); // Calling block.
}
@end
2013-12-31 19:50:37 +00:00
///////////////////////////////////////
// Memory Management
///////////////////////////////////////
2015-10-08 03:11:24 +00:00
/*
2013-12-31 19:50:37 +00:00
For each object used in an application, memory must be allocated for that object. When the application
2015-10-08 03:11:24 +00:00
is done using that object, memory must be deallocated to ensure application efficiency.
Objective-C does not use garbage collection and instead uses reference counting. As long as
2013-12-31 19:50:37 +00:00
there is at least one reference to an object (also called "owning" an object), then the object
2015-10-08 03:11:24 +00:00
will be available to use (known as "ownership").
2013-12-31 19:50:37 +00:00
When an instance owns an object, its reference counter is increments by one. When the
object is released, the reference counter decrements by one. When reference count is zero,
2015-10-08 03:11:24 +00:00
the object is removed from memory.
2013-12-31 19:50:37 +00:00
2015-10-08 03:11:24 +00:00
With all object interactions, follow the pattern of:
(1) create the object, (2) use the object, (3) then free the object from memory.
2013-12-31 19:50:37 +00:00
*/
MyClass *classVar = [MyClass alloc]; // 'alloc' sets classVar's reference count to one. Returns pointer to object
[classVar release]; // Decrements classVar's reference count
// 'retain' claims ownership of existing object instance and increments reference count. Returns pointer to object
MyClass *newVar = [classVar retain]; // If classVar is released, object is still in memory because newVar is owner
[classVar autorelease]; // Removes ownership of object at end of @autoreleasepool block. Returns pointer to object
2013-12-31 19:50:37 +00:00
// @property can use 'retain' and 'assign' as well for small convenient definitions
@property (retain) MyClass *instance; // Release old value and retain a new one (strong reference)
@property (assign) NSSet *set; // Pointer to new value without retaining/releasing old (weak reference)
2013-12-31 19:50:37 +00:00
// Automatic Reference Counting (ARC)
// Because memory management can be a pain, Xcode 4.2 and iOS 4 introduced Automatic Reference Counting (ARC).
2015-10-08 03:11:24 +00:00
// ARC is a compiler feature that inserts retain, release, and autorelease automatically for you, so when using ARC,
// you must not use retain, relase, or autorelease
2015-10-08 03:11:24 +00:00
MyClass *arcMyClass = [[MyClass alloc] init];
// ... code using arcMyClass
2015-10-08 03:11:24 +00:00
// Without ARC, you will need to call: [arcMyClass release] after you're done using arcMyClass. But with ARC,
// there is no need. It will insert this release statement for you
// As for the 'assign' and 'retain' @property attributes, with ARC you use 'weak' and 'strong'
@property (weak) MyClass *weakVar; // 'weak' does not take ownership of object. If original instance's reference count
// is set to zero, weakVar will automatically receive value of nil to avoid application crashing
@property (strong) MyClass *strongVar; // 'strong' takes ownership of object. Ensures object will stay in memory to use
// For regular variables (not @property declared variables), use the following:
__strong NSString *strongString; // Default. Variable is retained in memory until it leaves it's scope
__weak NSSet *weakSet; // Weak reference to existing object. When existing object is released, weakSet is set to nil
__unsafe_unretained NSArray *unsafeArray; // Like __weak, but unsafeArray not set to nil when existing object is released
2013-08-13 14:58:13 +00:00
2013-08-13 12:32:20 +00:00
```
## Further Reading
[Wikipedia Objective-C](http://en.wikipedia.org/wiki/Objective-C)
[Programming with Objective-C. Apple PDF book](https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/ProgrammingWithObjectiveC.pdf)
2013-08-13 12:32:20 +00:00
[Programming with Objective-C for iOS](https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/ObjectiveC.html)
[Programming with Objective-C for Mac OSX](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html)
2013-08-13 12:32:20 +00:00
[iOS For High School Students: Getting Started](http://www.raywenderlich.com/5600/ios-for-high-school-students-getting-started)