SlideShare a Scribd company logo
1 of 279
Download to read offline
Modernizes your
Objective-C
Massimo Oliviero!
Software Developer

@maxoly
About
Massimo Oliviero

Freelance Software Developer & Trainer

#pragma mark founder
!
www.massimooliviero.net

massimo.oliviero@gmail.com

@maxoly
#pragma mark
iOS & OSX Developers Community
We organize the #PragmaConference, an event
dedicated to iOS and OS X development
!
http://www.pragmamark.org
http://www.facebook.com/groups/pragmamark
@pragmamarkorg
Agenda
Agenda
‣ Syntax
Agenda
‣ Syntax
‣ Conventions
Agenda
‣ Syntax
‣ Conventions
‣ Coding
Agenda
‣ Syntax
‣ Conventions
‣ Coding
‣ Framework
Syntax
use new literal syntax
you can create NSArray, NSDictionary, NSNumber with a simple @
Literals
NSArray *names = [NSArray
arrayWithObjects:@"Marco", @"Paolo", @"Flavio", nil];
NSDictionary *jobs = [NSDictionary
dictionaryWithObjectsAndKeys:@"Marco", @"CTO", @"Paolo", "CEO", nil];
NSNumber *one = [NSNumber numberWithInt:1];
NSNumber *boolNum = [NSNumber numberWithBool:YES];
NSNumber *square = [NSNumber numberWithDouble:sqrt(2)];
Literals
NSArray *names = [NSArray
arrayWithObjects:@"Marco", @"Paolo", @"Flavio", nil];
NSDictionary *jobs = [NSDictionary
dictionaryWithObjectsAndKeys:@"Marco", @"CTO", @"Paolo", "CEO", nil];
NSNumber *one = [NSNumber numberWithInt:1];
NSNumber *boolNum = [NSNumber numberWithBool:YES];
NSNumber *square = [NSNumber numberWithDouble:sqrt(2)];
NSArray *names = @[ @"Marco", @"Paolo", @"Giuseppe" ];
!
NSDictionary *jobs = @{ @"CTO" : @"Marco", @"CEO" : @"Paolo" };
!
NSNumber *one = @1;
NSNumber *boolNum = @YES;
NSNumber *square = @(sqrt(2));
Literals
Literals
‣ The new object literals significantly reduce the
verbosity of code
Literals
‣ The new object literals significantly reduce the
verbosity of code
‣ All objects made via literal (such an array or a
dictionary) are immutable
Literals
‣ The new object literals significantly reduce the
verbosity of code
‣ All objects made via literal (such an array or a
dictionary) are immutable
‣ Remember that @(expr) dynamically evaluates the
boxed expression and returns the appropriate object
literal based on its value
use Object Subscripting
Object pointer values can now be used with C’s subscripting operator
Object Subscripting
!
NSArray *people = @[ @"John", @"Steve", @"Bill" ];
NSString *steve = [people objectAtIndex:1];
NSDictionary *books = @{ @"123" : @"Odyssey", @"234" : @"Illiad" };
NSString *illiad = [books objectForKey:@“234"];
!
// Mutable
NSMutableArray *mPeople = [people mutableCopy];
[mPeople addObject:@"Ive"];
NSMutableDictionary *mBooks = [books mutableCopy];
[mBooks setObject:@"Othello" forKey:@"876"];
Object Subscripting
!
NSArray *people = @[ @"John", @"Steve", @"Bill" ];
NSString *steve = [people objectAtIndex:1];
NSDictionary *books = @{ @"123" : @"Odyssey", @"234" : @"Illiad" };
NSString *illiad = [books objectForKey:@“234"];
!
// Mutable
NSMutableArray *mPeople = [people mutableCopy];
[mPeople addObject:@"Ive"];
NSMutableDictionary *mBooks = [books mutableCopy];
[mBooks setObject:@"Othello" forKey:@"876"];
!
NSArray *people = @[ @"John", @"Steve", @"Bill" ];
NSString *steve = people[1];
NSDictionary *books = @{ @"123" : @"Odyssey", @"234" : @"Illiad" };
NSString *illiad = books[@"234"];
!
!
// Mutable
NSMutableArray *mPeople = [people mutableCopy];
mPeople[3] = @"Ive";
NSMutableDictionary *mBooks = [books mutableCopy];
mBooks[@"876"] = @"Othello";
Custom Subscripting
Custom Subscripting
@interface MGACustomer : NSObject
@property (nonatomic, strong, readonly) NSArray *orders;
// Custom Indexed Subscripting
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;
// Custom Keyed Subscripting
- (id)objectForKeyedSubscript:(id <NSCopying>)key;
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key;
@end
// how to use custom subscripting
- (void)foo
{
MGACustomer *customer = [[MGACustomer alloc] init];
id order67 = customer[67];
id order34 = customer[@"order.34"];
}
Object Subscripting
Object Subscripting
‣ Subscripting syntax can significantly reduce the
verbosity of code that deals heavily with arrays and
dictionaries
Object Subscripting
‣ Subscripting syntax can significantly reduce the
verbosity of code that deals heavily with arrays and
dictionaries
‣ Syntax similar to that found in common scripting
languages
Object Subscripting
‣ Subscripting syntax can significantly reduce the
verbosity of code that deals heavily with arrays and
dictionaries
‣ Syntax similar to that found in common scripting
languages
‣ You can extend your own classes with subscripting
support
use new @import declaration
@import is the new compiler directive introduced by Modules
@import
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h> // you must add framework from Target > Build Phases
!
!
@interface MGAMapViewController : UIViewController
!
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
!
@end
@import
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h> // you must add framework from Target > Build Phases
!
!
@interface MGAMapViewController : UIViewController
!
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
!
@end
@import UIKit;
@import MapKit; // no additional steps required
!
!
@interface MGAMapViewController : UIViewController
!
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
!
@end
@import
@import
‣ Modules provide an alternative, simpler way to use
software libraries that provides better compile-time
scalability and eliminates many of the problems
inherent to using the C preprocessor to access the API
of a library
@import
‣ Modules provide an alternative, simpler way to use
software libraries that provides better compile-time
scalability and eliminates many of the problems
inherent to using the C preprocessor to access the API
of a library
‣ Modules link frameworks automatically (no more
need to link framework from Build Phases)
@import
‣ Modules provide an alternative, simpler way to use
software libraries that provides better compile-time
scalability and eliminates many of the problems
inherent to using the C preprocessor to access the API
of a library
‣ Modules link frameworks automatically (no more
need to link framework from Build Phases)
‣ At this time, modules are only available for Apple’s
frameworks and have been implicitly disabled for C++
use new type instancetype
instancetype is a contextual keyword that can be used as a result type to signal that a
method returns a related result type, you can use it as return type of an init method or
a (convenient)constructor
instancetype
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, copy) NSString *name;
+ (id)customerWithName:(NSString *)name;
!
@end
!
@implementation MGACustomer
!
+ (id)customerWithName:(NSString *)name
{
id user = [[self alloc] init];
[user setName:name];
return user;
}
!
@end
!
!
!
!
!
!
!
!
instancetype
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, copy) NSString *name;
+ (id)customerWithName:(NSString *)name;
!
@end
!
@implementation MGACustomer
!
+ (id)customerWithName:(NSString *)name
{
id user = [[self alloc] init];
[user setName:name];
return user;
}
!
@end
!
!
!
!
!
!
!
!
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, copy) NSString *name;
+ (id)customerWithName:(NSString *)name;
!
@end
!
@implementation MGACustomer
!
+ (id)customerWithName:(NSString *)name
{
id user = [[self alloc] init];
[user setName:name];
return user;
}
!
@end
!
..
!
- (void)foo
{
// assign an object of type MGACustomer to a string variable
// will not generate any error or warning at compile-time
NSString *wrong = [MGACustomer customerWithName:@"test"];
}
instancetype
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, copy) NSString *name;
+ (id)customerWithName:(NSString *)name;
!
@end
!
@implementation MGACustomer
!
+ (id)customerWithName:(NSString *)name
{
id user = [[self alloc] init];
[user setName:name];
return user;
}
!
@end
!
!
!
!
!
!
!
!
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, copy) NSString *name;
+ (id)customerWithName:(NSString *)name;
!
@end
!
@implementation MGACustomer
!
+ (id)customerWithName:(NSString *)name
{
id user = [[self alloc] init];
[user setName:name];
return user;
}
!
@end
!
..
!
- (void)foo
{
// assign an object of type MGACustomer to a string variable
// will not generate any error or warning at compile-time
NSString *wrong = [MGACustomer customerWithName:@"test"];
}
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, copy) NSString *name;
+ (instancetype)customerWithName:(NSString *)name;
!
@end
!
@implementation MGACustomer
!
+ (instancetype)customerWithName:(NSString *)name
{
id user = [[self alloc] init];
[user setName:name];
return user;
}
!
@end
!
..
!
- (void)foo
{
// With ‘instancetype’ the compiler could infer type, it will generate: Incompatible
// pointer types initializing 'NSString *' with an expression of type 'MGACustomer *'
NSString *wrong = [MGACustomer customerWithName:@"test"];
}
instancetype
instancetype
‣ With instancetype, the compiler will correctly infer
that the result of convenient constructor is an
instance of a MGACustomer
instancetype
‣ With instancetype, the compiler will correctly infer
that the result of convenient constructor is an
instance of a MGACustomer
‣ Instancetype, unlike id, can only be used as the result
type in a method declaration
instancetype
‣ With instancetype, the compiler will correctly infer
that the result of convenient constructor is an
instance of a MGACustomer
‣ Instancetype, unlike id, can only be used as the result
type in a method declaration
‣ Init method should also use instancetype instead of
id, instancetype is more explicit and therefore better
than id
use auto property synthesis
synthesize not necessary for @property since Xcode 4.4
auto property synthesis
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, copy) NSString *name;
@property (nonatomic, readwrite, copy) NSString *address;
!
@end
!
!
!
!
@implementation MGACustomer
{
NSString *_name;
NSString *_address;
}
!
@synthesize name = _name;
@synthesize address = _address;
!
- (void)foo
{
_name = @"Apple Inc.";
}
!
@end
auto property synthesis
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, copy) NSString *name;
@property (nonatomic, readwrite, copy) NSString *address;
!
@end
!
!
!
!
@implementation MGACustomer
{
NSString *_name;
NSString *_address;
}
!
@synthesize name = _name;
@synthesize address = _address;
!
- (void)foo
{
_name = @"Apple Inc.";
}
!
@end
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, copy) NSString *name;
@property (nonatomic, readwrite, copy) NSString *address;
!
@end
!
!
!
!
@implementation MGACustomer
!
!
// compiler auto-synthesizes properties for you
// and generate corresponding ivar(s)
// with underscore as prefix
!
!
!
- (void)foo
{
_name = @"Apple Inc.”; // you can still access to ivar
}
!
@end
auto property synthesis
auto property synthesis
‣ Clang provides support for autosynthesis of declared
properties. Using this feature, clang provides default
synthesis of those properties not declared @dynamic
and not having user provided backing getter and
setter methods.
auto property synthesis
‣ Clang provides support for autosynthesis of declared
properties. Using this feature, clang provides default
synthesis of those properties not declared @dynamic
and not having user provided backing getter and
setter methods.
‣ Auto-synthesis is not support for properties defined in
a protocol
auto property synthesis
‣ Clang provides support for autosynthesis of declared
properties. Using this feature, clang provides default
synthesis of those properties not declared @dynamic
and not having user provided backing getter and
setter methods.
‣ Auto-synthesis is not support for properties defined in
a protocol
‣ The compiler will add the ivar for you (with underscore
prefix) when it adds the required accessor methods
use copy for any immutable class
for attributes whose type is an immutable value class that conforms to the
NSCopying protocol (e.g.. NSDate, NSNumber, NSArray, NSSet), you almost always
should specify copy in your @property declaration
copy attribute
!
!
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, strong) NSString *name;
@property (nonatomic, readwrite, strong) NSString *address;
@property (nonatomic, readwrite, strong) NSArray *orders;
@property (nonatomic, readwrite, strong) NSDate *created;
!
@end
!
copy attribute
!
!
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, strong) NSString *name;
@property (nonatomic, readwrite, strong) NSString *address;
@property (nonatomic, readwrite, strong) NSArray *orders;
@property (nonatomic, readwrite, strong) NSDate *created;
!
@end
!
!
!
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, copy) NSString *name;
@property (nonatomic, readwrite, copy) NSString *address;
@property (nonatomic, readwrite, copy) NSArray *orders;
@property (nonatomic, readwrite, copy) NSDate *created;
!
@end
!
copy attribute
copy attribute
‣ The reason of copy is that it is possible to have a
property that is declared as an immutable type (such
as NSString) yet pass it a mutable type (such as
NSMutableString). In which case it is possible to
change the property from outside the class
copy attribute
‣ The reason of copy is that it is possible to have a
property that is declared as an immutable type (such
as NSString) yet pass it a mutable type (such as
NSMutableString). In which case it is possible to
change the property from outside the class
‣ using copy is recommended, because it behaves
sensibly with class clusters, sending copy to a mutable
class returns an immutable copy of the object
NS_ENUM & NS_OPTIONS macro
these macros are the new, preferred way to declare enum types.
NS_ENUM
typedef enum MGAUserProfile : NSUInteger
{
MGAUserProfileAdmin,
MGAUserProfileGuest,
MGAUserProfileOperator
} MGAUserProfile;
!
!
!
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, assign) MGAUserProfile profile;
!
@end
NS_ENUM
typedef enum MGAUserProfile : NSUInteger
{
MGAUserProfileAdmin,
MGAUserProfileGuest,
MGAUserProfileOperator
} MGAUserProfile;
!
!
!
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, assign) MGAUserProfile profile;
!
@end
typedef NS_ENUM(NSUInteger, MGAUserProfile)
{
MGAUserProfileAdmin,
MGAUserProfileGuest,
MGAUserProfileOperator
};
!
!
!
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, assign) MGAUserProfile profile;
!
@end
NS_OPTIONS
typedef enum MGAUserProfile : NSUInteger
{
MGAUserProfileAdmin = 1 << 0,
MGAUserProfileGuest = 1 << 1,
MGAUserProfileOperator = 1 << 2
} MGAUserProfile;
!
!
!
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, assign) MGAUserProfile profile;
!
@end
NS_OPTIONS
typedef enum MGAUserProfile : NSUInteger
{
MGAUserProfileAdmin = 1 << 0,
MGAUserProfileGuest = 1 << 1,
MGAUserProfileOperator = 1 << 2
} MGAUserProfile;
!
!
!
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, assign) MGAUserProfile profile;
!
@end
typedef NS_OPTIONS(NSUInteger, MGAUserProfile)
{
MGAUserProfileAdmin = 1 << 0,
MGAUserProfileGuest = 1 << 1,
MGAUserProfileOperator = 1 << 2,
};
!
!
!
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, assign) MGAUserProfile profile;
!
@end
NS_ENUM & NS_OPTIONS
NS_ENUM & NS_OPTIONS
‣ The new macros combines the best of all ways to
declare an enum or an option, and even provide hints
to the compiler for type-checking and switch
statement completeness.
NS_ENUM & NS_OPTIONS
‣ The new macros combines the best of all ways to
declare an enum or an option, and even provide hints
to the compiler for type-checking and switch
statement completeness.
‣ If the compiler is operating in C++11 or Objective-C+
+11 mode, the macros behave slightly differently in
order to make the code compatible with the mixed
mode
use extern const not #define
the best way to define a globally accessible constant is extern const
extern const
// Constants.h
#define kMGAProjectConst @“myString"
#define kMGASomeMagicValue 42
extern const
// Constants.h
#define kMGAProjectConst @“myString"
#define kMGASomeMagicValue 42
extern const
// Constants.h
extern NSString * const kMGAProjectConst;
extern CGFloat const kMGASomeMagicValue;
// Constants.m
#import “Constants.h"
NSString * const kMGAProjectConst = @“server.com”;
CGFloat const kMGASomeMagicValue = 42.0f;
// Constants.h
#define kMGAProjectConst @“myString"
#define kMGASomeMagicValue 42
extern const
// Constants.h
extern NSString * const kMGAProjectConst;
extern CGFloat const kMGASomeMagicValue;
// Constants.m
#import “Constants.h"
NSString * const kMGAProjectConst = @“server.com”;
CGFloat const kMGASomeMagicValue = 42.0f;
// Constants.h
FOUNDATION_EXPORT NSString * const kMGAProjectConst;
FOUNDATION_EXPORT CGFloat const kMGASomeMagicValue;
!
!
!
// Constants.m
#import “Constants.h"
!
NSString * const kMGAProjectConst = @“server.com”;
CGFloat const kMGASomeMagicValue = 42.0f;
extern const
extern const
‣ It ensures that the compiler do a static type
checking and emit a warning if you try to use it
somewhere where it isn't expecting
extern const
‣ It ensures that the compiler do a static type
checking and emit a warning if you try to use it
somewhere where it isn't expecting
‣ One benefit is that changing the value of a constant
does not cause a rebuild of your entire program.
extern const
‣ It ensures that the compiler do a static type
checking and emit a warning if you try to use it
somewhere where it isn't expecting
‣ One benefit is that changing the value of a constant
does not cause a rebuild of your entire program.
‣ Use FOUNDATION_EXPORT macro instead of extern
if your code will be used in mixed C/C++
environments or on other platforms
use Foundation Data Types
if you are unsure, the Foundation Data Types (like NSInterger or CGFloat) are the best
choice because they are architecture safe versions of the corresponding C types
Foundation Data Types
Foundation Data Types
‣ The Fondation Data Types were introduced to make it
easier to write code that works on both 32-bit and 64-
bit without modification
Foundation Data Types
‣ The Fondation Data Types were introduced to make it
easier to write code that works on both 32-bit and 64-
bit without modification
‣ You usually want to use Foundation Data Types when
you don't know what kind of processor architecture
your code might run on
Foundation Data Types
‣ The Fondation Data Types were introduced to make it
easier to write code that works on both 32-bit and 64-
bit without modification
‣ You usually want to use Foundation Data Types when
you don't know what kind of processor architecture
your code might run on
‣ However, if you need to take control on memory
footprint you can use native types
Use Class Extensions to Hide Private Data
Class extensions are often used to extend the public interface with additional private
methods, properties or ivars for use within the implementation of the class itself
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
!
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
!
!
!
!
!
!
!
!
@end
!
@implementation MGAMapViewController
!
!
!
!
!
!
!
!
!
@end
Class Extensions
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
!
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
!
!
!
!
!
!
!
!
@end
!
@implementation MGAMapViewController
!
!
!
!
!
!
!
!
!
@end
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
!
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
!
!
!
!
- (void)privateMethod;
!
!
!
@end
!
@implementation MGAMapViewController
!
!
!
!
- (void)privateMethod
{
}
!
@end
Class Extensions
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
!
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
!
!
!
!
!
!
!
!
@end
!
@implementation MGAMapViewController
!
!
!
!
!
!
!
!
!
@end
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
!
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
!
!
!
!
- (void)privateMethod;
!
!
!
@end
!
@implementation MGAMapViewController
!
!
!
!
- (void)privateMethod
{
}
!
@end
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
!
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
{
NSString *privateString;
}
!
- (void)privateMethod;
!
!
!
@end
!
@implementation MGAMapViewController
!
!
!
!
- (void)privateMethod
{
privateString = @"hello";
}
!
@end
Class Extensions
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
!
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
!
!
!
!
!
!
!
!
@end
!
@implementation MGAMapViewController
!
!
!
!
!
!
!
!
!
@end
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
!
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
!
!
!
!
- (void)privateMethod;
!
!
!
@end
!
@implementation MGAMapViewController
!
!
!
!
- (void)privateMethod
{
}
!
@end
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
!
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
{
NSString *privateString;
}
!
- (void)privateMethod;
!
!
!
@end
!
@implementation MGAMapViewController
!
!
!
!
- (void)privateMethod
{
privateString = @"hello";
}
!
@end
Class Extensions
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
@property (nonatomic, readonly) NSArray *points;
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
{
NSString *privateString;
}
!
- (void)privateMethod;
!
@property (nonatomic, strong, readwrite) NSArray *points;
!
@end
!
@implementation MGAMapViewController
!
!
!
!
- (void)privateMethod
{
privateString = @"hello";
}
!
@end
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
!
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
!
!
!
!
!
!
!
!
@end
!
@implementation MGAMapViewController
!
!
!
!
!
!
!
!
!
@end
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
!
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
!
!
!
!
- (void)privateMethod;
!
!
!
@end
!
@implementation MGAMapViewController
!
!
!
!
- (void)privateMethod
{
}
!
@end
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
!
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
{
NSString *privateString;
}
!
- (void)privateMethod;
!
!
!
@end
!
@implementation MGAMapViewController
!
!
!
!
- (void)privateMethod
{
privateString = @"hello";
}
!
@end
Class Extensions
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
@property (nonatomic, readonly) NSArray *points;
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
{
NSString *privateString;
}
!
- (void)privateMethod;
!
@property (nonatomic, strong, readwrite) NSArray *points;
!
@end
!
@implementation MGAMapViewController
!
!
!
!
- (void)privateMethod
{
privateString = @"hello";
}
!
@end
// MGAMapViewController.h
@interface MGAMapViewController : UIViewController
!
@property (nonatomic, readonly) NSArray *points;
!
@end
!
// MGAMapViewController.m
@interface MGAMapViewController ()
{
NSString *privateString;
}
!
- (void)privateMethod;
!
@property (nonatomic, strong, readwrite) NSArray *points;
!
@end
!
@implementation MGAMapViewController
{
NSInteger counter;
}
!
- (void)privateMethod
{
privateString = @"hello";
}
!
@end
Class Extensions
Class Extensions
‣ A class extension bears some similarity to a category,
but it can only be added to a class for which you have
the source code at compile time. The methods
declared by a class extension are implemented in the
@implementation block for the original class
Class Extensions
‣ A class extension bears some similarity to a category,
but it can only be added to a class for which you have
the source code at compile time. The methods
declared by a class extension are implemented in the
@implementation block for the original class
‣ By declaring the class extension inside the source code
file for the class implementation, the information stays
private to the class; the header files in theory should
only expose public interface for your classes
Class Extensions
Class Extensions
‣ It’s possible to use a class extension to add custom
instance variables. These are declared inside braces in
the class extension interface
Class Extensions
‣ It’s possible to use a class extension to add custom
instance variables. These are declared inside braces in
the class extension interface
‣ It’s also common, for example, to define a property as
readonly in the interface, but as readwrite in a class
extension declared above the implementation, in order
that the internal methods of the class can change the
property value directly
Class Extensions
‣ It’s possible to use a class extension to add custom
instance variables. These are declared inside braces in
the class extension interface
‣ It’s also common, for example, to define a property as
readonly in the interface, but as readwrite in a class
extension declared above the implementation, in order
that the internal methods of the class can change the
property value directly
‣ It’s also possible to declare an ivar in the
@implemetation block
Conventions
use prefixes on all classes
classes must be named uniquely in order to avoid name clashes
use prefixes on all classes
@interface Customer : NSObject
!
@property (nonatomic, readwrite, copy) NSString *name;
@property (nonatomic, readwrite, copy) NSString *address;
!
@end
!
!
!
!
@interface HomeViewController : UIViewController
!
@property (weak, nonatomic) IBOutlet UILabel *userLabel;
@property (weak, nonatomic) IBOutlet UILabel *logoLabel;
@property (strong, nonatomic) Customer *user;
!
@end
use prefixes on all classes
@interface Customer : NSObject
!
@property (nonatomic, readwrite, copy) NSString *name;
@property (nonatomic, readwrite, copy) NSString *address;
!
@end
!
!
!
!
@interface HomeViewController : UIViewController
!
@property (weak, nonatomic) IBOutlet UILabel *userLabel;
@property (weak, nonatomic) IBOutlet UILabel *logoLabel;
@property (strong, nonatomic) Customer *user;
!
@end
@interface MGACustomer : NSObject
!
@property (nonatomic, readwrite, copy) NSString *name;
@property (nonatomic, readwrite, copy) NSString *address;
!
@end
!
!
!
!
@interface MGAHomeViewController : UIViewController
!
@property (weak, nonatomic) IBOutlet UILabel *userLabel;
@property (weak, nonatomic) IBOutlet UILabel *logoLabel;
@property (strong, nonatomic) MAGCustomer *user;
!
@end
use prefixes on all classes
use prefixes on all classes
‣ Choose a prefix with at least 3 uppercase chars that are
significant for the project
use prefixes on all classes
‣ Choose a prefix with at least 3 uppercase chars that are
significant for the project
‣ Two-letter prefixes are reserved by Apple for use in
framework classes, so you must use 3 (or more)
use prefixes on all classes
‣ Choose a prefix with at least 3 uppercase chars that are
significant for the project
‣ Two-letter prefixes are reserved by Apple for use in
framework classes, so you must use 3 (or more)
‣ Objective-C classes must be named uniquely not only within
the code that you’re writing in a project, but also across any
frameworks or bundles you might be including. As an
example, you should avoid using generic class names like
ViewController or TextParser because it’s possible a
framework you include in your app may fail to follow
conventions and create classes with the same names.
use a prefix for method names in categories
in a category you should include a prefix on the method name to avoid clashes
prefix category methods
!
@interface NSString (MGAAdditions)
!
- (NSString *)reverse;
- (NSString *)sha256;
!
@end
prefix category methods
!
@interface NSString (MGAAdditions)
!
- (NSString *)reverse;
- (NSString *)sha256;
!
@end
!
@interface NSString (MGAAdditions)
!
- (NSString *)mga_reverse;
- (NSString *)mga_sha256;
!
@end
prefix category methods
prefix category methods
‣ If the name of a method declared in a category is the same as a
method in the original class, or a method in another category
on the same class (or even a superclass), the behavior is
undefined as to which method implementation is used at
runtime.
prefix category methods
‣ If the name of a method declared in a category is the same as a
method in the original class, or a method in another category
on the same class (or even a superclass), the behavior is
undefined as to which method implementation is used at
runtime.
‣ In order to avoid undefined behavior, it’s best practice to add a
prefix to method names in categories on framework classes, just
like you should add a prefix to the names of your own classes.
You might choose to use the same three letters you use for your
class prefixes, but lowercase to follow the usual convention for
method names, then an underscore, before the rest of the
method name
properly define BOOL property
for Boolean properties the getter method should start with is
properly define BOOL property
!
@interface MGAUser
!
@property (nonatomic, assign) BOOL authenticated;
!
@end
!
@interface MGAUser
!
@property (nonatomic, assign, getter = isAuthenticated) BOOL authenticated;
!
@end
use ~iphone and ~ipad
if you’re developing a universal app add tilde to xib name instead of underscore
!
!
~iphone and ~ipad
// MGAHomeViewController_iPhone.xib
// MGAHomeViewController_iPad.xib
!
@implementation MGAHomeViewController
!
- (id)init
{
NSString *nibName = @"MGAHomeViewController_iPhone";
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
nibName = @"MGAHomeViewController_iPad";
}
return [super initWithNibName:nibName bundle:nil];
}
!
@end
~iphone and ~ipad
// MGAHomeViewController_iPhone.xib
// MGAHomeViewController_iPad.xib
!
@implementation MGAHomeViewController
!
- (id)init
{
NSString *nibName = @"MGAHomeViewController_iPhone";
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
nibName = @"MGAHomeViewController_iPad";
}
return [super initWithNibName:nibName bundle:nil];
}
!
@end
please stop doing that!
~iphone and ~ipad
// MGAHomeViewController_iPhone.xib
// MGAHomeViewController_iPad.xib
!
@implementation MGAHomeViewController
!
- (id)init
{
NSString *nibName = @"MGAHomeViewController_iPhone";
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
nibName = @"MGAHomeViewController_iPad";
}
return [super initWithNibName:nibName bundle:nil];
}
!
@end
// MGAHomeViewController~iphone.xib
// MGAHomeViewController~ipad.xib
!
@implementation MGAHomeViewController
!
!
!
!
!
// no custom init required
!
!
!
!
!
!
!
@end
use ~iphone and ~ipad
use ~iphone and ~ipad
‣ Adding ~iphone and ~ipad to xib file name, the
runtime will automatically infer the correct xib to load
(e.g. MGAHomeViewController~iphone.xib and
MGAHomeViewController~ipad.xib)
use ~iphone and ~ipad
‣ Adding ~iphone and ~ipad to xib file name, the
runtime will automatically infer the correct xib to load
(e.g. MGAHomeViewController~iphone.xib and
MGAHomeViewController~ipad.xib)
‣ note, it’s case sensitive so iPhone and iPad, with a
capital P, do not work
organize #import statements
it’s a good practice grouping and commenting #import statements
organize #import statements
!
#import <CoreData/CoreData.h>
!
#import "MGAMapViewController.h"
#import “MGAPictureView.h"
#import “NSString+MGAAdditions.h”
!
#import “MGAUser.h"
!
#import <CoreLocation/CoreLocation.h>
#import “NSDate+MGAAdditions.h”
!
#import “MGAOrderCell.h"
#import “MGACustomer.h"
#import "UIImage+MGAAdditions.h"
!
#import “MGAHomeViewController.h"
#import <UIKit/UIKit.h>
!
#import “MGAUserCell.h"
organize #import statements
!
#import <CoreData/CoreData.h>
!
#import "MGAMapViewController.h"
#import “MGAPictureView.h"
#import “NSString+MGAAdditions.h”
!
#import “MGAUser.h"
!
#import <CoreLocation/CoreLocation.h>
#import “NSDate+MGAAdditions.h”
!
#import “MGAOrderCell.h"
#import “MGACustomer.h"
#import "UIImage+MGAAdditions.h"
!
#import “MGAHomeViewController.h"
#import <UIKit/UIKit.h>
!
#import “MGAUserCell.h"
!
// Frameworks
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#import <CoreLocation/CoreLocation.h>
!
// View Controllers
#import "MGAMapViewController.h"
#import “MGAHomeViewController.h”
!
// Views
#import “MGAPictureView.h”
!
// Cells
#import “MGAUserCell.h”
#import “MGAOrderCell.h”
!
// Models
#import “MGAUser.h"
#import “MGACustomer.h”
!
// Categories
#import “NSDate+MGAAdditions.h”
#import “UIImage+MGAAdditions.h"
#import “NSString+MGAAdditions.h”
organize #import statements
organize #import statements
‣ group #imports
organize #import statements
‣ group #imports
‣ comment the groups
organize #import statements
‣ group #imports
‣ comment the groups
‣ If your are pedantic you can sort #import by length :)
use #pragma mark
organize your code, visually
#pragma mark
#pragma mark - View
!
- (void)viewDidLoad
{
[super viewDidLoad];
…
}
!
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
…
}
!
#pragma mark - UIScrollViewDelegate
!
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
…
}
!
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
…
}
!
#pragma mark - Actions
!
- (IBAction)loginButtonTouched:(id)sender
{
}
#pragma mark
#pragma mark
#pragma mark
‣ Use #pragma mark in your @implementation to divide
code into logical sections
#pragma mark
‣ Use #pragma mark in your @implementation to divide
code into logical sections
‣ It is also a way to organize your methods in the
method list pop up view in Xcode
Coding
don’t #import in header file
most #import statements should only be written in .m files, not .h headers
don’t #import in header file
#import "MGAUser.h"
#import "MGANetworkManager.h"
!
@interface MGALoginViewController : UIViewController
!
@property (nonatomic, readonly) MGAUser *user;
@property (nonatomic, strong, readwrite) MGANetworkManager *network;
!
@end
!
!
!
!
// MGALoginViewController.m
!
@implementation MGALoginViewController
!
!
@end
don’t #import in header file
#import "MGAUser.h"
#import "MGANetworkManager.h"
!
@interface MGALoginViewController : UIViewController
!
@property (nonatomic, readonly) MGAUser *user;
@property (nonatomic, strong, readwrite) MGANetworkManager *network;
!
@end
!
!
!
!
// MGALoginViewController.m
!
@implementation MGALoginViewController
!
!
@end
@class MGAUser; // forward class declaration
@class MGANetworkManager; // forward class declaration
!
@interface MGALoginViewController : UIViewController
!
@property (nonatomic, readonly) MGAUser *user;
@property (nonatomic, strong, readwrite) MGANetworkManager *network;
!
@end
!
!
!
!
// MGALoginViewController.m
!
#import "MGAUser.h"
#import “MGANetworkManager.h"
!
@implementation MGALoginViewController
!
!
@end
don’t #import in header file
don’t #import in header file
‣ Rather than adding #import statements for each class,
it's good practice to use forward class declarations in
the header, and import them in the implementation
don’t #import in header file
‣ Rather than adding #import statements for each class,
it's good practice to use forward class declarations in
the header, and import them in the implementation
‣ It reduce compile times and cyclical references
don’t #import in header file
‣ Rather than adding #import statements for each class,
it's good practice to use forward class declarations in
the header, and import them in the implementation
‣ It reduce compile times and cyclical references
‣ The one real exception is when subclassing another
custom class, you'll need to #import its header.
use typedef to simplify Block syntax
If you need to define more than one block with the same signature, you might like to
define your own type for that signature
blocks with typedef
blocks with typedef
!
!
!
@interface MGACustomer
!
!
!
- (void)createOrder:(void(^)(MGAOrder *order))completion;
!
@end
blocks with typedef
!
!
!
@interface MGACustomer
!
!
!
- (void)createOrder:(void(^)(MGAOrder *order))completion;
!
@end
typedef void(^MGACustomerBlock)(MGAOrder *order);
!
!
@interface MGACustomer
!
!
!
- (void)createOrder:(void(^)(MGAOrder *order))completion;
!
@end
blocks with typedef
!
!
!
@interface MGACustomer
!
!
!
- (void)createOrder:(void(^)(MGAOrder *order))completion;
!
@end
typedef void(^MGACustomerBlock)(MGAOrder *order);
!
!
@interface MGACustomer
!
!
!
- (void)createOrder:(void(^)(MGAOrder *order))completion;
!
@end
typedef void(^MGACustomerBlock)(MGAOrder *order);
!
!
@interface MGACustomer
!
!
!
- (void)createOrder:(MGACustomerBlock)completion;
!
@end
blocks with typedef
!
!
!
@interface MGACustomer
!
!
!
- (void)createOrder:(void(^)(MGAOrder *order))completion;
!
@end
typedef void(^MGACustomerBlock)(MGAOrder *order);
!
!
@interface MGACustomer
!
!
!
- (void)createOrder:(void(^)(MGAOrder *order))completion;
!
@end
typedef void(^MGACustomerBlock)(MGAOrder *order);
!
!
@interface MGACustomer
!
!
!
- (void)createOrder:(MGACustomerBlock)completion;
!
@end
typedef void(^MGACustomerBlock)(MGAOrder *order);
!
!
@interface MGACustomer
!
@property (nonatomic, copy) MGACustomerBlock completionBlock;
!
- (void)createOrder:(MGACustomerBlock)completion;
!
@end
create types for blocks
create types for blocks
‣ types improve readability and clean up your method
definitions, life will be easier and It’s highly
recommend making use of them as much as possible
create types for blocks
‣ types improve readability and clean up your method
definitions, life will be easier and It’s highly
recommend making use of them as much as possible
‣ If you have to change the block signature, it is much
easier to change the typedef. The compiler, being a
nice fellow, will then tell you all the places the block
signature doesn’t match
how to access ivars
Oh my!
how to access ivars
!
- (instancetype)initWithUser:(MGAUser *)user
{
self = [super init];
if (self)
{
_user = user;
}
return self;
}
!
- (void)viewDidLoad
{
[super viewDidLoad];
[self.usernameLabel setText:self.user.name];
}
!
- (void)createNewUser
{
self.usernameLabel = [THMUser alloc] init];
}
how to access ivars
how to access ivars
‣ Direct access bypasses the property’s memory-
management semantics defined by the setter
how to access ivars
‣ Direct access bypasses the property’s memory-
management semantics defined by the setter
‣ KVO notifications would not be fired when accessing
the instance variables directly
how to access ivars
‣ Direct access bypasses the property’s memory-
management semantics defined by the setter
‣ KVO notifications would not be fired when accessing
the instance variables directly
‣ In init methods you should use direct instance variable
access, because subclasses could override the setter
how to access ivars
‣ Direct access bypasses the property’s memory-
management semantics defined by the setter
‣ KVO notifications would not be fired when accessing
the instance variables directly
‣ In init methods you should use direct instance variable
access, because subclasses could override the setter
‣ On the other part of class read/write data through
properties
always declare atomic/nonatomic
Properties are declared as atomic by default
declare atomic/nonatomic
#import <UIKit/UIKit.h>
!
@interface MGAMapViewController : UIViewController
!
@property (readonly) CERUser *user;
@property (copy) NSArray *locations;
@property (weak) IBOutlet UITableView *tableView;
!
@end
declare atomic/nonatomic
#import <UIKit/UIKit.h>
!
@interface MGAMapViewController : UIViewController
!
@property (readonly) CERUser *user;
@property (copy) NSArray *locations;
@property (weak) IBOutlet UITableView *tableView;
!
@end
#import <UIKit/UIKit.h>
!
@interface MGAMapViewController : UIViewController
!
@property (nonatomic, readonly) CERUser *user;
@property (nonatomic, copy) NSArray *locations;
@property (nonatomic, weak) IBOutlet UITableView *tableView;
!
@end
declare atomic/nonatomic
#import <UIKit/UIKit.h>
!
@interface MGAMapViewController : UIViewController
!
@property (readonly) CERUser *user;
@property (copy) NSArray *locations;
@property (weak) IBOutlet UITableView *tableView;
!
@end
#import <UIKit/UIKit.h>
!
@interface MGAMapViewController : UIViewController
!
@property (nonatomic, readonly) CERUser *user;
@property (nonatomic, copy) NSArray *locations;
@property (nonatomic, weak) IBOutlet UITableView *tableView;
!
@end
#import <UIKit/UIKit.h>
!
@interface MGAMapViewController : UIViewController
!
@property (nonatomic, readonly) CERUser *user;
@property (nonatomic, readwrite, copy) NSArray *locations;
@property (nonatomic, readwrite, weak) IBOutlet UITableView *tableView;
!
@end
declare atomic/nonatomic
declare atomic/nonatomic
‣ By default, synthesized accessors include locking to
make them atomic
declare atomic/nonatomic
‣ By default, synthesized accessors include locking to
make them atomic
‣ If you not need locking on property use nonatomic on
iOS, since performance is severely impacted if atomic
is used
use read-only properties
read-only properties are great for exposing information, you should use them often
read-only properties
!
@interface MGAMapViewController : UIViewController
!
@property (nonatomic, readonly) MGAUser *user;
@property (nonatomic, readonly) NSArray *locations;
!
@end
read-only properties
!
@interface MGAMapViewController : UIViewController
!
@property (nonatomic, readonly) MGAUser *user;
@property (nonatomic, readonly) NSArray *locations;
!
@end
!
@interface MGAMapViewController : UIViewController
!
@property (nonatomic, readonly) MGAUser *user;
@property (nonatomic, readonly) NSArray *locations;
!
@end
!
!
!
!
!
!
!
!
!
!
@implementation MGAMapViewController
!
- (instancetype)initWithUser:(MGaUser *)user
{
self = [super init];
if (self) {
_user = user;
}
return self;
}
!
@end
read-only properties
!
@interface MGAMapViewController : UIViewController
!
@property (nonatomic, readonly) MGAUser *user;
@property (nonatomic, readonly) NSArray *locations;
!
@end
!
@interface MGAMapViewController : UIViewController
!
@property (nonatomic, readonly) MGAUser *user;
@property (nonatomic, readonly) NSArray *locations;
!
@end
!
!
!
!
!
!
!
!
!
!
@implementation MGAMapViewController
!
- (instancetype)initWithUser:(MGaUser *)user
{
self = [super init];
if (self) {
_user = user;
}
return self;
}
!
@end
!
@interface MGAMapViewController : UIViewController
!
@property (nonatomic, readonly) MGAUser *user;
@property (nonatomic, readonly) NSArray *locations;
!
@end
!
!
@interface MGAMapViewController ()
!
@property (nonatomic, strong, readwrite) MGAUser *user;
@property (nonatomic, strong, readwrite) NSArray *locations;
!
@end
!
!
@implementation MGAMapViewController
!
- (instancetype)initWithUser:(MGAUser *)user
{
self = [super init];
if (self) {
_user = user;
}
return self;
}
!
@end
use read-only properties
use read-only properties
‣ expose object data with read-only properties, unless
you really need to allow access to internal data
through a public setter
use read-only properties
‣ expose object data with read-only properties, unless
you really need to allow access to internal data
through a public setter
‣ for read-only properties, you should defined a public
getter but a private setter in class extension
use weak to avoid retain cycles
a wrong memory management involves in memory leaks
retain cycle
retain cycle
Object BObject A
retain cycle
Object B
@property (strong)
Object A
retain cycle
Object B
@property (strong)
@property (strong)
Object A
retain cycle
Object B
@property (strong)
@property (strong)
Object A
retain cycle
Object B
@property (strong)
@property (strong)
Object A
retain cycle
Object B
@property (strong)
Object A
@property (weak)
use __weak typeof
a wrong memory management involves in memory leaks
use __weak typeof
use __weak typeof
- (void)viewDidLoad
{
[super viewDidLoad];
self.manager = [[MGANetworkManager alloc] init];
!
!
!
[self.manager getUsers:^(NSArray *users, NSError *error)
{
if (!error)
{
self.users = elements;
[self.usersTableView reloadData];
}
}];
}
use __weak typeof
- (void)viewDidLoad
{
[super viewDidLoad];
self.manager = [[MGANetworkManager alloc] init];
!
!
!
[self.manager getUsers:^(NSArray *users, NSError *error)
{
if (!error)
{
self.users = elements;
[self.usersTableView reloadData];
}
}];
}
use __weak typeof
- (void)viewDidLoad
{
[super viewDidLoad];
self.manager = [[MGANetworkManager alloc] init];
!
!
!
[self.manager getUsers:^(NSArray *users, NSError *error)
{
if (!error)
{
self.users = elements;
[self.usersTableView reloadData];
}
}];
}
use __weak typeof
- (void)viewDidLoad
{
[super viewDidLoad];
self.manager = [[MGANetworkManager alloc] init];
!
!
!
[self.manager getUsers:^(NSArray *users, NSError *error)
{
if (!error)
{
self.users = elements;
[self.usersTableView reloadData];
}
}];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.manager = [[MGANetworkManager alloc] init];
!
__weak THMReportsViewController weakSelf = self;
!
[weakSelf.manager getUsers:^(NSArray *users, NSError *error)
{
if (!error)
{
weakSelf.users = elements;
[weakSelf.usersTableView reloadData];
}
}];
}
use __weak typeof
- (void)viewDidLoad
{
[super viewDidLoad];
self.manager = [[MGANetworkManager alloc] init];
!
!
!
[self.manager getUsers:^(NSArray *users, NSError *error)
{
if (!error)
{
self.users = elements;
[self.usersTableView reloadData];
}
}];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.manager = [[MGANetworkManager alloc] init];
!
__weak THMReportsViewController weakSelf = self;
!
[weakSelf.manager getUsers:^(NSArray *users, NSError *error)
{
if (!error)
{
weakSelf.users = elements;
[weakSelf.usersTableView reloadData];
}
}];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.manager = [[MGANetworkManager alloc] init];
!
__weak typeof(self) weakSelf = self;
!
[weakSelf.manager getUsers:^(NSArray *users, NSError *error)
{
if (!error)
{
weakSelf.users = elements;
[weakSelf.usersTableView reloadData];
}
}];
}
Manage third-part libraries with CocoaPods
it’s an application level dependency manager for the Objective-C projects
Cocoapods
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Using FormatterKit (1.4.2)
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Using FormatterKit (1.4.2)
Using ISO8601DateFormatterValueTransformer (0.5.0)
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Using FormatterKit (1.4.2)
Using ISO8601DateFormatterValueTransformer (0.5.0)
Using RHAddressBook (1.1.1)
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Using FormatterKit (1.4.2)
Using ISO8601DateFormatterValueTransformer (0.5.0)
Using RHAddressBook (1.1.1)
Using RKValueTransformers (1.0.1)
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Using FormatterKit (1.4.2)
Using ISO8601DateFormatterValueTransformer (0.5.0)
Using RHAddressBook (1.1.1)
Using RKValueTransformers (1.0.1)
Using RestKit (0.22.0)
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Using FormatterKit (1.4.2)
Using ISO8601DateFormatterValueTransformer (0.5.0)
Using RHAddressBook (1.1.1)
Using RKValueTransformers (1.0.1)
Using RestKit (0.22.0)
Using SDWebImage (3.5.4)
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Using FormatterKit (1.4.2)
Using ISO8601DateFormatterValueTransformer (0.5.0)
Using RHAddressBook (1.1.1)
Using RKValueTransformers (1.0.1)
Using RestKit (0.22.0)
Using SDWebImage (3.5.4)
Using SDWebImage-ProgressView (0.3.1)
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Using FormatterKit (1.4.2)
Using ISO8601DateFormatterValueTransformer (0.5.0)
Using RHAddressBook (1.1.1)
Using RKValueTransformers (1.0.1)
Using RestKit (0.22.0)
Using SDWebImage (3.5.4)
Using SDWebImage-ProgressView (0.3.1)
Using SOCKit (1.1)
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Using FormatterKit (1.4.2)
Using ISO8601DateFormatterValueTransformer (0.5.0)
Using RHAddressBook (1.1.1)
Using RKValueTransformers (1.0.1)
Using RestKit (0.22.0)
Using SDWebImage (3.5.4)
Using SDWebImage-ProgressView (0.3.1)
Using SOCKit (1.1)
Using TransitionKit (2.0.0)
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Using FormatterKit (1.4.2)
Using ISO8601DateFormatterValueTransformer (0.5.0)
Using RHAddressBook (1.1.1)
Using RKValueTransformers (1.0.1)
Using RestKit (0.22.0)
Using SDWebImage (3.5.4)
Using SDWebImage-ProgressView (0.3.1)
Using SOCKit (1.1)
Using TransitionKit (2.0.0)
Generating Pods project
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Using FormatterKit (1.4.2)
Using ISO8601DateFormatterValueTransformer (0.5.0)
Using RHAddressBook (1.1.1)
Using RKValueTransformers (1.0.1)
Using RestKit (0.22.0)
Using SDWebImage (3.5.4)
Using SDWebImage-ProgressView (0.3.1)
Using SOCKit (1.1)
Using TransitionKit (2.0.0)
Generating Pods project
Integrating client project
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Using FormatterKit (1.4.2)
Using ISO8601DateFormatterValueTransformer (0.5.0)
Using RHAddressBook (1.1.1)
Using RKValueTransformers (1.0.1)
Using RestKit (0.22.0)
Using SDWebImage (3.5.4)
Using SDWebImage-ProgressView (0.3.1)
Using SOCKit (1.1)
Using TransitionKit (2.0.0)
Generating Pods project
Integrating client project
Cocoapods
$ sudo gem install cocoapods
$ cd MyGreatApp
$ pod init
$ edit Podfile
platform :ios, '6.1'
pod 'RestKit', '~> 0.22.0'
pod 'FXKeychain', '~> 1.5'
pod 'SDWebImage', '~> 3.5.2'
pod 'SDWebImage-ProgressView', '~> 0.3.0'
pod 'RHAddressBook', '~> 1.1.1'
pod 'FormatterKit', '~> 1.4.2'
$ pod install
Analyzing dependencies
Downloading dependencies
Using AFNetworking (1.3.3)
Using FXKeychain (1.5)
Using FormatterKit (1.4.2)
Using ISO8601DateFormatterValueTransformer (0.5.0)
Using RHAddressBook (1.1.1)
Using RKValueTransformers (1.0.1)
Using RestKit (0.22.0)
Using SDWebImage (3.5.4)
Using SDWebImage-ProgressView (0.3.1)
Using SOCKit (1.1)
Using TransitionKit (2.0.0)
Generating Pods project
Integrating client project
$
Cocoapods
Cocoapods
‣ CocoaPods manage dependency for you, it download
source files, imports headers and configures flags
Cocoapods
‣ CocoaPods manage dependency for you, it download
source files, imports headers and configures flags
‣ CocoaPods is strongly inspired by a combination of
the Ruby projects RubyGems and Bundler
Cocoapods
‣ CocoaPods manage dependency for you, it download
source files, imports headers and configures flags
‣ CocoaPods is strongly inspired by a combination of
the Ruby projects RubyGems and Bundler
‣ CocoaPods focuses on source-based distribution of
third party code and automatic integration into Xcode
projects
Cocoapods
‣ CocoaPods manage dependency for you, it download
source files, imports headers and configures flags
‣ CocoaPods is strongly inspired by a combination of
the Ruby projects RubyGems and Bundler
‣ CocoaPods focuses on source-based distribution of
third party code and automatic integration into Xcode
projects
‣ CocoaPods runs from the command line
Framework
Key-Value Coding
dynamically set and get properties and object graph
Key-Value Coding
MGACustomer *c1 = [[MGACustomer alloc] initWithName:@“ACME Inc.”];
c1.address = [[MGAAddress alloc] initWithZip:@“33568”];
!
!
[c1 valueForKey:@"name"]; // ACME Inc.
[c1 valueForKeyPath:@“address.zip"]; // 33568
Key-Value Coding
MGACustomer *c1 = [[MGACustomer alloc] initWithName:@“ACME Inc.”];
c1.address = [[MGAAddress alloc] initWithZip:@“33568”];
!
!
[c1 valueForKey:@"name"]; // ACME Inc.
[c1 valueForKeyPath:@“address.zip"]; // 33568
NSArray *names = @[ @"Steve", @"Bill", @"Ive" ];
!
// you can “get the value” of any method with no parameter
[names valueForKey:@"uppercaseString"]; // @[ @“STEVE”, @“BILL”, @“IVE”]
[names valueForKey:@"lowercaseString"]; // @[ @“steve”, @“bill”, @“ive”]
!
!
// It’s really any method.
// For example, -[NSObject self] is a method like any other.
[@"Steve" valueForKey:@“self"]; // @“Steve”
!
!
// KVC automatically boxes and unboxes values
[names valueForKey:@"length"]; // @[ @5, @4, @3 ]
Key-Value Coding
Key-Value Coding
‣ Key-value coding is a mechanism for accessing an
object’s properties indirectly, using strings to identify
properties
Key-Value Coding
‣ Key-value coding is a mechanism for accessing an
object’s properties indirectly, using strings to identify
properties
‣ You can get the value of any method with no
parameter
Key-Value Coding
‣ Key-value coding is a mechanism for accessing an
object’s properties indirectly, using strings to identify
properties
‣ You can get the value of any method with no
parameter
‣ Key-Value Coding automatically boxes and unboxes
values into their object representation.
discover KVC Collection Operators
save a few extra lines of code
KVC Collection Operators
KVC Collection Operators
MGAPerson *p1 = [[MGAPerson alloc] initWithName:@"Max" age:34];
MGAPerson *p2 = [[MGAPerson alloc] initWithName:@"Steve" age:54];
MGAPerson *p3 = [[MGAPerson alloc] initWithName:@"Bill" age:62];
NSArray *people = @[ p1, p2, p3 ];
// Simple Collection Operators
[people valueForKeyPath:@"@count"]; // 3
[people valueForKeyPath:@"@sum.age"]; // 150.00
[people valueForKeyPath:@"@avg.age"]; // 50.00
[people valueForKeyPath:@"@max.age"]; // 63.00
// Objects Operators
[people valueForKeyPath:@"@unionOfObjects.name"]; // "Max", "Steve", “Bill"
// Simple Collection Operators with NSNumber
NSArray *numbers = @[ @(1), @(2), @(3) ];
[numbers valueForKeyPath:@"@max.self"]; // 3
KVC Collection Operators
KVC Collection Operators
‣ Collection operators allow actions to be performed on
the items of a collection using key path notation and
an action operator
KVC Collection Operators
‣ Collection operators allow actions to be performed on
the items of a collection using key path notation and
an action operator
‣ Collection operators are specialized key paths that are
passed as the parameter to the valueForKeyPath:
method
KVC Collection Operators
‣ Collection operators allow actions to be performed on
the items of a collection using key path notation and
an action operator
‣ Collection operators are specialized key paths that are
passed as the parameter to the valueForKeyPath:
method
‣ The operator is specified by a string preceded by an at
sign (@)
discover NSBlockOperation class
NSBlockOperation
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
{
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
{
for (NSInteger i = 0; i < 10000; i++)
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
{
for (NSInteger i = 0; i < 10000; i++)
{
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
{
for (NSInteger i = 0; i < 10000; i++)
{
if ([weakOp isCancelled])
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
{
for (NSInteger i = 0; i < 10000; i++)
{
if ([weakOp isCancelled])
{
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
{
for (NSInteger i = 0; i < 10000; i++)
{
if ([weakOp isCancelled])
{
break;
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
{
for (NSInteger i = 0; i < 10000; i++)
{
if ([weakOp isCancelled])
{
break;
}
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
{
for (NSInteger i = 0; i < 10000; i++)
{
if ([weakOp isCancelled])
{
break;
}
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
{
for (NSInteger i = 0; i < 10000; i++)
{
if ([weakOp isCancelled])
{
break;
}
NSLog(@"%i", i);
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
{
for (NSInteger i = 0; i < 10000; i++)
{
if ([weakOp isCancelled])
{
break;
}
NSLog(@"%i", i);
}
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
{
for (NSInteger i = 0; i < 10000; i++)
{
if ([weakOp isCancelled])
{
break;
}
NSLog(@"%i", i);
}
}];
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
{
for (NSInteger i = 0; i < 10000; i++)
{
if ([weakOp isCancelled])
{
break;
}
NSLog(@"%i", i);
}
}];
NSBlockOperation
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak typeof(blockOp) weakOp = blockOp;
[blockOp addExecutionBlock:^
{
for (NSInteger i = 0; i < 10000; i++)
{
if ([weakOp isCancelled])
{
break;
}
NSLog(@"%i", i);
}
}];
[blockOp start];
NSBlockOperation
NSBlockOperation
‣ NSBlockOperation is a concrete subclass that wraps
block in operations
NSBlockOperation
‣ NSBlockOperation is a concrete subclass that wraps
block in operations
‣ You can use this object to execute several blocks at
once without having to create separate operation
objects for each
NSBlockOperation
‣ NSBlockOperation is a concrete subclass that wraps
block in operations
‣ You can use this object to execute several blocks at
once without having to create separate operation
objects for each
‣ When executing more than one block, the operation
itself is considered finished only when all blocks have
finished executing
NSError
it encapsulates richer and more extensible error information
Create an NSError
Create an NSError
NSString * const kMGAErrorDomain = @“com.acmeinc.MyGreatApp”;
typedef NS_ENUM(NSInteger, MGAErrorCode)
{
MGAErrorCodeUnableToLocateUser = 500,
MGAErrorCodeInvalidUser = 401
};
NSDictionary *userInfo =
@{
NSLocalizedDescriptionKey:
NSLocalizedString(@“Location error”, nil),
NSLocalizedFailureReasonErrorKey :
NSLocalizedString(@"The location service is not active.", nil),
NSLocalizedRecoverySuggestionErrorKey :
NSLocalizedString(@"Please turn on the location service and try again", nil)
};
NSError *error = [NSError errorWithDomain:kMGAErrorDomain
code:MGAErrorCodeUnableToLocateUser
userInfo:userInfo];
Handle NSError
Handle NSError
- (void)handleError:(NSError *)error
{
if (error)
{
NSString *errorMessage;
errorMessage = [NSString stringWithFormat:@"%@n%@",
error.localizedFailureReason,
error.localizedRecoverySuggestion];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:error.localizedDescription
message:errorMessage
delegate:nil
cancelButtonTitle:NSLocalizedString(@"OK", nil)
otherButtonTitles:nil, nil];
[alert show];
}
}
Consuming NSError
Consuming NSError
- (void)doLogin
{
NSString *user = self.usernameTextField.text;
NSString *pass = self.passwordTextField.text;
__weak typeof(self) weakSelf = self;
[self.service loginWithUser:user pass:pass completion:^(TMGAUser *user, NSError *error)
{
[weakSelf handleError:error];
if (!error)
{
[weakSelf navigateToHome];
}
}];
}
NSError
NSError
‣ An NSError object encapsulates richer and more
extensible error information than is possible using
only an error code or error string
NSError
‣ An NSError object encapsulates richer and more
extensible error information than is possible using
only an error code or error string
‣ The core attributes of an NSError object are an error
domain, a domain-specific error code and a user info
dictionary containing application specific information.
NSError
‣ An NSError object encapsulates richer and more
extensible error information than is possible using
only an error code or error string
‣ The core attributes of an NSError object are an error
domain, a domain-specific error code and a user info
dictionary containing application specific information.
‣ Domain-specific error codes are generally defined by
constants in an enum.
use NSCache
It’s a collection-like container, or cache, that stores key-value pairs, similar to the
NSMutableDictionary class.
NSCache
NSCache
NSCache *cache = [[NSCache alloc] init];
!
!
// Sets the maximum number of objects that the cache can hold.
!
// This limit is not a strict limit, and if the cache goes over the limit,
// an object in the cache could be evicted instantly, later, or possibly never,
// all depending on the implementation details of the cache.
[cache setCountLimit:50];
!
!
// Sets the maximum total cost that the cache can have before it starts evicting objects
!
// If adding this object to the cache causes the cache’s total cost to rise above
// totalCostLimit, the cache could automatically evict some of its objects until its
// total cost falls below totalCostLimit. The order in which the cache evicts objects is
// not guaranteed. This limit is not a strict limit, and if the cache goes over the
// limit, an object in the cache could be evicted instantly, at a later point in time,
// or possibly never, all depending on the implementation details of the cache.
[cache setTotalCostLimit:5000];
!
!
// Add object to cache with cost
[cache setObject:customer1 forKey:@"c1" cost:10];
!
!
// Add object to cache without cost
[cache setObject:customer2 forKey:@"c2"];
NSCache
NSCache
‣ NSCache is basically just an NSMutableDictionary that
automatically evicts objects in order to free up space
in memory as needed
NSCache
‣ NSCache is basically just an NSMutableDictionary that
automatically evicts objects in order to free up space
in memory as needed
‣ The NSCache class incorporates various auto-removal
policies, which ensure that it does not use too much of
the system’s memory. The system automatically carries
out these policies if memory is needed by other
applications. When invoked, these policies remove
some items from the cache, minimizing its memory
footprint.
NSCache
NSCache
‣ It is guaranteed to be thread-safe.
NSCache
‣ It is guaranteed to be thread-safe.
‣ It is much slower to access.
NSCache
‣ It is guaranteed to be thread-safe.
‣ It is much slower to access.
‣ It may throw out objects from time to time. You can set
costs and limits, but they're not guaranteed to be followed.
NSCache
‣ It is guaranteed to be thread-safe.
‣ It is much slower to access.
‣ It may throw out objects from time to time. You can set
costs and limits, but they're not guaranteed to be followed.
‣ It is not toll-free bridged to anything in CoreFoundation.
NSCache
‣ It is guaranteed to be thread-safe.
‣ It is much slower to access.
‣ It may throw out objects from time to time. You can set
costs and limits, but they're not guaranteed to be followed.
‣ It is not toll-free bridged to anything in CoreFoundation.
‣ You can't query the number of objects that are in the
cache.
NSCache
‣ It is guaranteed to be thread-safe.
‣ It is much slower to access.
‣ It may throw out objects from time to time. You can set
costs and limits, but they're not guaranteed to be followed.
‣ It is not toll-free bridged to anything in CoreFoundation.
‣ You can't query the number of objects that are in the
cache.
‣ You can't enumerate a cache.
NSValue
NSValue is a simple container for a single C or Objective-C data value
NSValue
NSValue
NSMutableArray *items = [@[] mutableCopy];
[items addObject:[NSValue valueWithCGSize:CGSizeMake(200.0f, 300.0f)]];
NSValue *sizeValue = items[0];
CGSize size = [sizeValue CGSizeValue];
// define new struct
typedef struct MGAColor
{
float red, blue, green;
}
MGAColor;
MGAColor color = { 255.0, 0.0f, 34.0 };
[items addObject:[NSValue valueWithBytes:&color objCType:@encode(MGAColor)]];
NSValue
NSMutableArray *items = [@[] mutableCopy];
[items addObject:[NSValue valueWithCGSize:CGSizeMake(200.0f, 300.0f)]];
NSValue *sizeValue = items[0];
CGSize size = [sizeValue CGSizeValue];
// define new struct
typedef struct MGAColor
{
float red, blue, green;
}
MGAColor;
MGAColor color = { 255.0, 0.0f, 34.0 };
[items addObject:[NSValue valueWithBytes:&color objCType:@encode(MGAColor)]];
MGAUser *user = [[MGAUser alloc] init]; // it not conforms to <NSCopying>
NSMutableDictionary *items = [@{} mutableCopy];
// e.g. I want to store num of login attempts of a user
// because my custom class MGAUser does not conform to <NSCopying>
// I can’t use it as key value. The workaround is to box user instance
// into NSValue object with valueWithNonretainedObject:
[items setObject:numLogin forKey:[NSValue valueWithNonretainedObject:user]];
NSValue
NSValue
‣ It can hold scalars and value types, as well as pointers
and object IDs.
NSValue
‣ It can hold scalars and value types, as well as pointers
and object IDs.
‣ NSValue uses type encoding to create the necessary
data structures to represent values internally
NSValue
‣ It can hold scalars and value types, as well as pointers
and object IDs.
‣ NSValue uses type encoding to create the necessary
data structures to represent values internally
‣ valueWithNonretainedObject: allows objects to be
added to a collection, without the need for satisfying
<NSCopying> protocol
Thanks!
Massimo Oliviero
@maxoly

More Related Content

What's hot

ECMAScript 6: A Better JavaScript for the Ambient Computing Era
ECMAScript 6: A Better JavaScript for the Ambient Computing EraECMAScript 6: A Better JavaScript for the Ambient Computing Era
ECMAScript 6: A Better JavaScript for the Ambient Computing EraAllen Wirfs-Brock
 
JS Level Up: Prototypes
JS Level Up: PrototypesJS Level Up: Prototypes
JS Level Up: PrototypesVernon Kesner
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesAnkit Rastogi
 
Objective-C for Java Developers
Objective-C for Java DevelopersObjective-C for Java Developers
Objective-C for Java DevelopersBob McCune
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Domenic Denicola
 
Introduction to Underscore.js
Introduction to Underscore.jsIntroduction to Underscore.js
Introduction to Underscore.jsDavid Jacobs
 
GDG Almaty Meetup: Reactive full-stack .NET web applications with WebSharper
GDG Almaty Meetup: Reactive full-stack .NET web applications with WebSharperGDG Almaty Meetup: Reactive full-stack .NET web applications with WebSharper
GDG Almaty Meetup: Reactive full-stack .NET web applications with WebSharpergranicz
 
Introduction to Ecmascript - ES6
Introduction to Ecmascript - ES6Introduction to Ecmascript - ES6
Introduction to Ecmascript - ES6Nilesh Jayanandana
 
Maintainable JavaScript 2012
Maintainable JavaScript 2012Maintainable JavaScript 2012
Maintainable JavaScript 2012Nicholas Zakas
 
JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6Solution4Future
 
ES2015 (ES6) Overview
ES2015 (ES6) OverviewES2015 (ES6) Overview
ES2015 (ES6) Overviewhesher
 
Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPJeremy Kendall
 
Powerful JavaScript Tips and Best Practices
Powerful JavaScript Tips and Best PracticesPowerful JavaScript Tips and Best Practices
Powerful JavaScript Tips and Best PracticesDragos Ionita
 
Php 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodPhp 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodJeremy Kendall
 

What's hot (20)

ECMAScript 6: A Better JavaScript for the Ambient Computing Era
ECMAScript 6: A Better JavaScript for the Ambient Computing EraECMAScript 6: A Better JavaScript for the Ambient Computing Era
ECMAScript 6: A Better JavaScript for the Ambient Computing Era
 
JS Level Up: Prototypes
JS Level Up: PrototypesJS Level Up: Prototypes
JS Level Up: Prototypes
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practices
 
Underscore.js
Underscore.jsUnderscore.js
Underscore.js
 
Objective-C for Java Developers
Objective-C for Java DevelopersObjective-C for Java Developers
Objective-C for Java Developers
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
 
Introduction to Underscore.js
Introduction to Underscore.jsIntroduction to Underscore.js
Introduction to Underscore.js
 
Effective ES6
Effective ES6Effective ES6
Effective ES6
 
Underscore
UnderscoreUnderscore
Underscore
 
Introduction to Underscore.js
Introduction to Underscore.jsIntroduction to Underscore.js
Introduction to Underscore.js
 
GDG Almaty Meetup: Reactive full-stack .NET web applications with WebSharper
GDG Almaty Meetup: Reactive full-stack .NET web applications with WebSharperGDG Almaty Meetup: Reactive full-stack .NET web applications with WebSharper
GDG Almaty Meetup: Reactive full-stack .NET web applications with WebSharper
 
Introduction to Ecmascript - ES6
Introduction to Ecmascript - ES6Introduction to Ecmascript - ES6
Introduction to Ecmascript - ES6
 
Es.next
Es.nextEs.next
Es.next
 
Maintainable JavaScript 2012
Maintainable JavaScript 2012Maintainable JavaScript 2012
Maintainable JavaScript 2012
 
JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6
 
Modern JS with ES6
Modern JS with ES6Modern JS with ES6
Modern JS with ES6
 
ES2015 (ES6) Overview
ES2015 (ES6) OverviewES2015 (ES6) Overview
ES2015 (ES6) Overview
 
Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHP
 
Powerful JavaScript Tips and Best Practices
Powerful JavaScript Tips and Best PracticesPowerful JavaScript Tips and Best Practices
Powerful JavaScript Tips and Best Practices
 
Php 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodPhp 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the Good
 

Viewers also liked

Android chat in the cloud: restful apis, authentication, push notifications a...
Android chat in the cloud: restful apis, authentication, push notifications a...Android chat in the cloud: restful apis, authentication, push notifications a...
Android chat in the cloud: restful apis, authentication, push notifications a...Codemotion
 
From gamification to game design
From gamification to game designFrom gamification to game design
From gamification to game designCodemotion
 
The Big “Why equal doesn’t equal” Quiz
The Big “Why equal doesn’t equal” QuizThe Big “Why equal doesn’t equal” Quiz
The Big “Why equal doesn’t equal” QuizCodemotion
 
Behaviour Driven Development - Tutta questione di comunicazione
Behaviour Driven Development - Tutta questione di comunicazioneBehaviour Driven Development - Tutta questione di comunicazione
Behaviour Driven Development - Tutta questione di comunicazioneCodemotion
 
Pragmatic Functional Refactoring with Java 8
Pragmatic Functional Refactoring with Java 8Pragmatic Functional Refactoring with Java 8
Pragmatic Functional Refactoring with Java 8Codemotion
 
Next Generation Media - Wolter
Next Generation Media - WolterNext Generation Media - Wolter
Next Generation Media - WolterCodemotion
 
Make sense of your big data - Pilato
Make sense of your big data - PilatoMake sense of your big data - Pilato
Make sense of your big data - PilatoCodemotion
 

Viewers also liked (7)

Android chat in the cloud: restful apis, authentication, push notifications a...
Android chat in the cloud: restful apis, authentication, push notifications a...Android chat in the cloud: restful apis, authentication, push notifications a...
Android chat in the cloud: restful apis, authentication, push notifications a...
 
From gamification to game design
From gamification to game designFrom gamification to game design
From gamification to game design
 
The Big “Why equal doesn’t equal” Quiz
The Big “Why equal doesn’t equal” QuizThe Big “Why equal doesn’t equal” Quiz
The Big “Why equal doesn’t equal” Quiz
 
Behaviour Driven Development - Tutta questione di comunicazione
Behaviour Driven Development - Tutta questione di comunicazioneBehaviour Driven Development - Tutta questione di comunicazione
Behaviour Driven Development - Tutta questione di comunicazione
 
Pragmatic Functional Refactoring with Java 8
Pragmatic Functional Refactoring with Java 8Pragmatic Functional Refactoring with Java 8
Pragmatic Functional Refactoring with Java 8
 
Next Generation Media - Wolter
Next Generation Media - WolterNext Generation Media - Wolter
Next Generation Media - Wolter
 
Make sense of your big data - Pilato
Make sense of your big data - PilatoMake sense of your big data - Pilato
Make sense of your big data - Pilato
 

Similar to Modernizes your objective C - Oliviero

Objective-C Crash Course for Web Developers
Objective-C Crash Course for Web DevelopersObjective-C Crash Course for Web Developers
Objective-C Crash Course for Web DevelopersJoris Verbogt
 
Avro, la puissance du binaire, la souplesse du JSON
Avro, la puissance du binaire, la souplesse du JSONAvro, la puissance du binaire, la souplesse du JSON
Avro, la puissance du binaire, la souplesse du JSONAlexandre Victoor
 
Taking Objective-C to the next level. UA Mobile 2016.
Taking Objective-C to the next level. UA Mobile 2016.Taking Objective-C to the next level. UA Mobile 2016.
Taking Objective-C to the next level. UA Mobile 2016.UA Mobile
 
Irving iOS Jumpstart Meetup - Objective-C Session 2
Irving iOS Jumpstart Meetup - Objective-C Session 2Irving iOS Jumpstart Meetup - Objective-C Session 2
Irving iOS Jumpstart Meetup - Objective-C Session 2irving-ios-jumpstart
 
FI MUNI 2012 - iOS Basics
FI MUNI 2012 - iOS BasicsFI MUNI 2012 - iOS Basics
FI MUNI 2012 - iOS BasicsPetr Dvorak
 
MFF UK - Introduction to iOS
MFF UK - Introduction to iOSMFF UK - Introduction to iOS
MFF UK - Introduction to iOSPetr Dvorak
 
Crafting Evolvable Api Responses
Crafting Evolvable Api ResponsesCrafting Evolvable Api Responses
Crafting Evolvable Api Responsesdarrelmiller71
 
iPhone Development Intro
iPhone Development IntroiPhone Development Intro
iPhone Development IntroLuis Azevedo
 
Don't Be Afraid of Abstract Syntax Trees
Don't Be Afraid of Abstract Syntax TreesDon't Be Afraid of Abstract Syntax Trees
Don't Be Afraid of Abstract Syntax TreesJamund Ferguson
 
"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)
"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)
"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)AvitoTech
 
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)Sarp Erdag
 
RubyMotion
RubyMotionRubyMotion
RubyMotionMark
 
Questioning the status quo
Questioning the status quoQuestioning the status quo
Questioning the status quoIvano Pagano
 
Objective C 基本介紹
Objective C 基本介紹Objective C 基本介紹
Objective C 基本介紹Giga Cheng
 

Similar to Modernizes your objective C - Oliviero (20)

Objective-C Crash Course for Web Developers
Objective-C Crash Course for Web DevelopersObjective-C Crash Course for Web Developers
Objective-C Crash Course for Web Developers
 
Avro, la puissance du binaire, la souplesse du JSON
Avro, la puissance du binaire, la souplesse du JSONAvro, la puissance du binaire, la souplesse du JSON
Avro, la puissance du binaire, la souplesse du JSON
 
Taking Objective-C to the next level. UA Mobile 2016.
Taking Objective-C to the next level. UA Mobile 2016.Taking Objective-C to the next level. UA Mobile 2016.
Taking Objective-C to the next level. UA Mobile 2016.
 
Irving iOS Jumpstart Meetup - Objective-C Session 2
Irving iOS Jumpstart Meetup - Objective-C Session 2Irving iOS Jumpstart Meetup - Objective-C Session 2
Irving iOS Jumpstart Meetup - Objective-C Session 2
 
FI MUNI 2012 - iOS Basics
FI MUNI 2012 - iOS BasicsFI MUNI 2012 - iOS Basics
FI MUNI 2012 - iOS Basics
 
MFF UK - Introduction to iOS
MFF UK - Introduction to iOSMFF UK - Introduction to iOS
MFF UK - Introduction to iOS
 
Crafting Evolvable Api Responses
Crafting Evolvable Api ResponsesCrafting Evolvable Api Responses
Crafting Evolvable Api Responses
 
iPhone Development Intro
iPhone Development IntroiPhone Development Intro
iPhone Development Intro
 
Don't Be Afraid of Abstract Syntax Trees
Don't Be Afraid of Abstract Syntax TreesDon't Be Afraid of Abstract Syntax Trees
Don't Be Afraid of Abstract Syntax Trees
 
Iphone course 1
Iphone course 1Iphone course 1
Iphone course 1
 
"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)
"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)
"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)
 
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
Hızlı Cocoa Geliştirme (Develop your next cocoa app faster!)
 
RubyMotion
RubyMotionRubyMotion
RubyMotion
 
Coding Ajax
Coding AjaxCoding Ajax
Coding Ajax
 
"Javascript" por Tiago Rodrigues
"Javascript" por Tiago Rodrigues"Javascript" por Tiago Rodrigues
"Javascript" por Tiago Rodrigues
 
Questioning the status quo
Questioning the status quoQuestioning the status quo
Questioning the status quo
 
Objective C 基本介紹
Objective C 基本介紹Objective C 基本介紹
Objective C 基本介紹
 
Coding Ajax
Coding AjaxCoding Ajax
Coding Ajax
 
Java script
Java scriptJava script
Java script
 
Symfony + GraphQL
Symfony + GraphQLSymfony + GraphQL
Symfony + GraphQL
 

More from Codemotion

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Codemotion
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyCodemotion
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaCodemotion
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserCodemotion
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Codemotion
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Codemotion
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Codemotion
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 - Codemotion
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Codemotion
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Codemotion
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Codemotion
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Codemotion
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Codemotion
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Codemotion
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Codemotion
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...Codemotion
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Codemotion
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Codemotion
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Codemotion
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Codemotion
 

More from Codemotion (20)

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending story
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storia
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard Altwasser
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
 

Recently uploaded

Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxnull - The Open Security Community
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 

Recently uploaded (20)

Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
The transition to renewables in India.pdf
The transition to renewables in India.pdfThe transition to renewables in India.pdf
The transition to renewables in India.pdf
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 

Modernizes your objective C - Oliviero

  • 2. About Massimo Oliviero
 Freelance Software Developer & Trainer
 #pragma mark founder ! www.massimooliviero.net
 massimo.oliviero@gmail.com
 @maxoly
  • 3. #pragma mark iOS & OSX Developers Community We organize the #PragmaConference, an event dedicated to iOS and OS X development ! http://www.pragmamark.org http://www.facebook.com/groups/pragmamark @pragmamarkorg
  • 10. use new literal syntax you can create NSArray, NSDictionary, NSNumber with a simple @
  • 11. Literals NSArray *names = [NSArray arrayWithObjects:@"Marco", @"Paolo", @"Flavio", nil]; NSDictionary *jobs = [NSDictionary dictionaryWithObjectsAndKeys:@"Marco", @"CTO", @"Paolo", "CEO", nil]; NSNumber *one = [NSNumber numberWithInt:1]; NSNumber *boolNum = [NSNumber numberWithBool:YES]; NSNumber *square = [NSNumber numberWithDouble:sqrt(2)];
  • 12. Literals NSArray *names = [NSArray arrayWithObjects:@"Marco", @"Paolo", @"Flavio", nil]; NSDictionary *jobs = [NSDictionary dictionaryWithObjectsAndKeys:@"Marco", @"CTO", @"Paolo", "CEO", nil]; NSNumber *one = [NSNumber numberWithInt:1]; NSNumber *boolNum = [NSNumber numberWithBool:YES]; NSNumber *square = [NSNumber numberWithDouble:sqrt(2)]; NSArray *names = @[ @"Marco", @"Paolo", @"Giuseppe" ]; ! NSDictionary *jobs = @{ @"CTO" : @"Marco", @"CEO" : @"Paolo" }; ! NSNumber *one = @1; NSNumber *boolNum = @YES; NSNumber *square = @(sqrt(2));
  • 14. Literals ‣ The new object literals significantly reduce the verbosity of code
  • 15. Literals ‣ The new object literals significantly reduce the verbosity of code ‣ All objects made via literal (such an array or a dictionary) are immutable
  • 16. Literals ‣ The new object literals significantly reduce the verbosity of code ‣ All objects made via literal (such an array or a dictionary) are immutable ‣ Remember that @(expr) dynamically evaluates the boxed expression and returns the appropriate object literal based on its value
  • 17. use Object Subscripting Object pointer values can now be used with C’s subscripting operator
  • 18. Object Subscripting ! NSArray *people = @[ @"John", @"Steve", @"Bill" ]; NSString *steve = [people objectAtIndex:1]; NSDictionary *books = @{ @"123" : @"Odyssey", @"234" : @"Illiad" }; NSString *illiad = [books objectForKey:@“234"]; ! // Mutable NSMutableArray *mPeople = [people mutableCopy]; [mPeople addObject:@"Ive"]; NSMutableDictionary *mBooks = [books mutableCopy]; [mBooks setObject:@"Othello" forKey:@"876"];
  • 19. Object Subscripting ! NSArray *people = @[ @"John", @"Steve", @"Bill" ]; NSString *steve = [people objectAtIndex:1]; NSDictionary *books = @{ @"123" : @"Odyssey", @"234" : @"Illiad" }; NSString *illiad = [books objectForKey:@“234"]; ! // Mutable NSMutableArray *mPeople = [people mutableCopy]; [mPeople addObject:@"Ive"]; NSMutableDictionary *mBooks = [books mutableCopy]; [mBooks setObject:@"Othello" forKey:@"876"]; ! NSArray *people = @[ @"John", @"Steve", @"Bill" ]; NSString *steve = people[1]; NSDictionary *books = @{ @"123" : @"Odyssey", @"234" : @"Illiad" }; NSString *illiad = books[@"234"]; ! ! // Mutable NSMutableArray *mPeople = [people mutableCopy]; mPeople[3] = @"Ive"; NSMutableDictionary *mBooks = [books mutableCopy]; mBooks[@"876"] = @"Othello";
  • 21. Custom Subscripting @interface MGACustomer : NSObject @property (nonatomic, strong, readonly) NSArray *orders; // Custom Indexed Subscripting - (id)objectAtIndexedSubscript:(NSUInteger)idx; - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx; // Custom Keyed Subscripting - (id)objectForKeyedSubscript:(id <NSCopying>)key; - (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key; @end // how to use custom subscripting - (void)foo { MGACustomer *customer = [[MGACustomer alloc] init]; id order67 = customer[67]; id order34 = customer[@"order.34"]; }
  • 23. Object Subscripting ‣ Subscripting syntax can significantly reduce the verbosity of code that deals heavily with arrays and dictionaries
  • 24. Object Subscripting ‣ Subscripting syntax can significantly reduce the verbosity of code that deals heavily with arrays and dictionaries ‣ Syntax similar to that found in common scripting languages
  • 25. Object Subscripting ‣ Subscripting syntax can significantly reduce the verbosity of code that deals heavily with arrays and dictionaries ‣ Syntax similar to that found in common scripting languages ‣ You can extend your own classes with subscripting support
  • 26. use new @import declaration @import is the new compiler directive introduced by Modules
  • 27. @import #import <UIKit/UIKit.h> #import <MapKit/MapKit.h> // you must add framework from Target > Build Phases ! ! @interface MGAMapViewController : UIViewController ! @property (weak, nonatomic) IBOutlet MKMapView *mapView; ! @end
  • 28. @import #import <UIKit/UIKit.h> #import <MapKit/MapKit.h> // you must add framework from Target > Build Phases ! ! @interface MGAMapViewController : UIViewController ! @property (weak, nonatomic) IBOutlet MKMapView *mapView; ! @end @import UIKit; @import MapKit; // no additional steps required ! ! @interface MGAMapViewController : UIViewController ! @property (weak, nonatomic) IBOutlet MKMapView *mapView; ! @end
  • 30. @import ‣ Modules provide an alternative, simpler way to use software libraries that provides better compile-time scalability and eliminates many of the problems inherent to using the C preprocessor to access the API of a library
  • 31. @import ‣ Modules provide an alternative, simpler way to use software libraries that provides better compile-time scalability and eliminates many of the problems inherent to using the C preprocessor to access the API of a library ‣ Modules link frameworks automatically (no more need to link framework from Build Phases)
  • 32. @import ‣ Modules provide an alternative, simpler way to use software libraries that provides better compile-time scalability and eliminates many of the problems inherent to using the C preprocessor to access the API of a library ‣ Modules link frameworks automatically (no more need to link framework from Build Phases) ‣ At this time, modules are only available for Apple’s frameworks and have been implicitly disabled for C++
  • 33. use new type instancetype instancetype is a contextual keyword that can be used as a result type to signal that a method returns a related result type, you can use it as return type of an init method or a (convenient)constructor
  • 34. instancetype @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, copy) NSString *name; + (id)customerWithName:(NSString *)name; ! @end ! @implementation MGACustomer ! + (id)customerWithName:(NSString *)name { id user = [[self alloc] init]; [user setName:name]; return user; } ! @end ! ! ! ! ! ! ! !
  • 35. instancetype @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, copy) NSString *name; + (id)customerWithName:(NSString *)name; ! @end ! @implementation MGACustomer ! + (id)customerWithName:(NSString *)name { id user = [[self alloc] init]; [user setName:name]; return user; } ! @end ! ! ! ! ! ! ! ! @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, copy) NSString *name; + (id)customerWithName:(NSString *)name; ! @end ! @implementation MGACustomer ! + (id)customerWithName:(NSString *)name { id user = [[self alloc] init]; [user setName:name]; return user; } ! @end ! .. ! - (void)foo { // assign an object of type MGACustomer to a string variable // will not generate any error or warning at compile-time NSString *wrong = [MGACustomer customerWithName:@"test"]; }
  • 36. instancetype @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, copy) NSString *name; + (id)customerWithName:(NSString *)name; ! @end ! @implementation MGACustomer ! + (id)customerWithName:(NSString *)name { id user = [[self alloc] init]; [user setName:name]; return user; } ! @end ! ! ! ! ! ! ! ! @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, copy) NSString *name; + (id)customerWithName:(NSString *)name; ! @end ! @implementation MGACustomer ! + (id)customerWithName:(NSString *)name { id user = [[self alloc] init]; [user setName:name]; return user; } ! @end ! .. ! - (void)foo { // assign an object of type MGACustomer to a string variable // will not generate any error or warning at compile-time NSString *wrong = [MGACustomer customerWithName:@"test"]; } @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, copy) NSString *name; + (instancetype)customerWithName:(NSString *)name; ! @end ! @implementation MGACustomer ! + (instancetype)customerWithName:(NSString *)name { id user = [[self alloc] init]; [user setName:name]; return user; } ! @end ! .. ! - (void)foo { // With ‘instancetype’ the compiler could infer type, it will generate: Incompatible // pointer types initializing 'NSString *' with an expression of type 'MGACustomer *' NSString *wrong = [MGACustomer customerWithName:@"test"]; }
  • 38. instancetype ‣ With instancetype, the compiler will correctly infer that the result of convenient constructor is an instance of a MGACustomer
  • 39. instancetype ‣ With instancetype, the compiler will correctly infer that the result of convenient constructor is an instance of a MGACustomer ‣ Instancetype, unlike id, can only be used as the result type in a method declaration
  • 40. instancetype ‣ With instancetype, the compiler will correctly infer that the result of convenient constructor is an instance of a MGACustomer ‣ Instancetype, unlike id, can only be used as the result type in a method declaration ‣ Init method should also use instancetype instead of id, instancetype is more explicit and therefore better than id
  • 41. use auto property synthesis synthesize not necessary for @property since Xcode 4.4
  • 42. auto property synthesis @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, copy) NSString *name; @property (nonatomic, readwrite, copy) NSString *address; ! @end ! ! ! ! @implementation MGACustomer { NSString *_name; NSString *_address; } ! @synthesize name = _name; @synthesize address = _address; ! - (void)foo { _name = @"Apple Inc."; } ! @end
  • 43. auto property synthesis @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, copy) NSString *name; @property (nonatomic, readwrite, copy) NSString *address; ! @end ! ! ! ! @implementation MGACustomer { NSString *_name; NSString *_address; } ! @synthesize name = _name; @synthesize address = _address; ! - (void)foo { _name = @"Apple Inc."; } ! @end @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, copy) NSString *name; @property (nonatomic, readwrite, copy) NSString *address; ! @end ! ! ! ! @implementation MGACustomer ! ! // compiler auto-synthesizes properties for you // and generate corresponding ivar(s) // with underscore as prefix ! ! ! - (void)foo { _name = @"Apple Inc.”; // you can still access to ivar } ! @end
  • 45. auto property synthesis ‣ Clang provides support for autosynthesis of declared properties. Using this feature, clang provides default synthesis of those properties not declared @dynamic and not having user provided backing getter and setter methods.
  • 46. auto property synthesis ‣ Clang provides support for autosynthesis of declared properties. Using this feature, clang provides default synthesis of those properties not declared @dynamic and not having user provided backing getter and setter methods. ‣ Auto-synthesis is not support for properties defined in a protocol
  • 47. auto property synthesis ‣ Clang provides support for autosynthesis of declared properties. Using this feature, clang provides default synthesis of those properties not declared @dynamic and not having user provided backing getter and setter methods. ‣ Auto-synthesis is not support for properties defined in a protocol ‣ The compiler will add the ivar for you (with underscore prefix) when it adds the required accessor methods
  • 48. use copy for any immutable class for attributes whose type is an immutable value class that conforms to the NSCopying protocol (e.g.. NSDate, NSNumber, NSArray, NSSet), you almost always should specify copy in your @property declaration
  • 49. copy attribute ! ! @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, strong) NSString *name; @property (nonatomic, readwrite, strong) NSString *address; @property (nonatomic, readwrite, strong) NSArray *orders; @property (nonatomic, readwrite, strong) NSDate *created; ! @end !
  • 50. copy attribute ! ! @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, strong) NSString *name; @property (nonatomic, readwrite, strong) NSString *address; @property (nonatomic, readwrite, strong) NSArray *orders; @property (nonatomic, readwrite, strong) NSDate *created; ! @end ! ! ! @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, copy) NSString *name; @property (nonatomic, readwrite, copy) NSString *address; @property (nonatomic, readwrite, copy) NSArray *orders; @property (nonatomic, readwrite, copy) NSDate *created; ! @end !
  • 52. copy attribute ‣ The reason of copy is that it is possible to have a property that is declared as an immutable type (such as NSString) yet pass it a mutable type (such as NSMutableString). In which case it is possible to change the property from outside the class
  • 53. copy attribute ‣ The reason of copy is that it is possible to have a property that is declared as an immutable type (such as NSString) yet pass it a mutable type (such as NSMutableString). In which case it is possible to change the property from outside the class ‣ using copy is recommended, because it behaves sensibly with class clusters, sending copy to a mutable class returns an immutable copy of the object
  • 54. NS_ENUM & NS_OPTIONS macro these macros are the new, preferred way to declare enum types.
  • 55. NS_ENUM typedef enum MGAUserProfile : NSUInteger { MGAUserProfileAdmin, MGAUserProfileGuest, MGAUserProfileOperator } MGAUserProfile; ! ! ! @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, assign) MGAUserProfile profile; ! @end
  • 56. NS_ENUM typedef enum MGAUserProfile : NSUInteger { MGAUserProfileAdmin, MGAUserProfileGuest, MGAUserProfileOperator } MGAUserProfile; ! ! ! @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, assign) MGAUserProfile profile; ! @end typedef NS_ENUM(NSUInteger, MGAUserProfile) { MGAUserProfileAdmin, MGAUserProfileGuest, MGAUserProfileOperator }; ! ! ! @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, assign) MGAUserProfile profile; ! @end
  • 57. NS_OPTIONS typedef enum MGAUserProfile : NSUInteger { MGAUserProfileAdmin = 1 << 0, MGAUserProfileGuest = 1 << 1, MGAUserProfileOperator = 1 << 2 } MGAUserProfile; ! ! ! @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, assign) MGAUserProfile profile; ! @end
  • 58. NS_OPTIONS typedef enum MGAUserProfile : NSUInteger { MGAUserProfileAdmin = 1 << 0, MGAUserProfileGuest = 1 << 1, MGAUserProfileOperator = 1 << 2 } MGAUserProfile; ! ! ! @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, assign) MGAUserProfile profile; ! @end typedef NS_OPTIONS(NSUInteger, MGAUserProfile) { MGAUserProfileAdmin = 1 << 0, MGAUserProfileGuest = 1 << 1, MGAUserProfileOperator = 1 << 2, }; ! ! ! @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, assign) MGAUserProfile profile; ! @end
  • 60. NS_ENUM & NS_OPTIONS ‣ The new macros combines the best of all ways to declare an enum or an option, and even provide hints to the compiler for type-checking and switch statement completeness.
  • 61. NS_ENUM & NS_OPTIONS ‣ The new macros combines the best of all ways to declare an enum or an option, and even provide hints to the compiler for type-checking and switch statement completeness. ‣ If the compiler is operating in C++11 or Objective-C+ +11 mode, the macros behave slightly differently in order to make the code compatible with the mixed mode
  • 62. use extern const not #define the best way to define a globally accessible constant is extern const
  • 64. // Constants.h #define kMGAProjectConst @“myString" #define kMGASomeMagicValue 42 extern const
  • 65. // Constants.h #define kMGAProjectConst @“myString" #define kMGASomeMagicValue 42 extern const // Constants.h extern NSString * const kMGAProjectConst; extern CGFloat const kMGASomeMagicValue; // Constants.m #import “Constants.h" NSString * const kMGAProjectConst = @“server.com”; CGFloat const kMGASomeMagicValue = 42.0f;
  • 66. // Constants.h #define kMGAProjectConst @“myString" #define kMGASomeMagicValue 42 extern const // Constants.h extern NSString * const kMGAProjectConst; extern CGFloat const kMGASomeMagicValue; // Constants.m #import “Constants.h" NSString * const kMGAProjectConst = @“server.com”; CGFloat const kMGASomeMagicValue = 42.0f; // Constants.h FOUNDATION_EXPORT NSString * const kMGAProjectConst; FOUNDATION_EXPORT CGFloat const kMGASomeMagicValue; ! ! ! // Constants.m #import “Constants.h" ! NSString * const kMGAProjectConst = @“server.com”; CGFloat const kMGASomeMagicValue = 42.0f;
  • 68. extern const ‣ It ensures that the compiler do a static type checking and emit a warning if you try to use it somewhere where it isn't expecting
  • 69. extern const ‣ It ensures that the compiler do a static type checking and emit a warning if you try to use it somewhere where it isn't expecting ‣ One benefit is that changing the value of a constant does not cause a rebuild of your entire program.
  • 70. extern const ‣ It ensures that the compiler do a static type checking and emit a warning if you try to use it somewhere where it isn't expecting ‣ One benefit is that changing the value of a constant does not cause a rebuild of your entire program. ‣ Use FOUNDATION_EXPORT macro instead of extern if your code will be used in mixed C/C++ environments or on other platforms
  • 71. use Foundation Data Types if you are unsure, the Foundation Data Types (like NSInterger or CGFloat) are the best choice because they are architecture safe versions of the corresponding C types
  • 73. Foundation Data Types ‣ The Fondation Data Types were introduced to make it easier to write code that works on both 32-bit and 64- bit without modification
  • 74. Foundation Data Types ‣ The Fondation Data Types were introduced to make it easier to write code that works on both 32-bit and 64- bit without modification ‣ You usually want to use Foundation Data Types when you don't know what kind of processor architecture your code might run on
  • 75. Foundation Data Types ‣ The Fondation Data Types were introduced to make it easier to write code that works on both 32-bit and 64- bit without modification ‣ You usually want to use Foundation Data Types when you don't know what kind of processor architecture your code might run on ‣ However, if you need to take control on memory footprint you can use native types
  • 76. Use Class Extensions to Hide Private Data Class extensions are often used to extend the public interface with additional private methods, properties or ivars for use within the implementation of the class itself
  • 77. // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! ! ! @end ! // MGAMapViewController.m @interface MGAMapViewController () ! ! ! ! ! ! ! ! @end ! @implementation MGAMapViewController ! ! ! ! ! ! ! ! ! @end Class Extensions
  • 78. // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! ! ! @end ! // MGAMapViewController.m @interface MGAMapViewController () ! ! ! ! ! ! ! ! @end ! @implementation MGAMapViewController ! ! ! ! ! ! ! ! ! @end // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! ! ! @end ! // MGAMapViewController.m @interface MGAMapViewController () ! ! ! ! - (void)privateMethod; ! ! ! @end ! @implementation MGAMapViewController ! ! ! ! - (void)privateMethod { } ! @end Class Extensions
  • 79. // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! ! ! @end ! // MGAMapViewController.m @interface MGAMapViewController () ! ! ! ! ! ! ! ! @end ! @implementation MGAMapViewController ! ! ! ! ! ! ! ! ! @end // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! ! ! @end ! // MGAMapViewController.m @interface MGAMapViewController () ! ! ! ! - (void)privateMethod; ! ! ! @end ! @implementation MGAMapViewController ! ! ! ! - (void)privateMethod { } ! @end // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! ! ! @end ! // MGAMapViewController.m @interface MGAMapViewController () { NSString *privateString; } ! - (void)privateMethod; ! ! ! @end ! @implementation MGAMapViewController ! ! ! ! - (void)privateMethod { privateString = @"hello"; } ! @end Class Extensions
  • 80. // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! ! ! @end ! // MGAMapViewController.m @interface MGAMapViewController () ! ! ! ! ! ! ! ! @end ! @implementation MGAMapViewController ! ! ! ! ! ! ! ! ! @end // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! ! ! @end ! // MGAMapViewController.m @interface MGAMapViewController () ! ! ! ! - (void)privateMethod; ! ! ! @end ! @implementation MGAMapViewController ! ! ! ! - (void)privateMethod { } ! @end // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! ! ! @end ! // MGAMapViewController.m @interface MGAMapViewController () { NSString *privateString; } ! - (void)privateMethod; ! ! ! @end ! @implementation MGAMapViewController ! ! ! ! - (void)privateMethod { privateString = @"hello"; } ! @end Class Extensions // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! @property (nonatomic, readonly) NSArray *points; ! @end ! // MGAMapViewController.m @interface MGAMapViewController () { NSString *privateString; } ! - (void)privateMethod; ! @property (nonatomic, strong, readwrite) NSArray *points; ! @end ! @implementation MGAMapViewController ! ! ! ! - (void)privateMethod { privateString = @"hello"; } ! @end
  • 81. // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! ! ! @end ! // MGAMapViewController.m @interface MGAMapViewController () ! ! ! ! ! ! ! ! @end ! @implementation MGAMapViewController ! ! ! ! ! ! ! ! ! @end // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! ! ! @end ! // MGAMapViewController.m @interface MGAMapViewController () ! ! ! ! - (void)privateMethod; ! ! ! @end ! @implementation MGAMapViewController ! ! ! ! - (void)privateMethod { } ! @end // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! ! ! @end ! // MGAMapViewController.m @interface MGAMapViewController () { NSString *privateString; } ! - (void)privateMethod; ! ! ! @end ! @implementation MGAMapViewController ! ! ! ! - (void)privateMethod { privateString = @"hello"; } ! @end Class Extensions // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! @property (nonatomic, readonly) NSArray *points; ! @end ! // MGAMapViewController.m @interface MGAMapViewController () { NSString *privateString; } ! - (void)privateMethod; ! @property (nonatomic, strong, readwrite) NSArray *points; ! @end ! @implementation MGAMapViewController ! ! ! ! - (void)privateMethod { privateString = @"hello"; } ! @end // MGAMapViewController.h @interface MGAMapViewController : UIViewController ! @property (nonatomic, readonly) NSArray *points; ! @end ! // MGAMapViewController.m @interface MGAMapViewController () { NSString *privateString; } ! - (void)privateMethod; ! @property (nonatomic, strong, readwrite) NSArray *points; ! @end ! @implementation MGAMapViewController { NSInteger counter; } ! - (void)privateMethod { privateString = @"hello"; } ! @end
  • 83. Class Extensions ‣ A class extension bears some similarity to a category, but it can only be added to a class for which you have the source code at compile time. The methods declared by a class extension are implemented in the @implementation block for the original class
  • 84. Class Extensions ‣ A class extension bears some similarity to a category, but it can only be added to a class for which you have the source code at compile time. The methods declared by a class extension are implemented in the @implementation block for the original class ‣ By declaring the class extension inside the source code file for the class implementation, the information stays private to the class; the header files in theory should only expose public interface for your classes
  • 86. Class Extensions ‣ It’s possible to use a class extension to add custom instance variables. These are declared inside braces in the class extension interface
  • 87. Class Extensions ‣ It’s possible to use a class extension to add custom instance variables. These are declared inside braces in the class extension interface ‣ It’s also common, for example, to define a property as readonly in the interface, but as readwrite in a class extension declared above the implementation, in order that the internal methods of the class can change the property value directly
  • 88. Class Extensions ‣ It’s possible to use a class extension to add custom instance variables. These are declared inside braces in the class extension interface ‣ It’s also common, for example, to define a property as readonly in the interface, but as readwrite in a class extension declared above the implementation, in order that the internal methods of the class can change the property value directly ‣ It’s also possible to declare an ivar in the @implemetation block
  • 90. use prefixes on all classes classes must be named uniquely in order to avoid name clashes
  • 91. use prefixes on all classes @interface Customer : NSObject ! @property (nonatomic, readwrite, copy) NSString *name; @property (nonatomic, readwrite, copy) NSString *address; ! @end ! ! ! ! @interface HomeViewController : UIViewController ! @property (weak, nonatomic) IBOutlet UILabel *userLabel; @property (weak, nonatomic) IBOutlet UILabel *logoLabel; @property (strong, nonatomic) Customer *user; ! @end
  • 92. use prefixes on all classes @interface Customer : NSObject ! @property (nonatomic, readwrite, copy) NSString *name; @property (nonatomic, readwrite, copy) NSString *address; ! @end ! ! ! ! @interface HomeViewController : UIViewController ! @property (weak, nonatomic) IBOutlet UILabel *userLabel; @property (weak, nonatomic) IBOutlet UILabel *logoLabel; @property (strong, nonatomic) Customer *user; ! @end @interface MGACustomer : NSObject ! @property (nonatomic, readwrite, copy) NSString *name; @property (nonatomic, readwrite, copy) NSString *address; ! @end ! ! ! ! @interface MGAHomeViewController : UIViewController ! @property (weak, nonatomic) IBOutlet UILabel *userLabel; @property (weak, nonatomic) IBOutlet UILabel *logoLabel; @property (strong, nonatomic) MAGCustomer *user; ! @end
  • 93. use prefixes on all classes
  • 94. use prefixes on all classes ‣ Choose a prefix with at least 3 uppercase chars that are significant for the project
  • 95. use prefixes on all classes ‣ Choose a prefix with at least 3 uppercase chars that are significant for the project ‣ Two-letter prefixes are reserved by Apple for use in framework classes, so you must use 3 (or more)
  • 96. use prefixes on all classes ‣ Choose a prefix with at least 3 uppercase chars that are significant for the project ‣ Two-letter prefixes are reserved by Apple for use in framework classes, so you must use 3 (or more) ‣ Objective-C classes must be named uniquely not only within the code that you’re writing in a project, but also across any frameworks or bundles you might be including. As an example, you should avoid using generic class names like ViewController or TextParser because it’s possible a framework you include in your app may fail to follow conventions and create classes with the same names.
  • 97. use a prefix for method names in categories in a category you should include a prefix on the method name to avoid clashes
  • 98. prefix category methods ! @interface NSString (MGAAdditions) ! - (NSString *)reverse; - (NSString *)sha256; ! @end
  • 99. prefix category methods ! @interface NSString (MGAAdditions) ! - (NSString *)reverse; - (NSString *)sha256; ! @end ! @interface NSString (MGAAdditions) ! - (NSString *)mga_reverse; - (NSString *)mga_sha256; ! @end
  • 101. prefix category methods ‣ If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime.
  • 102. prefix category methods ‣ If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime. ‣ In order to avoid undefined behavior, it’s best practice to add a prefix to method names in categories on framework classes, just like you should add a prefix to the names of your own classes. You might choose to use the same three letters you use for your class prefixes, but lowercase to follow the usual convention for method names, then an underscore, before the rest of the method name
  • 103. properly define BOOL property for Boolean properties the getter method should start with is
  • 104. properly define BOOL property ! @interface MGAUser ! @property (nonatomic, assign) BOOL authenticated; ! @end ! @interface MGAUser ! @property (nonatomic, assign, getter = isAuthenticated) BOOL authenticated; ! @end
  • 105. use ~iphone and ~ipad if you’re developing a universal app add tilde to xib name instead of underscore ! !
  • 106. ~iphone and ~ipad // MGAHomeViewController_iPhone.xib // MGAHomeViewController_iPad.xib ! @implementation MGAHomeViewController ! - (id)init { NSString *nibName = @"MGAHomeViewController_iPhone"; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { nibName = @"MGAHomeViewController_iPad"; } return [super initWithNibName:nibName bundle:nil]; } ! @end
  • 107. ~iphone and ~ipad // MGAHomeViewController_iPhone.xib // MGAHomeViewController_iPad.xib ! @implementation MGAHomeViewController ! - (id)init { NSString *nibName = @"MGAHomeViewController_iPhone"; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { nibName = @"MGAHomeViewController_iPad"; } return [super initWithNibName:nibName bundle:nil]; } ! @end please stop doing that!
  • 108. ~iphone and ~ipad // MGAHomeViewController_iPhone.xib // MGAHomeViewController_iPad.xib ! @implementation MGAHomeViewController ! - (id)init { NSString *nibName = @"MGAHomeViewController_iPhone"; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { nibName = @"MGAHomeViewController_iPad"; } return [super initWithNibName:nibName bundle:nil]; } ! @end // MGAHomeViewController~iphone.xib // MGAHomeViewController~ipad.xib ! @implementation MGAHomeViewController ! ! ! ! ! // no custom init required ! ! ! ! ! ! ! @end
  • 109. use ~iphone and ~ipad
  • 110. use ~iphone and ~ipad ‣ Adding ~iphone and ~ipad to xib file name, the runtime will automatically infer the correct xib to load (e.g. MGAHomeViewController~iphone.xib and MGAHomeViewController~ipad.xib)
  • 111. use ~iphone and ~ipad ‣ Adding ~iphone and ~ipad to xib file name, the runtime will automatically infer the correct xib to load (e.g. MGAHomeViewController~iphone.xib and MGAHomeViewController~ipad.xib) ‣ note, it’s case sensitive so iPhone and iPad, with a capital P, do not work
  • 112. organize #import statements it’s a good practice grouping and commenting #import statements
  • 113. organize #import statements ! #import <CoreData/CoreData.h> ! #import "MGAMapViewController.h" #import “MGAPictureView.h" #import “NSString+MGAAdditions.h” ! #import “MGAUser.h" ! #import <CoreLocation/CoreLocation.h> #import “NSDate+MGAAdditions.h” ! #import “MGAOrderCell.h" #import “MGACustomer.h" #import "UIImage+MGAAdditions.h" ! #import “MGAHomeViewController.h" #import <UIKit/UIKit.h> ! #import “MGAUserCell.h"
  • 114. organize #import statements ! #import <CoreData/CoreData.h> ! #import "MGAMapViewController.h" #import “MGAPictureView.h" #import “NSString+MGAAdditions.h” ! #import “MGAUser.h" ! #import <CoreLocation/CoreLocation.h> #import “NSDate+MGAAdditions.h” ! #import “MGAOrderCell.h" #import “MGACustomer.h" #import "UIImage+MGAAdditions.h" ! #import “MGAHomeViewController.h" #import <UIKit/UIKit.h> ! #import “MGAUserCell.h" ! // Frameworks #import <UIKit/UIKit.h> #import <CoreData/CoreData.h> #import <CoreLocation/CoreLocation.h> ! // View Controllers #import "MGAMapViewController.h" #import “MGAHomeViewController.h” ! // Views #import “MGAPictureView.h” ! // Cells #import “MGAUserCell.h” #import “MGAOrderCell.h” ! // Models #import “MGAUser.h" #import “MGACustomer.h” ! // Categories #import “NSDate+MGAAdditions.h” #import “UIImage+MGAAdditions.h" #import “NSString+MGAAdditions.h”
  • 117. organize #import statements ‣ group #imports ‣ comment the groups
  • 118. organize #import statements ‣ group #imports ‣ comment the groups ‣ If your are pedantic you can sort #import by length :)
  • 119. use #pragma mark organize your code, visually
  • 120. #pragma mark #pragma mark - View ! - (void)viewDidLoad { [super viewDidLoad]; … } ! - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; … } ! #pragma mark - UIScrollViewDelegate ! - (void)scrollViewDidScroll:(UIScrollView *)scrollView { … } ! - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { … } ! #pragma mark - Actions ! - (IBAction)loginButtonTouched:(id)sender { }
  • 123. #pragma mark ‣ Use #pragma mark in your @implementation to divide code into logical sections
  • 124. #pragma mark ‣ Use #pragma mark in your @implementation to divide code into logical sections ‣ It is also a way to organize your methods in the method list pop up view in Xcode
  • 125. Coding
  • 126. don’t #import in header file most #import statements should only be written in .m files, not .h headers
  • 127. don’t #import in header file #import "MGAUser.h" #import "MGANetworkManager.h" ! @interface MGALoginViewController : UIViewController ! @property (nonatomic, readonly) MGAUser *user; @property (nonatomic, strong, readwrite) MGANetworkManager *network; ! @end ! ! ! ! // MGALoginViewController.m ! @implementation MGALoginViewController ! ! @end
  • 128. don’t #import in header file #import "MGAUser.h" #import "MGANetworkManager.h" ! @interface MGALoginViewController : UIViewController ! @property (nonatomic, readonly) MGAUser *user; @property (nonatomic, strong, readwrite) MGANetworkManager *network; ! @end ! ! ! ! // MGALoginViewController.m ! @implementation MGALoginViewController ! ! @end @class MGAUser; // forward class declaration @class MGANetworkManager; // forward class declaration ! @interface MGALoginViewController : UIViewController ! @property (nonatomic, readonly) MGAUser *user; @property (nonatomic, strong, readwrite) MGANetworkManager *network; ! @end ! ! ! ! // MGALoginViewController.m ! #import "MGAUser.h" #import “MGANetworkManager.h" ! @implementation MGALoginViewController ! ! @end
  • 129. don’t #import in header file
  • 130. don’t #import in header file ‣ Rather than adding #import statements for each class, it's good practice to use forward class declarations in the header, and import them in the implementation
  • 131. don’t #import in header file ‣ Rather than adding #import statements for each class, it's good practice to use forward class declarations in the header, and import them in the implementation ‣ It reduce compile times and cyclical references
  • 132. don’t #import in header file ‣ Rather than adding #import statements for each class, it's good practice to use forward class declarations in the header, and import them in the implementation ‣ It reduce compile times and cyclical references ‣ The one real exception is when subclassing another custom class, you'll need to #import its header.
  • 133. use typedef to simplify Block syntax If you need to define more than one block with the same signature, you might like to define your own type for that signature
  • 135. blocks with typedef ! ! ! @interface MGACustomer ! ! ! - (void)createOrder:(void(^)(MGAOrder *order))completion; ! @end
  • 136. blocks with typedef ! ! ! @interface MGACustomer ! ! ! - (void)createOrder:(void(^)(MGAOrder *order))completion; ! @end typedef void(^MGACustomerBlock)(MGAOrder *order); ! ! @interface MGACustomer ! ! ! - (void)createOrder:(void(^)(MGAOrder *order))completion; ! @end
  • 137. blocks with typedef ! ! ! @interface MGACustomer ! ! ! - (void)createOrder:(void(^)(MGAOrder *order))completion; ! @end typedef void(^MGACustomerBlock)(MGAOrder *order); ! ! @interface MGACustomer ! ! ! - (void)createOrder:(void(^)(MGAOrder *order))completion; ! @end typedef void(^MGACustomerBlock)(MGAOrder *order); ! ! @interface MGACustomer ! ! ! - (void)createOrder:(MGACustomerBlock)completion; ! @end
  • 138. blocks with typedef ! ! ! @interface MGACustomer ! ! ! - (void)createOrder:(void(^)(MGAOrder *order))completion; ! @end typedef void(^MGACustomerBlock)(MGAOrder *order); ! ! @interface MGACustomer ! ! ! - (void)createOrder:(void(^)(MGAOrder *order))completion; ! @end typedef void(^MGACustomerBlock)(MGAOrder *order); ! ! @interface MGACustomer ! ! ! - (void)createOrder:(MGACustomerBlock)completion; ! @end typedef void(^MGACustomerBlock)(MGAOrder *order); ! ! @interface MGACustomer ! @property (nonatomic, copy) MGACustomerBlock completionBlock; ! - (void)createOrder:(MGACustomerBlock)completion; ! @end
  • 139. create types for blocks
  • 140. create types for blocks ‣ types improve readability and clean up your method definitions, life will be easier and It’s highly recommend making use of them as much as possible
  • 141. create types for blocks ‣ types improve readability and clean up your method definitions, life will be easier and It’s highly recommend making use of them as much as possible ‣ If you have to change the block signature, it is much easier to change the typedef. The compiler, being a nice fellow, will then tell you all the places the block signature doesn’t match
  • 142. how to access ivars Oh my!
  • 143. how to access ivars ! - (instancetype)initWithUser:(MGAUser *)user { self = [super init]; if (self) { _user = user; } return self; } ! - (void)viewDidLoad { [super viewDidLoad]; [self.usernameLabel setText:self.user.name]; } ! - (void)createNewUser { self.usernameLabel = [THMUser alloc] init]; }
  • 144. how to access ivars
  • 145. how to access ivars ‣ Direct access bypasses the property’s memory- management semantics defined by the setter
  • 146. how to access ivars ‣ Direct access bypasses the property’s memory- management semantics defined by the setter ‣ KVO notifications would not be fired when accessing the instance variables directly
  • 147. how to access ivars ‣ Direct access bypasses the property’s memory- management semantics defined by the setter ‣ KVO notifications would not be fired when accessing the instance variables directly ‣ In init methods you should use direct instance variable access, because subclasses could override the setter
  • 148. how to access ivars ‣ Direct access bypasses the property’s memory- management semantics defined by the setter ‣ KVO notifications would not be fired when accessing the instance variables directly ‣ In init methods you should use direct instance variable access, because subclasses could override the setter ‣ On the other part of class read/write data through properties
  • 149. always declare atomic/nonatomic Properties are declared as atomic by default
  • 150. declare atomic/nonatomic #import <UIKit/UIKit.h> ! @interface MGAMapViewController : UIViewController ! @property (readonly) CERUser *user; @property (copy) NSArray *locations; @property (weak) IBOutlet UITableView *tableView; ! @end
  • 151. declare atomic/nonatomic #import <UIKit/UIKit.h> ! @interface MGAMapViewController : UIViewController ! @property (readonly) CERUser *user; @property (copy) NSArray *locations; @property (weak) IBOutlet UITableView *tableView; ! @end #import <UIKit/UIKit.h> ! @interface MGAMapViewController : UIViewController ! @property (nonatomic, readonly) CERUser *user; @property (nonatomic, copy) NSArray *locations; @property (nonatomic, weak) IBOutlet UITableView *tableView; ! @end
  • 152. declare atomic/nonatomic #import <UIKit/UIKit.h> ! @interface MGAMapViewController : UIViewController ! @property (readonly) CERUser *user; @property (copy) NSArray *locations; @property (weak) IBOutlet UITableView *tableView; ! @end #import <UIKit/UIKit.h> ! @interface MGAMapViewController : UIViewController ! @property (nonatomic, readonly) CERUser *user; @property (nonatomic, copy) NSArray *locations; @property (nonatomic, weak) IBOutlet UITableView *tableView; ! @end #import <UIKit/UIKit.h> ! @interface MGAMapViewController : UIViewController ! @property (nonatomic, readonly) CERUser *user; @property (nonatomic, readwrite, copy) NSArray *locations; @property (nonatomic, readwrite, weak) IBOutlet UITableView *tableView; ! @end
  • 154. declare atomic/nonatomic ‣ By default, synthesized accessors include locking to make them atomic
  • 155. declare atomic/nonatomic ‣ By default, synthesized accessors include locking to make them atomic ‣ If you not need locking on property use nonatomic on iOS, since performance is severely impacted if atomic is used
  • 156. use read-only properties read-only properties are great for exposing information, you should use them often
  • 157. read-only properties ! @interface MGAMapViewController : UIViewController ! @property (nonatomic, readonly) MGAUser *user; @property (nonatomic, readonly) NSArray *locations; ! @end
  • 158. read-only properties ! @interface MGAMapViewController : UIViewController ! @property (nonatomic, readonly) MGAUser *user; @property (nonatomic, readonly) NSArray *locations; ! @end ! @interface MGAMapViewController : UIViewController ! @property (nonatomic, readonly) MGAUser *user; @property (nonatomic, readonly) NSArray *locations; ! @end ! ! ! ! ! ! ! ! ! ! @implementation MGAMapViewController ! - (instancetype)initWithUser:(MGaUser *)user { self = [super init]; if (self) { _user = user; } return self; } ! @end
  • 159. read-only properties ! @interface MGAMapViewController : UIViewController ! @property (nonatomic, readonly) MGAUser *user; @property (nonatomic, readonly) NSArray *locations; ! @end ! @interface MGAMapViewController : UIViewController ! @property (nonatomic, readonly) MGAUser *user; @property (nonatomic, readonly) NSArray *locations; ! @end ! ! ! ! ! ! ! ! ! ! @implementation MGAMapViewController ! - (instancetype)initWithUser:(MGaUser *)user { self = [super init]; if (self) { _user = user; } return self; } ! @end ! @interface MGAMapViewController : UIViewController ! @property (nonatomic, readonly) MGAUser *user; @property (nonatomic, readonly) NSArray *locations; ! @end ! ! @interface MGAMapViewController () ! @property (nonatomic, strong, readwrite) MGAUser *user; @property (nonatomic, strong, readwrite) NSArray *locations; ! @end ! ! @implementation MGAMapViewController ! - (instancetype)initWithUser:(MGAUser *)user { self = [super init]; if (self) { _user = user; } return self; } ! @end
  • 161. use read-only properties ‣ expose object data with read-only properties, unless you really need to allow access to internal data through a public setter
  • 162. use read-only properties ‣ expose object data with read-only properties, unless you really need to allow access to internal data through a public setter ‣ for read-only properties, you should defined a public getter but a private setter in class extension
  • 163. use weak to avoid retain cycles a wrong memory management involves in memory leaks
  • 166. retain cycle Object B @property (strong) Object A
  • 167. retain cycle Object B @property (strong) @property (strong) Object A
  • 168. retain cycle Object B @property (strong) @property (strong) Object A
  • 169. retain cycle Object B @property (strong) @property (strong) Object A
  • 170. retain cycle Object B @property (strong) Object A @property (weak)
  • 171. use __weak typeof a wrong memory management involves in memory leaks
  • 173. use __weak typeof - (void)viewDidLoad { [super viewDidLoad]; self.manager = [[MGANetworkManager alloc] init]; ! ! ! [self.manager getUsers:^(NSArray *users, NSError *error) { if (!error) { self.users = elements; [self.usersTableView reloadData]; } }]; }
  • 174. use __weak typeof - (void)viewDidLoad { [super viewDidLoad]; self.manager = [[MGANetworkManager alloc] init]; ! ! ! [self.manager getUsers:^(NSArray *users, NSError *error) { if (!error) { self.users = elements; [self.usersTableView reloadData]; } }]; }
  • 175. use __weak typeof - (void)viewDidLoad { [super viewDidLoad]; self.manager = [[MGANetworkManager alloc] init]; ! ! ! [self.manager getUsers:^(NSArray *users, NSError *error) { if (!error) { self.users = elements; [self.usersTableView reloadData]; } }]; }
  • 176. use __weak typeof - (void)viewDidLoad { [super viewDidLoad]; self.manager = [[MGANetworkManager alloc] init]; ! ! ! [self.manager getUsers:^(NSArray *users, NSError *error) { if (!error) { self.users = elements; [self.usersTableView reloadData]; } }]; } - (void)viewDidLoad { [super viewDidLoad]; self.manager = [[MGANetworkManager alloc] init]; ! __weak THMReportsViewController weakSelf = self; ! [weakSelf.manager getUsers:^(NSArray *users, NSError *error) { if (!error) { weakSelf.users = elements; [weakSelf.usersTableView reloadData]; } }]; }
  • 177. use __weak typeof - (void)viewDidLoad { [super viewDidLoad]; self.manager = [[MGANetworkManager alloc] init]; ! ! ! [self.manager getUsers:^(NSArray *users, NSError *error) { if (!error) { self.users = elements; [self.usersTableView reloadData]; } }]; } - (void)viewDidLoad { [super viewDidLoad]; self.manager = [[MGANetworkManager alloc] init]; ! __weak THMReportsViewController weakSelf = self; ! [weakSelf.manager getUsers:^(NSArray *users, NSError *error) { if (!error) { weakSelf.users = elements; [weakSelf.usersTableView reloadData]; } }]; } - (void)viewDidLoad { [super viewDidLoad]; self.manager = [[MGANetworkManager alloc] init]; ! __weak typeof(self) weakSelf = self; ! [weakSelf.manager getUsers:^(NSArray *users, NSError *error) { if (!error) { weakSelf.users = elements; [weakSelf.usersTableView reloadData]; } }]; }
  • 178. Manage third-part libraries with CocoaPods it’s an application level dependency manager for the Objective-C projects
  • 180. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile
  • 181. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2'
  • 182. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install
  • 183. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install
  • 184. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install
  • 185. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies
  • 186. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies
  • 187. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies
  • 188. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3)
  • 189. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5)
  • 190. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5) Using FormatterKit (1.4.2)
  • 191. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5) Using FormatterKit (1.4.2) Using ISO8601DateFormatterValueTransformer (0.5.0)
  • 192. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5) Using FormatterKit (1.4.2) Using ISO8601DateFormatterValueTransformer (0.5.0) Using RHAddressBook (1.1.1)
  • 193. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5) Using FormatterKit (1.4.2) Using ISO8601DateFormatterValueTransformer (0.5.0) Using RHAddressBook (1.1.1) Using RKValueTransformers (1.0.1)
  • 194. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5) Using FormatterKit (1.4.2) Using ISO8601DateFormatterValueTransformer (0.5.0) Using RHAddressBook (1.1.1) Using RKValueTransformers (1.0.1) Using RestKit (0.22.0)
  • 195. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5) Using FormatterKit (1.4.2) Using ISO8601DateFormatterValueTransformer (0.5.0) Using RHAddressBook (1.1.1) Using RKValueTransformers (1.0.1) Using RestKit (0.22.0) Using SDWebImage (3.5.4)
  • 196. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5) Using FormatterKit (1.4.2) Using ISO8601DateFormatterValueTransformer (0.5.0) Using RHAddressBook (1.1.1) Using RKValueTransformers (1.0.1) Using RestKit (0.22.0) Using SDWebImage (3.5.4) Using SDWebImage-ProgressView (0.3.1)
  • 197. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5) Using FormatterKit (1.4.2) Using ISO8601DateFormatterValueTransformer (0.5.0) Using RHAddressBook (1.1.1) Using RKValueTransformers (1.0.1) Using RestKit (0.22.0) Using SDWebImage (3.5.4) Using SDWebImage-ProgressView (0.3.1) Using SOCKit (1.1)
  • 198. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5) Using FormatterKit (1.4.2) Using ISO8601DateFormatterValueTransformer (0.5.0) Using RHAddressBook (1.1.1) Using RKValueTransformers (1.0.1) Using RestKit (0.22.0) Using SDWebImage (3.5.4) Using SDWebImage-ProgressView (0.3.1) Using SOCKit (1.1) Using TransitionKit (2.0.0)
  • 199. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5) Using FormatterKit (1.4.2) Using ISO8601DateFormatterValueTransformer (0.5.0) Using RHAddressBook (1.1.1) Using RKValueTransformers (1.0.1) Using RestKit (0.22.0) Using SDWebImage (3.5.4) Using SDWebImage-ProgressView (0.3.1) Using SOCKit (1.1) Using TransitionKit (2.0.0) Generating Pods project
  • 200. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5) Using FormatterKit (1.4.2) Using ISO8601DateFormatterValueTransformer (0.5.0) Using RHAddressBook (1.1.1) Using RKValueTransformers (1.0.1) Using RestKit (0.22.0) Using SDWebImage (3.5.4) Using SDWebImage-ProgressView (0.3.1) Using SOCKit (1.1) Using TransitionKit (2.0.0) Generating Pods project Integrating client project
  • 201. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5) Using FormatterKit (1.4.2) Using ISO8601DateFormatterValueTransformer (0.5.0) Using RHAddressBook (1.1.1) Using RKValueTransformers (1.0.1) Using RestKit (0.22.0) Using SDWebImage (3.5.4) Using SDWebImage-ProgressView (0.3.1) Using SOCKit (1.1) Using TransitionKit (2.0.0) Generating Pods project Integrating client project
  • 202. Cocoapods $ sudo gem install cocoapods $ cd MyGreatApp $ pod init $ edit Podfile platform :ios, '6.1' pod 'RestKit', '~> 0.22.0' pod 'FXKeychain', '~> 1.5' pod 'SDWebImage', '~> 3.5.2' pod 'SDWebImage-ProgressView', '~> 0.3.0' pod 'RHAddressBook', '~> 1.1.1' pod 'FormatterKit', '~> 1.4.2' $ pod install Analyzing dependencies Downloading dependencies Using AFNetworking (1.3.3) Using FXKeychain (1.5) Using FormatterKit (1.4.2) Using ISO8601DateFormatterValueTransformer (0.5.0) Using RHAddressBook (1.1.1) Using RKValueTransformers (1.0.1) Using RestKit (0.22.0) Using SDWebImage (3.5.4) Using SDWebImage-ProgressView (0.3.1) Using SOCKit (1.1) Using TransitionKit (2.0.0) Generating Pods project Integrating client project $
  • 204. Cocoapods ‣ CocoaPods manage dependency for you, it download source files, imports headers and configures flags
  • 205. Cocoapods ‣ CocoaPods manage dependency for you, it download source files, imports headers and configures flags ‣ CocoaPods is strongly inspired by a combination of the Ruby projects RubyGems and Bundler
  • 206. Cocoapods ‣ CocoaPods manage dependency for you, it download source files, imports headers and configures flags ‣ CocoaPods is strongly inspired by a combination of the Ruby projects RubyGems and Bundler ‣ CocoaPods focuses on source-based distribution of third party code and automatic integration into Xcode projects
  • 207. Cocoapods ‣ CocoaPods manage dependency for you, it download source files, imports headers and configures flags ‣ CocoaPods is strongly inspired by a combination of the Ruby projects RubyGems and Bundler ‣ CocoaPods focuses on source-based distribution of third party code and automatic integration into Xcode projects ‣ CocoaPods runs from the command line
  • 209. Key-Value Coding dynamically set and get properties and object graph
  • 210. Key-Value Coding MGACustomer *c1 = [[MGACustomer alloc] initWithName:@“ACME Inc.”]; c1.address = [[MGAAddress alloc] initWithZip:@“33568”]; ! ! [c1 valueForKey:@"name"]; // ACME Inc. [c1 valueForKeyPath:@“address.zip"]; // 33568
  • 211. Key-Value Coding MGACustomer *c1 = [[MGACustomer alloc] initWithName:@“ACME Inc.”]; c1.address = [[MGAAddress alloc] initWithZip:@“33568”]; ! ! [c1 valueForKey:@"name"]; // ACME Inc. [c1 valueForKeyPath:@“address.zip"]; // 33568 NSArray *names = @[ @"Steve", @"Bill", @"Ive" ]; ! // you can “get the value” of any method with no parameter [names valueForKey:@"uppercaseString"]; // @[ @“STEVE”, @“BILL”, @“IVE”] [names valueForKey:@"lowercaseString"]; // @[ @“steve”, @“bill”, @“ive”] ! ! // It’s really any method. // For example, -[NSObject self] is a method like any other. [@"Steve" valueForKey:@“self"]; // @“Steve” ! ! // KVC automatically boxes and unboxes values [names valueForKey:@"length"]; // @[ @5, @4, @3 ]
  • 213. Key-Value Coding ‣ Key-value coding is a mechanism for accessing an object’s properties indirectly, using strings to identify properties
  • 214. Key-Value Coding ‣ Key-value coding is a mechanism for accessing an object’s properties indirectly, using strings to identify properties ‣ You can get the value of any method with no parameter
  • 215. Key-Value Coding ‣ Key-value coding is a mechanism for accessing an object’s properties indirectly, using strings to identify properties ‣ You can get the value of any method with no parameter ‣ Key-Value Coding automatically boxes and unboxes values into their object representation.
  • 216. discover KVC Collection Operators save a few extra lines of code
  • 218. KVC Collection Operators MGAPerson *p1 = [[MGAPerson alloc] initWithName:@"Max" age:34]; MGAPerson *p2 = [[MGAPerson alloc] initWithName:@"Steve" age:54]; MGAPerson *p3 = [[MGAPerson alloc] initWithName:@"Bill" age:62]; NSArray *people = @[ p1, p2, p3 ]; // Simple Collection Operators [people valueForKeyPath:@"@count"]; // 3 [people valueForKeyPath:@"@sum.age"]; // 150.00 [people valueForKeyPath:@"@avg.age"]; // 50.00 [people valueForKeyPath:@"@max.age"]; // 63.00 // Objects Operators [people valueForKeyPath:@"@unionOfObjects.name"]; // "Max", "Steve", “Bill" // Simple Collection Operators with NSNumber NSArray *numbers = @[ @(1), @(2), @(3) ]; [numbers valueForKeyPath:@"@max.self"]; // 3
  • 220. KVC Collection Operators ‣ Collection operators allow actions to be performed on the items of a collection using key path notation and an action operator
  • 221. KVC Collection Operators ‣ Collection operators allow actions to be performed on the items of a collection using key path notation and an action operator ‣ Collection operators are specialized key paths that are passed as the parameter to the valueForKeyPath: method
  • 222. KVC Collection Operators ‣ Collection operators allow actions to be performed on the items of a collection using key path notation and an action operator ‣ Collection operators are specialized key paths that are passed as the parameter to the valueForKeyPath: method ‣ The operator is specified by a string preceded by an at sign (@)
  • 225. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
  • 226. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
  • 227. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp;
  • 228. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp;
  • 229. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^
  • 230. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^ {
  • 231. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^ { for (NSInteger i = 0; i < 10000; i++)
  • 232. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^ { for (NSInteger i = 0; i < 10000; i++) {
  • 233. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^ { for (NSInteger i = 0; i < 10000; i++) { if ([weakOp isCancelled])
  • 234. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^ { for (NSInteger i = 0; i < 10000; i++) { if ([weakOp isCancelled]) {
  • 235. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^ { for (NSInteger i = 0; i < 10000; i++) { if ([weakOp isCancelled]) { break;
  • 236. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^ { for (NSInteger i = 0; i < 10000; i++) { if ([weakOp isCancelled]) { break; }
  • 237. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^ { for (NSInteger i = 0; i < 10000; i++) { if ([weakOp isCancelled]) { break; }
  • 238. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^ { for (NSInteger i = 0; i < 10000; i++) { if ([weakOp isCancelled]) { break; } NSLog(@"%i", i);
  • 239. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^ { for (NSInteger i = 0; i < 10000; i++) { if ([weakOp isCancelled]) { break; } NSLog(@"%i", i); }
  • 240. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^ { for (NSInteger i = 0; i < 10000; i++) { if ([weakOp isCancelled]) { break; } NSLog(@"%i", i); } }];
  • 241. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^ { for (NSInteger i = 0; i < 10000; i++) { if ([weakOp isCancelled]) { break; } NSLog(@"%i", i); } }];
  • 242. NSBlockOperation NSBlockOperation *blockOp = [[NSBlockOperation alloc] init]; __weak typeof(blockOp) weakOp = blockOp; [blockOp addExecutionBlock:^ { for (NSInteger i = 0; i < 10000; i++) { if ([weakOp isCancelled]) { break; } NSLog(@"%i", i); } }]; [blockOp start];
  • 244. NSBlockOperation ‣ NSBlockOperation is a concrete subclass that wraps block in operations
  • 245. NSBlockOperation ‣ NSBlockOperation is a concrete subclass that wraps block in operations ‣ You can use this object to execute several blocks at once without having to create separate operation objects for each
  • 246. NSBlockOperation ‣ NSBlockOperation is a concrete subclass that wraps block in operations ‣ You can use this object to execute several blocks at once without having to create separate operation objects for each ‣ When executing more than one block, the operation itself is considered finished only when all blocks have finished executing
  • 247. NSError it encapsulates richer and more extensible error information
  • 249. Create an NSError NSString * const kMGAErrorDomain = @“com.acmeinc.MyGreatApp”; typedef NS_ENUM(NSInteger, MGAErrorCode) { MGAErrorCodeUnableToLocateUser = 500, MGAErrorCodeInvalidUser = 401 }; NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@“Location error”, nil), NSLocalizedFailureReasonErrorKey : NSLocalizedString(@"The location service is not active.", nil), NSLocalizedRecoverySuggestionErrorKey : NSLocalizedString(@"Please turn on the location service and try again", nil) }; NSError *error = [NSError errorWithDomain:kMGAErrorDomain code:MGAErrorCodeUnableToLocateUser userInfo:userInfo];
  • 251. Handle NSError - (void)handleError:(NSError *)error { if (error) { NSString *errorMessage; errorMessage = [NSString stringWithFormat:@"%@n%@", error.localizedFailureReason, error.localizedRecoverySuggestion]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:error.localizedDescription message:errorMessage delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", nil) otherButtonTitles:nil, nil]; [alert show]; } }
  • 253. Consuming NSError - (void)doLogin { NSString *user = self.usernameTextField.text; NSString *pass = self.passwordTextField.text; __weak typeof(self) weakSelf = self; [self.service loginWithUser:user pass:pass completion:^(TMGAUser *user, NSError *error) { [weakSelf handleError:error]; if (!error) { [weakSelf navigateToHome]; } }]; }
  • 255. NSError ‣ An NSError object encapsulates richer and more extensible error information than is possible using only an error code or error string
  • 256. NSError ‣ An NSError object encapsulates richer and more extensible error information than is possible using only an error code or error string ‣ The core attributes of an NSError object are an error domain, a domain-specific error code and a user info dictionary containing application specific information.
  • 257. NSError ‣ An NSError object encapsulates richer and more extensible error information than is possible using only an error code or error string ‣ The core attributes of an NSError object are an error domain, a domain-specific error code and a user info dictionary containing application specific information. ‣ Domain-specific error codes are generally defined by constants in an enum.
  • 258. use NSCache It’s a collection-like container, or cache, that stores key-value pairs, similar to the NSMutableDictionary class.
  • 260. NSCache NSCache *cache = [[NSCache alloc] init]; ! ! // Sets the maximum number of objects that the cache can hold. ! // This limit is not a strict limit, and if the cache goes over the limit, // an object in the cache could be evicted instantly, later, or possibly never, // all depending on the implementation details of the cache. [cache setCountLimit:50]; ! ! // Sets the maximum total cost that the cache can have before it starts evicting objects ! // If adding this object to the cache causes the cache’s total cost to rise above // totalCostLimit, the cache could automatically evict some of its objects until its // total cost falls below totalCostLimit. The order in which the cache evicts objects is // not guaranteed. This limit is not a strict limit, and if the cache goes over the // limit, an object in the cache could be evicted instantly, at a later point in time, // or possibly never, all depending on the implementation details of the cache. [cache setTotalCostLimit:5000]; ! ! // Add object to cache with cost [cache setObject:customer1 forKey:@"c1" cost:10]; ! ! // Add object to cache without cost [cache setObject:customer2 forKey:@"c2"];
  • 262. NSCache ‣ NSCache is basically just an NSMutableDictionary that automatically evicts objects in order to free up space in memory as needed
  • 263. NSCache ‣ NSCache is basically just an NSMutableDictionary that automatically evicts objects in order to free up space in memory as needed ‣ The NSCache class incorporates various auto-removal policies, which ensure that it does not use too much of the system’s memory. The system automatically carries out these policies if memory is needed by other applications. When invoked, these policies remove some items from the cache, minimizing its memory footprint.
  • 265. NSCache ‣ It is guaranteed to be thread-safe.
  • 266. NSCache ‣ It is guaranteed to be thread-safe. ‣ It is much slower to access.
  • 267. NSCache ‣ It is guaranteed to be thread-safe. ‣ It is much slower to access. ‣ It may throw out objects from time to time. You can set costs and limits, but they're not guaranteed to be followed.
  • 268. NSCache ‣ It is guaranteed to be thread-safe. ‣ It is much slower to access. ‣ It may throw out objects from time to time. You can set costs and limits, but they're not guaranteed to be followed. ‣ It is not toll-free bridged to anything in CoreFoundation.
  • 269. NSCache ‣ It is guaranteed to be thread-safe. ‣ It is much slower to access. ‣ It may throw out objects from time to time. You can set costs and limits, but they're not guaranteed to be followed. ‣ It is not toll-free bridged to anything in CoreFoundation. ‣ You can't query the number of objects that are in the cache.
  • 270. NSCache ‣ It is guaranteed to be thread-safe. ‣ It is much slower to access. ‣ It may throw out objects from time to time. You can set costs and limits, but they're not guaranteed to be followed. ‣ It is not toll-free bridged to anything in CoreFoundation. ‣ You can't query the number of objects that are in the cache. ‣ You can't enumerate a cache.
  • 271. NSValue NSValue is a simple container for a single C or Objective-C data value
  • 273. NSValue NSMutableArray *items = [@[] mutableCopy]; [items addObject:[NSValue valueWithCGSize:CGSizeMake(200.0f, 300.0f)]]; NSValue *sizeValue = items[0]; CGSize size = [sizeValue CGSizeValue]; // define new struct typedef struct MGAColor { float red, blue, green; } MGAColor; MGAColor color = { 255.0, 0.0f, 34.0 }; [items addObject:[NSValue valueWithBytes:&color objCType:@encode(MGAColor)]];
  • 274. NSValue NSMutableArray *items = [@[] mutableCopy]; [items addObject:[NSValue valueWithCGSize:CGSizeMake(200.0f, 300.0f)]]; NSValue *sizeValue = items[0]; CGSize size = [sizeValue CGSizeValue]; // define new struct typedef struct MGAColor { float red, blue, green; } MGAColor; MGAColor color = { 255.0, 0.0f, 34.0 }; [items addObject:[NSValue valueWithBytes:&color objCType:@encode(MGAColor)]]; MGAUser *user = [[MGAUser alloc] init]; // it not conforms to <NSCopying> NSMutableDictionary *items = [@{} mutableCopy]; // e.g. I want to store num of login attempts of a user // because my custom class MGAUser does not conform to <NSCopying> // I can’t use it as key value. The workaround is to box user instance // into NSValue object with valueWithNonretainedObject: [items setObject:numLogin forKey:[NSValue valueWithNonretainedObject:user]];
  • 276. NSValue ‣ It can hold scalars and value types, as well as pointers and object IDs.
  • 277. NSValue ‣ It can hold scalars and value types, as well as pointers and object IDs. ‣ NSValue uses type encoding to create the necessary data structures to represent values internally
  • 278. NSValue ‣ It can hold scalars and value types, as well as pointers and object IDs. ‣ NSValue uses type encoding to create the necessary data structures to represent values internally ‣ valueWithNonretainedObject: allows objects to be added to a collection, without the need for satisfying <NSCopying> protocol