On Github xichen2016 / objc_basic_sides
Created by Chen Xi
Objective-C is a strict superset of C, which means that it’s possible to seamlessly combine both languages in the same source file.
// This is an inline comment
/* This is a block comment.
It can span multiple lines. */
// main.m
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
double odometer = 9200.8;
int odometerAsInteger = (int)odometer;
NSLog(@"You've driven %.1f miles", odometer); // 9200.8
NSLog(@"You've driven %d miles", odometerAsInteger); // 9200
}
return 0;
}
double const pi = 3.14159;
pi = 42001.0; // Compiler error
id
The id type is the generic type for all Objective-C objects. Like a void pointer, it can store a reference to any type of object.
id mysteryObject = @"An NSString object";
NSLog(@"%@", [mysteryObject description]);
mysteryObject = @{@"model": @"Ford", @"year": @1967};
NSLog(@"%@", [mysteryObject description]);
Class
Objective-C classes are represented as objects themselves, using a special data type called Class. This lets you, for example, dynamically check an object’s type at runtime.
Class targetClass = [NSString class];
id mysteryObject = @"An NSString object";
if ([mysteryObject isKindOfClass:targetClass]) {
NSLog(@"Yup! That's an instance of the target class");
}
SEL
The SEL data type is used to store selectors, which are Objective-C’s internal representation of a method name.
SEL someMethod = @selector(sayHello);
standard alloc/init pattern
NSNumber *twentySeven = [[NSNumber alloc] initWithInt:27];factory methods provided by Foundation Framework
NSNumber *twentySeven = [NSNumber numberWithInt:27];
int modelYear = 1990;
if (modelYear < 1967) {
NSLog(@"That car is an antique!!!");
} else if (modelYear <= 1991) {
NSLog(@"That car is a classic!");
} else if (modelYear == 2013) {
NSLog(@"That's a brand new car!");
} else {
NSLog(@"There's nothing special about that car.");
}
// Switch statements (only work with integral types)
switch (modelYear) {
case 1987:
NSLog(@"Your car is from 1987.");
break;
case 1988:
NSLog(@"Your car is from 1988.");
break;
case 1989:
case 1990:
NSLog(@"Your car is from 1989 or 1990.");
break;
default:
NSLog(@"I have no idea when your car was made.");
break;
}
// For-in loops ("Fast-enumeration," specific to Objective-C)
NSArray *models = @[@"Ford", @"Honda", @"Nissan", @"Porsche"];
for (id model in models) {
NSLog(@"%@", model);
}
Objective-C is similar to C++ in that it abstracts a class’s interface from its implementation. An interface declares the public properties and methods of a class, and the corresponding implementation defines the code that actually makes these properties and methods work.
// Car.h
#import <Foundation/Foundation.h>
@interface Car : NSObject {
// Protected instance variables
}
@property (copy) NSString *model;
- (void)drive;
@end
// Car.m
#import "Car.h"
@implementation Car {
// Private instance variables
double _odometer;
}
@synthesize model = _model; // Optional for Xcode 4.4+
- (void)drive {
NSLog(@"Driving a %@. Vrooooom!", self.model);
}
@end
// main.m
#import <Foundation/Foundation.h>
#import "Car.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Car *toyota = [[Car alloc] init];
[toyota setModel:@"Toyota Corolla"];
NSLog(@"Created a %@", [toyota model]);
toyota.model = @"Toyota Camry";
NSLog(@"Changed the car to a %@", toyota.model);
[toyota drive];
}
return 0;
}
// Car.h
+ (void)setDefaultModel:(NSString *)aModel;
// Car.m
#import "Car.h"
static NSString *_defaultModel;
@implementation Car {
...
+ (void)setDefaultModel:(NSString *)aModel {
_defaultModel = [aModel copy];
}
@end
// main.m
[Car setDefaultModel:@"Nissan Versa"];
// Car.h
- (id)initWithModel:(NSString *)aModel;
// Car.m
- (id)initWithModel:(NSString *)aModel {
self = [super init];
if (self) {
// Any custom setup work goes here
_model = [aModel copy];
_odometer = 0;
}
return self;
}
- (id)init {
// Forward to the "designated" initialization method
return [self initWithModel:_defaultModel];
}
// Car.m
+ (void)initialize {
if (self == [Car class]) {
// Makes sure this isn't executed more than once
_defaultModel = @"Nissan Versa";
}
}
// main.m
#import <Foundation/Foundation.h>
#import "Car.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// Instantiating objects
Car *nissan = [[Car alloc] init];
NSLog(@"Created a %@", [nissan model]);
Car *chevy = [[Car alloc] initWithModel:@"Chevy Corvette"];
NSLog(@"Created a %@, too.", chevy.model);
}
return 0;
}
// Car.h
#import <Foundation/Foundation.h>
@interface Car : NSObject
@property BOOL running;
@end
// Car.m
#import "Car.h"
@implementation Car
@synthesize running = _running; // Optional for Xcode 4.4+
@end
- (BOOL)running {
return _running;
}
- (void)setRunning:(BOOL)newValue {
_running = newValue;
}
// main.m
#import <Foundation/Foundation.h>
#import "Car.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Car *honda = [[Car alloc] init];
honda.running = YES; // [honda setRunning:YES]
NSLog(@"%d", honda.running); // [honda running]
}
return 0;
}
honda.running code actually calls setRunning: when you assign a value to it and the running method when you read a value from it.
If you don’t like @property’s default naming conventions, you can change the getter/setter method names with the getter= and setter= attributes.
@property (getter=isRunning) BOOL running;
Car *honda = [[Car alloc] init];
honda.running = YES; // [honda setRunning:YES]
NSLog(@"%d", honda.running); // [honda isRunning]
NSLog(@"%d", [honda running]); // Error: method no longer exists
The readonly attribute is an easy way to make a property read-only. It omits the setter method and prevents assignment via dot-notation, but the getter is unaffected.
#import <Foundation/Foundation.h>
@interface Car : NSObject
@property (getter=isRunning, readonly) BOOL running;
- (void)startEngine;
- (void)stopEngine;
@end
// Car.m
#import "Car.h"
@implementation Car
- (void)startEngine {
_running = YES;
}
- (void)stopEngine {
_running = NO;
}
@end
Car *honda = [[Car alloc] init];
[honda startEngine];
NSLog(@"Running: %d", honda.running);
honda.running = NO; // Error: read-only property
@property (nonatomic) NSString *model;
// Accessors
- (BOOL)isRunning;
- (void)setRunning:(BOOL)running;
// Action methods
- (void)driveForDistance:(double)theDistance;
- (void)driveFromOrigin:(id)theOrigin toDestination:(id)theDestination;
// Constructor methods
- (id)initWithModel:(NSString *)aModel;
- (id)initWithModel:(NSString *)aModel mileage:(double)theMileage;
// Comparison methods
- (BOOL)isEqualToCar:(Car *)anotherCar;
[porsche initWithModel:@"Porsche"];
[porsche initWithModel:@"Porsche" mileage:42000.0];
[[Car alloc] init];
Selectors are Objective-C’s internal representation of a method name. They let you treat a method as an independent entity, enabling you to separate an action from the object that needs to perform it.
// main.m
#import <Foundation/Foundation.h>
#import "Car.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Car *porsche = [[Car alloc] init];
porsche.model = @"Porsche 911 Carrera";
SEL stepOne = NSSelectorFromString(@"startEngine");
SEL stepTwo = @selector(driveForDistance:);
SEL stepThree = @selector(turnByAngle:quickly:);
// This is the same as:
// [porsche startEngine];
[porsche performSelector:stepOne];
// This is the same as:
// [porsche driveForDistance:[NSNumber numberWithDouble:5.7]];
[porsche performSelector:stepTwo
withObject:[NSNumber numberWithDouble:5.7]];
if ([porsche respondsToSelector:stepThree]) {
// This is the same as:
// [porsche turnByAngle:[NSNumber numberWithDouble:90.0]
// quickly:[NSNumber numberWithBool:YES]];
[porsche performSelector:stepThree
withObject:[NSNumber numberWithDouble:90.0]
withObject:[NSNumber numberWithBool:YES]];
}
NSLog(@"Step one: %@", NSStringFromSelector(stepOne));
}
return 0;
}