"Stop it! That     Hurts!"      Common iOS Anti-Patterns@CarlBrwn                             Carl Brown            Missin...
ObBioCarl Brown (@CarlBrwn)iOS ContractorTeach Intro to iOS classesCo-Organizer CocoaCoder.orgStarted Mobile Programming 2...
ObBioCarl Brown (@CarlBrwn)iOS ContractorTeach Intro to iOS classesCo-Organizer CocoaCoder.orgStarted Mobile Programming 2...
Why So Much Bad Code?I live in Austin Texas                         2012
Why So Much Bad Code?"Looks like any idiot can make an App"                                         2012
Why So Much Bad Code?I try not to travel                          2012
Why So Much Bad Code? Working with clients in Austin Where SxSW implies that  any idiot can found App startup oDesk/Elance...
Not "Bad Code"?   At least for purposes of this talk...Braces for if on next line                                         ...
Not "Bad Code"?   At least for purposes of this talk...Braces for if on next lineSingletons ([Class sharedInstance])      ...
Not "Bad Code"?   At least for purposes of this talk...Braces for if on next lineSingletons ([Class sharedInstance])Dot No...
Not "Bad Code"?   At least for purposes of this talk...Braces for if on next lineSingletons ([Class sharedInstance])Dot No...
Not "Bad Code"?   At least for purposes of this talk...Braces for if on next lineSingletons ([Class sharedInstance])Dot No...
Not "Bad Code"?   At least for purposes of this talk...Braces for if on next lineSingletons ([Class sharedInstance])Dot No...
"Out Of Scope"          Bad Code   At least for purposes of this talk...Wrong in any Language Methods way too long  (Inclu...
Notice:All of the code you are about to seeis real.All of it was either released to users,sold for real money or posted on...
Bad Code                while (self && [self retainCount] >= 0) {                    [self release];                }     ...
Bad Code                while (self && [self retainCount] >= 0) {                    [self release];                }     ...
Bad Code                while (self && [self retainCount] >= 0) {                    [self release];                }     ...
Bad Code                while (self && [self retainCount] >= 0) {                    [self release];                }     ...
Bad Code                while (self && [self retainCount] >= 0) {                    [self release];                }     ...
"Tier 1" Bad CodeCompletely Useless   2012
Tier1: D.U.I.http://xkcd.com/323/   2012
Tier1: D.U.I.       Developing Under the Influencehttp://xkcd.com/323/                   2012
Tier1: Exhaustion                    2012
Tier 1:   Rage Against     theMachine            2012
"Tier 2" Bad Code"Lost In Translation"   2012
Method Naming- (EDAMNote *) getNote: (NSString *)authenticationToken : (EDAMGuid) guid : (BOOL)withContent : (BOOL) withRe...
Method Naming- (EDAMNote *) getNote: (NSString *)authenticationToken : (EDAMGuid) guid : (BOOL)withContent : (BOOL) withRe...
Class Naming@interface SettingsView :          UIViewController             <UITableViewDelegate,             UITableViewD...
Dont re-init existing objectsNSArray *barItems = _tabBarController.tabBar.items;UIImage *image = [UIImage imageNamed:@"bar...
Read Good Code We dont expect people to write in English before they spend a lot of time reading it Programming Languages ...
Read Good Code We dont expect people to write in English before they spend a lot of time reading it Programming Languages ...
Coding Styleif ([UIImagePickerController       isSourceTypeAvailable:         UIImagePickerControllerSourceTypeCamera])   ...
Coding Styleif ([UIImagePickerController       isSourceTypeAvailable:         UIImagePickerControllerSourceTypeCamera])   ...
Coding Styleif ([UIImagePickerController       isSourceTypeAvailable:         UIImagePickerControllerSourceTypeCamera])   ...
Error vs. Exception@try {    // perform the request    NSError *error;    return [managedObjectContext            executeF...
More NSError- (BOOL) save {    NSError *error = nil;    BOOL res = [[self managedObjectContext]                 save: &err...
What if?- (BOOL)writeFile:(NSString*)name        error:(NSError**)error {  if (![data writeToFile:name error:error]) {    ...
Tries to Write File- (BOOL)writeFile:(NSString*)name        error:(NSError**)error {  if (![data writeToFile:name error:er...
Mkdir if needed- (BOOL)writeFile:(NSString*)name        error:(NSError**)error {  if (![data writeToFile:name error:error]...
Then tries writing again- (BOOL)writeFile:(NSString*)name        error:(NSError**)error {  if (![data writeToFile:name err...
What gets Returned?- (BOOL)writeFile:(NSString*)name        error:(NSError**)error {  if (![data writeToFile:name error:er...
So, dont check error - (BOOL) save {     NSError *error = nil;     BOOL res = [[self managedObjectContext]                ...
Check Return Value- (BOOL) save {    NSError *error = nil;    BOOL res = [[self managedObjectContext]                 save...
Threading...  [NSThread detachNewThreadSelector:      @selector(fetchImageOnNewThread:)        toTarget:self withObject:co...
Asynchronous iOS                           Programming Rules                                         Threads are bad      ...
...or Lack Thereof-(IBAction)uploadAll {  if ([uploadQueueArray count] > 0) {    for (NSDictionary *item in uploadQueueArr...
Operation vs Dispatch I tend to use NSOperations for:  things Im going to do several times  things that have non-trivial c...
Operation vs Dispatch I tend to use NSOperations for:  things Im going to do several times  things that have non-trivial c...
Waiting  [NSThread sleepForTimeInterval:0.5];! // wait until the operation is completed  !  [(NSConditionLock *) operation...
Waiting      [[NSRunLoop currentRunLoop]            runUntilDate:[NSDate           dateWithTimeIntervalSinceNow:2.0]];- (v...
Password Storage@interface Uploads : NSManagedObject@property (nonatomic, retain) NSString * username;@property (nonatomic...
Password Storage Use the Keychain. These will help.   2012
Date Stuff    monthsArray = [[NSArray alloc]initWithObjects:NSLocalizedString(@"January",@"January"), NSLocalizedString(@"...
Date StuffNSDateFormatter *dateFormatter =                 [NSDateFormatter new];monthsArray = [dateFormatter monthSymbols...
Careful with Cachingfetcher = [fetcherMap objectForKey:@"type"];if (!fetcher) {        fetcher = [[Fetcher alloc] init];  ...
Careful with Cachingfetcher = [ nil objectForKey:@"type"];if (!fetcher) {        fetcher = [[Fetcher alloc] init];        ...
Careful with Cachingfetcher = [ nil objectForKey:@"type"];if (!fetcher) {        fetcher = [[Fetcher alloc] init];        ...
Dont Cache That Way    Thats a paradigm from web    programming, not mobile    Good only when you have tons of    memory  ...
"Tier 3" Bad Code     "TL;DR"        2012
TagsUITableViewCell *cell = [tableView      dequeueReusableCellWithIdentifier:CellIdentifier];UILabel *dateLabel = (UILabe...
TagsUITableViewCell *cell = [tableView      dequeueReusableCellWithIdentifier:CellIdentifier];UILabel *dateLabel = (UILabe...
Tags should be a Last Resort  Primarily used for:   Multiple Instances of the same Class   With the same Delegate method  ...
Tags should be a Last Resort  Primarily used for:   Multiple Instances of the same Class   With the same Delegate method  ...
Tags should be a Last Resort  Primarily used for:   Multiple Instances of the same Class   With the same Delegate method  ...
Dont "Remember"          Core Data Results- (void)viewDidLoad{    self.results =       [self.fetchedResultsController fetc...
Ask the NSFetchedResultsController- (UITableViewCell *)tableView:(UITableView *)tableViewcellForRowAtIndexPath:(NSIndexPat...
Dont mix read-only and    read-write dataImagine an App that downloads bulkdata like phonebooks or storelocations or SKUs ...
Dont mix read-only and    read-write dataImagine an App that downloads bulkdata like phonebooks or storelocations or SKUsN...
Dont mix read-only and    read-write dataImagine an App that downloads bulkdata like phonebooks or storelocations or SKUsN...
NSOperations have OverheadNSOperationQueue *queue = [NSOperationQueue new];NSInvocationOperation *operation =             ...
Use GCD for one-offsdispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{        [self      ...
"Tier 3" Bad Code   "Its a Trap!!"   2012
"Tier 3" Bad Code   "Its a Trap!!"   2012
This is my scariest slide                            2012
This is my scariest slide                            2012
Three20http://twitter.com/joehewitt/status/118437722519121920   2012
Three20 cont.the new Facebook for iOS marks our firstrelease in years without the Three20framework.     https://www.faceboo...
asi-http-requestAfter giving it a lot of thought over thelast few weeks, I’ve decided that I’m notgoing to continue workin...
Async != Background- (void)viewDidLoad {! ///Snip...! [[NSURLConnection alloc] initWithRequest:request delegate:self];}- (...
"Rocket Engine" for Responsive Code                      2012
"Rocket Engine" for         Responsive CodeNSAssert(![NSThread isMainThread], @"BOOM");                                   ...
"Rocket Engine" for         Responsive CodeNSAssert(![NSThread isMainThread], @"BOOM");        WARNING: Rocket Engines    ...
Updating from Network- (void)eventModelDidLoad:(NSArray *)events{! for (UIImageView *poster in           self.scrollView.c...
Refresh Incrementally   Only Init the Subviews Where   User Might Scroll Soon    Think tableView and    dequeueReusableCel...
MVC Model         2012
MVC Model         Controller View                      2012
NMVCNetwork   Model (or at least "Disk")                     Controller          View                                     ...
NMVCNetwork   Model (or at least "Disk")                     Controller          View                                     ...
Networking Advice         Always* load the UI from local storage           WITHOUT WAITING or BLOCKING           Core Data...
Networking Advice         Always* load the UI from local storage           WITHOUT WAITING or BLOCKING           Core Data...
Networking Advice         Always* load the UI from local storage           WITHOUT WAITING or BLOCKING           Core Data...
Networking Advice         Always* load the UI from local storage           WITHOUT WAITING or BLOCKING           Core Data...
In SummaryProgram Sober and Rested, If PossibleLeave Other Languages Patterns    at the DoorProgram IdiomaticallyDont Figh...
Thank You CarlB@PDAgent.com      @CarlBrwn                     2012
Upcoming SlideShare
Loading in …5
×

360iDev iOS AntiPatterns

2,210 views
2,090 views

Published on

360iDev Presentation this year:

As a contract iOS programmer, I spend about 80% of my time working with other people's iOS code - either working as a part of existing teams or taking over incomplete projects from developers who are no longer around. Along the way, I've gathered a list of the common mistakes I've seen people make, the open-source libraries I've seen people misuse the most, and the really simple code changes that can make huge differences in the reliability and performance of your apps. For each mistake or anti-pattern, I'll have an explanation of the issue with it, and at least one potential remedy or remediation that could be taken.
This talk will have a lot of specific code examples on a number of different topics and technologies, so hopefully everyone will learn something. And hopefully at least something will save you some time.
Note that this will be a very opinionated talk, and I'm quite likely to step on someone's pet pattern, so there may be fireworks.

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,210
On SlideShare
0
From Embeds
0
Number of Embeds
57
Actions
Shares
0
Downloads
13
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide
  • Start ScreenFlow and Camera!!!\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Often, this is just code written by stupid people\n
  • Developing Under the Influence...\n
  • But there&apos;s not a lot we can learn from looking at Tier1 Badness, so on to...\n
  • \n
  • Useful Somewhere, but not Here\n
  • This is from one of my favorite public APIs to pick on: Evernote\n
  • Please don&apos;t name your ViewControllers &quot;SomethingView&quot;\n
  • \n
  • \n
  • This was a fun bug I had to chase down.\nI&apos;m pretty sure the original file looked like this\n
  • And then I think this happened\n
  • Which resulted in this file, which would sometimes present the camera button on devices without the camera, which would then crash if clicked.\n
  • \n
  • \n
  • So Imagine there&apos;s a framework for saving a file\n
  • \n
  • \n
  • \n
  • So Imagine there&apos;s a framework for saving a file\n
  • \n
  • \n
  • iOS app for company with multi-billion dollar market cap.\n
  • \n
  • But, it could be worse. This was a Flash programmer on a video uploading app.\n\nApparently, Flash doesn&apos;t do threads...\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • In this case, fetcherMap was nil, so it would occasionally crash\n
  • In this case, fetcherMap was nil, so it would occasionally crash\n
  • In this case, fetcherMap was nil, so it would occasionally crash\n
  • \n
  • Apparently Useful, but not practically so\n
  • So much for type safety\n
  • MKMapViewDelegate Needed when user taps button on Callout on MapView \n
  • MKMapViewDelegate Needed when user taps button on Callout on MapView \n
  • MKMapViewDelegate Needed when user taps button on Callout on MapView \n
  • MKMapViewDelegate Needed when user taps button on Callout on MapView \n
  • Because if something in the background changes the data, the object in your array is no longer valid. Usually something like: &quot;CoreData could not fulfill a fault&quot;\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • No matter what you think about this spider...\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • So here, every time an update comes from the network, every poster is deleted from the scrollview, and then a new poster is made and added for everything that the network had. Even if it was already there. Even if it&apos;s pages away from where the user might scroll\n
  • \n
  • Network talks to the model, not the controller\n
  • Network talks to the model, not the controller\n
  • Network talks to the model, not the controller\n
  • Network talks to the model, not the controller\n
  • Network talks to the model, not the controller\n
  • Network talks to the model, not the controller\n
  • Network talks to the model, not the controller\n
  • Network talks to the model, not the controller\n
  • \n
  • \n
  • \n
  • \n
  • Stay away from things that make you Stupid\nRemember what language you&apos;re writing in\nPay attention, think things through, and educate yourself\n
  • \n
  • 360iDev iOS AntiPatterns

    1. 1. "Stop it! That Hurts!" Common iOS Anti-Patterns@CarlBrwn Carl Brown Missing final vowel (blame Flickr) 2012
    2. 2. ObBioCarl Brown (@CarlBrwn)iOS ContractorTeach Intro to iOS classesCo-Organizer CocoaCoder.orgStarted Mobile Programming 2004 (Palm)Half of team (Nov. 08) that wroteLIVESTRONG.com Calorie Tracker 2012
    3. 3. ObBioCarl Brown (@CarlBrwn)iOS ContractorTeach Intro to iOS classesCo-Organizer CocoaCoder.orgStarted Mobile Programming 2004 (Palm)Half of team (Nov. 08) that wroteLIVESTRONG.com Calorie Tracker 2012
    4. 4. Why So Much Bad Code?I live in Austin Texas 2012
    5. 5. Why So Much Bad Code?"Looks like any idiot can make an App" 2012
    6. 6. Why So Much Bad Code?I try not to travel 2012
    7. 7. Why So Much Bad Code? Working with clients in Austin Where SxSW implies that any idiot can found App startup oDesk/Elance/etc are full of idiots 2008 NDA gave idiots a running start 2012
    8. 8. Not "Bad Code"? At least for purposes of this talk...Braces for if on next line 2012
    9. 9. Not "Bad Code"? At least for purposes of this talk...Braces for if on next lineSingletons ([Class sharedInstance]) 2012
    10. 10. Not "Bad Code"? At least for purposes of this talk...Braces for if on next lineSingletons ([Class sharedInstance])Dot Notation (self.foo vs [self foo]) 2012
    11. 11. Not "Bad Code"? At least for purposes of this talk...Braces for if on next lineSingletons ([Class sharedInstance])Dot Notation (self.foo vs [self foo])Max nested square brackets ([[[[ ]]]]) 2012
    12. 12. Not "Bad Code"? At least for purposes of this talk...Braces for if on next lineSingletons ([Class sharedInstance])Dot Notation (self.foo vs [self foo])Max nested square brackets ([[[[ ]]]])ARC-less-ness (at least not yet) 2012
    13. 13. Not "Bad Code"? At least for purposes of this talk...Braces for if on next lineSingletons ([Class sharedInstance])Dot Notation (self.foo vs [self foo])Max nested square brackets ([[[[ ]]]])ARC-less-ness (at least not yet)Lack of Unit Tests (Unfortunately) 2012
    14. 14. "Out Of Scope" Bad Code At least for purposes of this talk...Wrong in any Language Methods way too long (Including AppDelegate) "Stringly Typed" code Using strings instead of types or Classes or enumsGeneral Programming 101 Stuff 2012
    15. 15. Notice:All of the code you are about to seeis real.All of it was either released to users,sold for real money or posted online.Variable names have been changed toprotect the guilty.Some has been edited for brevity. 2012
    16. 16. Bad Code while (self && [self retainCount] >= 0) { [self release]; } ///Carls Note: retainCount is NSUInteger"Tier 1" Bad: if (--retainCount == 0) [self dealloc]; - (id)initWithTarget:(id)theTarget { retainCount = 1; // We do not retain 2012
    17. 17. Bad Code while (self && [self retainCount] >= 0) { [self release]; } ///Carls Note: retainCount is NSUInteger"Tier 1" Bad: if (--retainCount == 0) [self dealloc]; - (id)initWithTarget:(id)theTarget { retainCount = 1; // We do not retain 2012
    18. 18. Bad Code while (self && [self retainCount] >= 0) { [self release]; } ///Carls Note: retainCount is NSUInteger"Tier 1" Bad: if (--retainCount == 0) [self dealloc]; - (id)initWithTarget:(id)theTarget { retainCount = 1; // We do not retain 2012
    19. 19. Bad Code while (self && [self retainCount] >= 0) { [self release]; } ///Carls Note: retainCount is NSUInteger"Tier 1" Bad: if (--retainCount == 0) [self dealloc]; - (id)initWithTarget:(id)theTarget { retainCount = 1; // We do not retain 2012
    20. 20. Bad Code while (self && [self retainCount] >= 0) { [self release]; } ///Carls Note: retainCount is NSUInteger"Tier 1" Bad: if (--retainCount == 0) [self dealloc]; - (id)initWithTarget:(id)theTarget { retainCount = 1; // We do not retain 2012
    21. 21. "Tier 1" Bad CodeCompletely Useless 2012
    22. 22. Tier1: D.U.I.http://xkcd.com/323/ 2012
    23. 23. Tier1: D.U.I. Developing Under the Influencehttp://xkcd.com/323/ 2012
    24. 24. Tier1: Exhaustion 2012
    25. 25. Tier 1: Rage Against theMachine 2012
    26. 26. "Tier 2" Bad Code"Lost In Translation" 2012
    27. 27. Method Naming- (EDAMNote *) getNote: (NSString *)authenticationToken : (EDAMGuid) guid : (BOOL)withContent : (BOOL) withResourcesData :(BOOL) withResourcesRecognition : (BOOL)withResourcesAlternateData; // throwsEDAMUserException *, EDAMSystemException *,EDAMNotFoundException *, TException 2012
    28. 28. Method Naming- (EDAMNote *) getNote: (NSString *)authenticationToken : (EDAMGuid) guid : (BOOL)withContent : (BOOL) withResourcesData :(BOOL) withResourcesRecognition : (BOOL)withResourcesAlternateData; // throwsEDAMUserException *, EDAMSystemException *,EDAMNotFoundException *, TException@selector(getNote::::::) 2012
    29. 29. Class Naming@interface SettingsView : UIViewController <UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate> 2012
    30. 30. Dont re-init existing objectsNSArray *barItems = _tabBarController.tabBar.items;UIImage *image = [UIImage imageNamed:@"barImage0.png"];[[barItems objectAtIndex:0] initWithTitle:@"Title0" image:image tag:0]; 2012
    31. 31. Read Good Code We dont expect people to write in English before they spend a lot of time reading it Programming Languages should be no different Read Good Books and Blogs WWDC videos and Apple Sample Code 2012
    32. 32. Read Good Code We dont expect people to write in English before they spend a lot of time reading it Programming Languages should be no different Read Good Books and Blogs WWDC videos and Apple Sample Code 2012
    33. 33. Coding Styleif ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) if ([[UIImagePickerController availableMediaTypesForSourceType: picker.sourceType] containsObject: kUTTypeMovie]) self.cameraButton.hidden = NO; 2012
    34. 34. Coding Styleif ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) self.title = @"Event Info"; if ([[UIImagePickerController availableMediaTypesForSourceType: picker.sourceType] containsObject: kUTTypeMovie]) self.cameraButton.hidden = NO; 2012
    35. 35. Coding Styleif ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) self.title = @"Event Info";if ([[UIImagePickerController availableMediaTypesForSourceType: picker.sourceType] containsObject: kUTTypeMovie]) self.cameraButton.hidden = NO; 2012
    36. 36. Error vs. Exception@try { // perform the request NSError *error; return [managedObjectContext executeFetchRequest:request error:&error];}@catch (NSException *exception) { NSLog(@"Problem Fetching: %@", exception);} 2012
    37. 37. More NSError- (BOOL) save { NSError *error = nil; BOOL res = [[self managedObjectContext] save: &error]; if (error != nil) { NSLog(@"Error saving data: %@", error); } return res;} 2012
    38. 38. What if?- (BOOL)writeFile:(NSString*)name error:(NSError**)error { if (![data writeToFile:name error:error]) { NSString *dir=[name lastPathComponent]; if (![fileMgr fileExistsAtPath:dir]) { [fileMgr createDirectoryAtPath:dir error:error]; if ([data writeToFile:name error:error]) { return YES; } } return NO; } return YES;} 2012
    39. 39. Tries to Write File- (BOOL)writeFile:(NSString*)name error:(NSError**)error { if (![data writeToFile:name error:error]) { NSString *dir=[name lastPathComponent]; if (![fileMgr fileExistsAtPath:dir]) { [fileMgr createDirectoryAtPath:dir error:error]; if ([data writeToFile:name error:error]) { return YES; } } return NO; } return YES;} 2012
    40. 40. Mkdir if needed- (BOOL)writeFile:(NSString*)name error:(NSError**)error { if (![data writeToFile:name error:error]) { NSString *dir=[name lastPathComponent]; if (![fileMgr fileExistsAtPath:dir]) { [fileMgr createDirectoryAtPath:dir error:error]; if ([data writeToFile:name error:error]) { return YES; } } return NO; } return YES;} 2012
    41. 41. Then tries writing again- (BOOL)writeFile:(NSString*)name error:(NSError**)error { if (![data writeToFile:name error:error]) { NSString *dir=[name lastPathComponent]; if (![fileMgr fileExistsAtPath:dir]) { [fileMgr createDirectoryAtPath:dir error:error]; if ([data writeToFile:name error:error]) { return YES; } } return NO; } return YES;} 2012
    42. 42. What gets Returned?- (BOOL)writeFile:(NSString*)name error:(NSError**)error { if (![data writeToFile:name error:error]) { NSString *dir=[name lastPathComponent]; if (![fileMgr fileExistsAtPath:dir]) { [fileMgr createDirectoryAtPath:dir error:error]; if ([data writeToFile:name error:error]) { return YES; } } return NO; } return YES;} 2012
    43. 43. So, dont check error - (BOOL) save { NSError *error = nil; BOOL res = [[self managedObjectContext] save: &error]; if (error ! = nil) { NSLog(@"Error saving data: %@", error); } return res; } 2012
    44. 44. Check Return Value- (BOOL) save { NSError *error = nil; BOOL res = [[self managedObjectContext] save: &error]; if (!res ) { NSLog(@"Error saving data: %@", error); } return res;} 2012
    45. 45. Threading... [NSThread detachNewThreadSelector: @selector(fetchImageOnNewThread:) toTarget:self withObject:connDict];-(void) fetchImageOnNewThread:(NSDictionary *) d { _image = [UIImage imageWithData: [NSData dataWithContentsOfURL: [d objectForKey:@"URL"]]];} 2012
    46. 46. Asynchronous iOS Programming Rules Threads are bad Use Queues instead Apples Concurrency Programming Guide*: Page 10: "The Move Away from Threads" Page 74: "Migrating Away from Threads" Page 74: "Replacing Threads with Dispatch Queues"* http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html 2012
    47. 47. ...or Lack Thereof-(IBAction)uploadAll { if ([uploadQueueArray count] > 0) { for (NSDictionary *item in uploadQueueArray) { [self.uploader connect:[item objectForKey:@"servername"]]; [self.uploader authenticate:[item objectForKey:@"user"] withPassword:[item objectForKey:@"pass"]]; [self.uploader uploadFile:[videoArray objectAtIndex:0]]; } }} 2012
    48. 48. Operation vs Dispatch I tend to use NSOperations for: things Im going to do several times things that have non-trivial complexity 2012
    49. 49. Operation vs Dispatch I tend to use NSOperations for: things Im going to do several times things that have non-trivial complexity I tend to use dispatch_async() for things: with less than 10 or so lines of code done only once in the App that wont need to change when spec changes 2012
    50. 50. Waiting [NSThread sleepForTimeInterval:0.5];! // wait until the operation is completed ! [(NSConditionLock *) operation.doneLock lockWhenCondition:kXmlOperationComplete beforeDate:[NSDate dateWithTimeIntervalSinceNow: kGiveUpInterval]]; 2012
    51. 51. Waiting [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];- (void)main { //Do Stuff CFRunLoopRun();}-(void) finish { CFRunLoopStop(CFRunLoopGetCurrent());} 2012
    52. 52. Password Storage@interface Uploads : NSManagedObject@property (nonatomic, retain) NSString * username;@property (nonatomic, retain) NSString * password;@end@implementation Uploads@dynamic username;@dynamic password;@end password.text = [[NSUserDefaults standardUserDefaults] valueForKey:kPasswordPreference]; 2012
    53. 53. Password Storage Use the Keychain. These will help. 2012
    54. 54. Date Stuff monthsArray = [[NSArray alloc]initWithObjects:NSLocalizedString(@"January",@"January"), NSLocalizedString(@"February",@"February"), NSLocalizedString(@"March", @"March"),NSLocalizedString(@"April", @"April"),NSLocalizedString(@"May", @"May"),NSLocalizedString(@"June", @"June"),NSLocalizedString(@"July", @"July"),NSLocalizedString(@"August", @"August"),NSLocalizedString(@"September",@"September"),NSLocalizedString(@"October",@"October"),NSLocalizedString(@"November", @"November"),NSLocalizedString(@"December", @"December"), nil]; 2012
    55. 55. Date StuffNSDateFormatter *dateFormatter = [NSDateFormatter new];monthsArray = [dateFormatter monthSymbols]; Use NSDateFormatters. But not too many. 2012
    56. 56. Careful with Cachingfetcher = [fetcherMap objectForKey:@"type"];if (!fetcher) { fetcher = [[Fetcher alloc] init]; [fetcherMap setValue:fetcher forKey:@"type"]; [fetcher release];}[ fetcher fetchPicturesForDelegate:self callbackMethod:@selector(picsFound:error:)]; Wheres the (intermittent) crash here? 2012
    57. 57. Careful with Cachingfetcher = [ nil objectForKey:@"type"];if (!fetcher) { fetcher = [[Fetcher alloc] init]; [ nil setValue:fetcher forKey:@"type"]; [fetcher release];}[ fetcher fetchPicturesForDelegate:self callbackMethod:@selector(picsFound:error:)]; Cache turned out to be nil 2012
    58. 58. Careful with Cachingfetcher = [ nil objectForKey:@"type"];if (!fetcher) { fetcher = [[Fetcher alloc] init]; [ nil setValue:fetcher forKey:@"type"]; [fetcher release];}[NSZombie fetchPicturesForDelegate:self callbackMethod:@selector(picsFound:error:)]; So fetcher could Zombify anytime 2012
    59. 59. Dont Cache That Way Thats a paradigm from web programming, not mobile Good only when you have tons of memory and need to serve >1K req/sec Mobile needs to be Responsive, but that kind of memory/time tradeoff not helpful 2012
    60. 60. "Tier 3" Bad Code "TL;DR" 2012
    61. 61. TagsUITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];UILabel *dateLabel = (UILabel *)[cell viewWithTag:1];UIView *imageBackground = (UIView *)[cell viewWithTag:2];UIImageView *thumbnail = (UIImageView *)[cell viewWithTag:3]; 2012
    62. 62. TagsUITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];UILabel *dateLabel = (UILabel *)[cell viewWithTag:1];UIView *imageBackground = (UIView *)[cell viewWithTag:2];UIImageView *thumbnail = (UIImageView *)[cell viewWithTag:3]; https://twitter.com/drance/status/226011326273695745 2012
    63. 63. Tags should be a Last Resort Primarily used for: Multiple Instances of the same Class With the same Delegate method 2012
    64. 64. Tags should be a Last Resort Primarily used for: Multiple Instances of the same Class With the same Delegate method Like UIAlertView or UIActionSheet 2012
    65. 65. Tags should be a Last Resort Primarily used for: Multiple Instances of the same Class With the same Delegate method Like UIAlertView or UIActionSheet also -[MKMapViewDelegate mapView:viewForAnnotation:] 2012
    66. 66. Dont "Remember" Core Data Results- (void)viewDidLoad{ self.results = [self.fetchedResultsController fetchedObjects];! //or self.results = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];}- (UITableViewCell *)tableView:(UITableView *)tableViewcellForRowAtIndexPath:(NSIndexPath *)indexPath{ cell.textLabel.text = [[self.results objectAtIndex:indexPath.row] name]; 2012
    67. 67. Ask the NSFetchedResultsController- (UITableViewCell *)tableView:(UITableView *)tableViewcellForRowAtIndexPath:(NSIndexPath *)indexPath{ cell.textLabel.text = [self.fetchedResultsController objectAtIndexPath:indexPath]; 2012
    68. 68. Dont mix read-only and read-write dataImagine an App that downloads bulkdata like phonebooks or storelocations or SKUs 2012
    69. 69. Dont mix read-only and read-write dataImagine an App that downloads bulkdata like phonebooks or storelocations or SKUsNow imagine that App also lets thelocal user comment/favorite/rate/review those entries 2012
    70. 70. Dont mix read-only and read-write dataImagine an App that downloads bulkdata like phonebooks or storelocations or SKUsNow imagine that App also lets thelocal user comment/favorite/rate/review those entriesNow imagine that every time youupdated 400K records, you had topreserve local modifications... 2012
    71. 71. NSOperations have OverheadNSOperationQueue *queue = [NSOperationQueue new];NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomeThing) object:nil];[queue addOperation:operation];[operation release];[queue release]; 2012
    72. 72. Use GCD for one-offsdispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ [self performSelector:@selector(doSomeThing)]; }); 2012
    73. 73. "Tier 3" Bad Code "Its a Trap!!" 2012
    74. 74. "Tier 3" Bad Code "Its a Trap!!" 2012
    75. 75. This is my scariest slide 2012
    76. 76. This is my scariest slide 2012
    77. 77. Three20http://twitter.com/joehewitt/status/118437722519121920 2012
    78. 78. Three20 cont.the new Facebook for iOS marks our firstrelease in years without the Three20framework.  https://www.facebook.com/notes/facebook-engineering/under-the-hood-rebuilding-facebook-for-ios/10151036091753920 2012
    79. 79. asi-http-requestAfter giving it a lot of thought over thelast few weeks, I’ve decided that I’m notgoing to continue working onASIHTTPRequest in future.http://allseeing-i.com/%5Brequest_release%5D; 2012
    80. 80. Async != Background- (void)viewDidLoad {! ///Snip...! [[NSURLConnection alloc] initWithRequest:request delegate:self];}- (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSString *jsonString = [[NSString alloc] initWithData:jsonResponse encoding:NSUTF8StringEncoding]; for (NSDictionary *jsonDict in [jsonString JSONValue]) {! ! //Create Object! ! [NSEntityDescription insertNewObjectForEntityForName:@"Event"];! }} AFNetworking can have this confusion 2012
    81. 81. "Rocket Engine" for Responsive Code 2012
    82. 82. "Rocket Engine" for Responsive CodeNSAssert(![NSThread isMainThread], @"BOOM"); 2012
    83. 83. "Rocket Engine" for Responsive CodeNSAssert(![NSThread isMainThread], @"BOOM"); WARNING: Rocket Engines can EXPLODE in testing. 2012
    84. 84. Updating from Network- (void)eventModelDidLoad:(NSArray *)events{! for (UIImageView *poster in self.scrollView.contentView.subViews) {        [poster removeFromSuperview];  }  for (Event *event in events)  {    UIImageView *poster = [[UIImageView alloc] initWithImage:event.image]; [eventPoster setFrame:event.frameRect];    [self.scrollView.contentView addSubview:poster];  }} Typical of a RESTKit Project 2012
    85. 85. Refresh Incrementally Only Init the Subviews Where User Might Scroll Soon Think tableView and dequeueReusableCellWithIdentifier Dont Delete & Recreate Subviews that Already Exist 2012
    86. 86. MVC Model 2012
    87. 87. MVC Model Controller View 2012
    88. 88. NMVCNetwork Model (or at least "Disk") Controller View 2012
    89. 89. NMVCNetwork Model (or at least "Disk") Controller View 2012
    90. 90. Networking Advice Always* load the UI from local storage WITHOUT WAITING or BLOCKING Core Data or local file or something Put up a placeholder if no data*Except with live web pages or HTTP streaming or the like 2012
    91. 91. Networking Advice Always* load the UI from local storage WITHOUT WAITING or BLOCKING Core Data or local file or something Put up a placeholder if no data Then start async download*Except with live web pages or HTTP streaming or the like 2012
    92. 92. Networking Advice Always* load the UI from local storage WITHOUT WAITING or BLOCKING Core Data or local file or something Put up a placeholder if no data Then start async download Then put network data in local storage*Except with live web pages or HTTP streaming or the like 2012
    93. 93. Networking Advice Always* load the UI from local storage WITHOUT WAITING or BLOCKING Core Data or local file or something Put up a placeholder if no data Then start async download Then put network data in local storage Then notify the UI to refresh itself*Except with live web pages or HTTP streaming or the like 2012
    94. 94. In SummaryProgram Sober and Rested, If PossibleLeave Other Languages Patterns at the DoorProgram IdiomaticallyDont Fight the FrameworksRead the Fine PrintLook for Hidden Bugs 2012
    95. 95. Thank You CarlB@PDAgent.com @CarlBrwn 2012

    ×