Your SlideShare is downloading. ×
0
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
360iDev iOS AntiPatterns
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

360iDev iOS AntiPatterns

1,769

Published on

360iDev Presentation this year: …

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
1,769
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
13
Comments
0
Likes
3
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
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'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't name your ViewControllers "SomethingView"\n
  • \n
  • \n
  • This was a fun bug I had to chase down.\nI'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's a framework for saving a file\n
  • \n
  • \n
  • \n
  • So Imagine there'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'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: "CoreData could not fulfill a fault"\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'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're writing in\nPay attention, think things through, and educate yourself\n
  • \n
  • Transcript

    • 1. "Stop it! That Hurts!" Common iOS Anti-Patterns@CarlBrwn Carl Brown Missing final vowel (blame Flickr) 2012
    • 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. 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. Why So Much Bad Code?I live in Austin Texas 2012
    • 5. Why So Much Bad Code?"Looks like any idiot can make an App" 2012
    • 6. Why So Much Bad Code?I try not to travel 2012
    • 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. Not "Bad Code"? At least for purposes of this talk...Braces for if on next line 2012
    • 9. Not "Bad Code"? At least for purposes of this talk...Braces for if on next lineSingletons ([Class sharedInstance]) 2012
    • 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. 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. 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. 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. "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. 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. 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. 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. 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. 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. 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. "Tier 1" Bad CodeCompletely Useless 2012
    • 22. Tier1: D.U.I.http://xkcd.com/323/ 2012
    • 23. Tier1: D.U.I. Developing Under the Influencehttp://xkcd.com/323/ 2012
    • 24. Tier1: Exhaustion 2012
    • 25. Tier 1: Rage Against theMachine 2012
    • 26. "Tier 2" Bad Code"Lost In Translation" 2012
    • 27. Method Naming- (EDAMNote *) getNote: (NSString *)authenticationToken : (EDAMGuid) guid : (BOOL)withContent : (BOOL) withResourcesData :(BOOL) withResourcesRecognition : (BOOL)withResourcesAlternateData; // throwsEDAMUserException *, EDAMSystemException *,EDAMNotFoundException *, TException 2012
    • 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. Class Naming@interface SettingsView : UIViewController <UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate> 2012
    • 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. 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. 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. Coding Styleif ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) if ([[UIImagePickerController availableMediaTypesForSourceType: picker.sourceType] containsObject: kUTTypeMovie]) self.cameraButton.hidden = NO; 2012
    • 34. Coding Styleif ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) self.title = @"Event Info"; if ([[UIImagePickerController availableMediaTypesForSourceType: picker.sourceType] containsObject: kUTTypeMovie]) self.cameraButton.hidden = NO; 2012
    • 35. Coding Styleif ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) self.title = @"Event Info";if ([[UIImagePickerController availableMediaTypesForSourceType: picker.sourceType] containsObject: kUTTypeMovie]) self.cameraButton.hidden = NO; 2012
    • 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. 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. 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. 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. 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. 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. 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. 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. 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. Threading... [NSThread detachNewThreadSelector: @selector(fetchImageOnNewThread:) toTarget:self withObject:connDict];-(void) fetchImageOnNewThread:(NSDictionary *) d { _image = [UIImage imageWithData: [NSData dataWithContentsOfURL: [d objectForKey:@"URL"]]];} 2012
    • 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. ...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. Operation vs Dispatch I tend to use NSOperations for: things Im going to do several times things that have non-trivial complexity 2012
    • 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. Waiting [NSThread sleepForTimeInterval:0.5];! // wait until the operation is completed ! [(NSConditionLock *) operation.doneLock lockWhenCondition:kXmlOperationComplete beforeDate:[NSDate dateWithTimeIntervalSinceNow: kGiveUpInterval]]; 2012
    • 51. Waiting [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];- (void)main { //Do Stuff CFRunLoopRun();}-(void) finish { CFRunLoopStop(CFRunLoopGetCurrent());} 2012
    • 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. Password Storage Use the Keychain. These will help. 2012
    • 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. Date StuffNSDateFormatter *dateFormatter = [NSDateFormatter new];monthsArray = [dateFormatter monthSymbols]; Use NSDateFormatters. But not too many. 2012
    • 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. 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. 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. 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. "Tier 3" Bad Code "TL;DR" 2012
    • 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. 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. Tags should be a Last Resort Primarily used for: Multiple Instances of the same Class With the same Delegate method 2012
    • 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. 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. 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. Ask the NSFetchedResultsController- (UITableViewCell *)tableView:(UITableView *)tableViewcellForRowAtIndexPath:(NSIndexPath *)indexPath{ cell.textLabel.text = [self.fetchedResultsController objectAtIndexPath:indexPath]; 2012
    • 68. Dont mix read-only and read-write dataImagine an App that downloads bulkdata like phonebooks or storelocations or SKUs 2012
    • 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. 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. 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. Use GCD for one-offsdispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ [self performSelector:@selector(doSomeThing)]; }); 2012
    • 73. "Tier 3" Bad Code "Its a Trap!!" 2012
    • 74. "Tier 3" Bad Code "Its a Trap!!" 2012
    • 75. This is my scariest slide 2012
    • 76. This is my scariest slide 2012
    • 77. Three20http://twitter.com/joehewitt/status/118437722519121920 2012
    • 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. 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. 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. "Rocket Engine" for Responsive Code 2012
    • 82. "Rocket Engine" for Responsive CodeNSAssert(![NSThread isMainThread], @"BOOM"); 2012
    • 83. "Rocket Engine" for Responsive CodeNSAssert(![NSThread isMainThread], @"BOOM"); WARNING: Rocket Engines can EXPLODE in testing. 2012
    • 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. Refresh Incrementally Only Init the Subviews Where User Might Scroll Soon Think tableView and dequeueReusableCellWithIdentifier Dont Delete & Recreate Subviews that Already Exist 2012
    • 86. MVC Model 2012
    • 87. MVC Model Controller View 2012
    • 88. NMVCNetwork Model (or at least "Disk") Controller View 2012
    • 89. NMVCNetwork Model (or at least "Disk") Controller View 2012
    • 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. 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. 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. 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. 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. Thank You CarlB@PDAgent.com @CarlBrwn 2012

    ×