SlideShare uma empresa Scribd logo
1 de 95
"Stop it! That
     Hurts!"
      Common iOS Anti-Patterns

@CarlBrwn                             Carl Brown

            Missing final vowel (blame Flickr)      2012
ObBio
Carl Brown (@CarlBrwn)
iOS Contractor
Teach Intro to iOS classes
Co-Organizer CocoaCoder.org
Started Mobile Programming 2004 (Palm)
Half of team (Nov. '08) that wrote
LIVESTRONG.com Calorie Tracker


                                         2012
ObBio
Carl Brown (@CarlBrwn)
iOS Contractor
Teach Intro to iOS classes
Co-Organizer CocoaCoder.org
Started Mobile Programming 2004 (Palm)
Half of team (Nov. '08) that wrote
LIVESTRONG.com Calorie Tracker


                                         2012
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/etc are full of idiots
 2008 NDA gave idiots a running start



                                        2012
Not "Bad Code"?
   At least for purposes of this talk...
Braces for 'if' on next line




                                           2012
Not "Bad Code"?
   At least for purposes of this talk...
Braces for 'if' on next line
Singletons ([Class sharedInstance])




                                           2012
Not "Bad Code"?
   At least for purposes of this talk...
Braces for 'if' on next line
Singletons ([Class sharedInstance])
Dot Notation (self.foo vs [self foo])




                                           2012
Not "Bad Code"?
   At least for purposes of this talk...
Braces for 'if' on next line
Singletons ([Class sharedInstance])
Dot Notation (self.foo vs [self foo])
Max nested square brackets ([[[[ ]]]])




                                           2012
Not "Bad Code"?
   At least for purposes of this talk...
Braces for 'if' on next line
Singletons ([Class sharedInstance])
Dot Notation (self.foo vs [self foo])
Max nested square brackets ([[[[ ]]]])
ARC-less-ness (at least not yet)



                                           2012
Not "Bad Code"?
   At least for purposes of this talk...
Braces for 'if' on next line
Singletons ([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
"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 enums
General Programming 101 Stuff
                                           2012
Notice:
All of the code you are about to see
is real.
All of it was either released to users,
sold for real money or posted online.
Variable names have been changed to
protect the guilty.
Some has been edited for brevity.

                                          2012
Bad Code
                while (self && [self retainCount] >= 0) {
                    [self release];
                }
                ///Carl's Note: retainCount is NSUInteger
"Tier 1" Bad:
                if (--retainCount == 0) [self dealloc];


                - (id)initWithTarget:(id)theTarget
                {
                    retainCount = 1;

                    // We do not retain




                                                          2012
Bad Code
                while (self && [self retainCount] >= 0) {
                    [self release];
                }
                ///Carl's Note: retainCount is NSUInteger
"Tier 1" Bad:
                if (--retainCount == 0) [self dealloc];


                - (id)initWithTarget:(id)theTarget
                {
                    retainCount = 1;

                    // We do not retain




                                                          2012
Bad Code
                while (self && [self retainCount] >= 0) {
                    [self release];
                }
                ///Carl's Note: retainCount is NSUInteger
"Tier 1" Bad:
                if (--retainCount == 0) [self dealloc];


                - (id)initWithTarget:(id)theTarget
                {
                    retainCount = 1;

                    // We do not retain




                                                          2012
Bad Code
                while (self && [self retainCount] >= 0) {
                    [self release];
                }
                ///Carl's Note: retainCount is NSUInteger
"Tier 1" Bad:
                if (--retainCount == 0) [self dealloc];


                - (id)initWithTarget:(id)theTarget
                {
                    retainCount = 1;

                    // We do not retain




                                                          2012
Bad Code
                while (self && [self retainCount] >= 0) {
                    [self release];
                }
                ///Carl's Note: retainCount is NSUInteger
"Tier 1" Bad:
                if (--retainCount == 0) [self dealloc];


                - (id)initWithTarget:(id)theTarget
                {
                    retainCount = 1;

                    // We do not retain




                                                          2012
"Tier 1" Bad Code




Completely Useless   2012
Tier1: D.U.I.



http://xkcd.com/323/   2012
Tier1: D.U.I.
       Developing Under the Influence




http://xkcd.com/323/                   2012
Tier1: Exhaustion




                    2012
Tier 1:
   Rage
 Against
     the
Machine
            2012
"Tier 2" Bad Code




"Lost In Translation"   2012
Method Naming
- (EDAMNote *) getNote: (NSString *)
authenticationToken : (EDAMGuid) guid : (BOOL)
withContent : (BOOL) withResourcesData :
(BOOL) withResourcesRecognition : (BOOL)
withResourcesAlternateData; // throws
EDAMUserException *, EDAMSystemException *,
EDAMNotFoundException *, TException




                                                 2012
Method Naming
- (EDAMNote *) getNote: (NSString *)
authenticationToken : (EDAMGuid) guid : (BOOL)
withContent : (BOOL) withResourcesData :
(BOOL) withResourcesRecognition : (BOOL)
withResourcesAlternateData; // throws
EDAMUserException *, EDAMSystemException *,
EDAMNotFoundException *, TException

@selector(getNote::::::)


                                                 2012
Class Naming
@interface SettingsView :
          UIViewController
             <UITableViewDelegate,
             UITableViewDataSource,
             UITextFieldDelegate>




                                      2012
Don't re-init existing objects


NSArray *barItems = _tabBarController.tabBar.items;
UIImage *image = [UIImage imageNamed:@"barImage0.png"];
[[barItems objectAtIndex:0]
      initWithTitle:@"Title0" image:image tag:0];




                                                     2012
Read Good Code
 We don't 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
Read Good Code
 We don't 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
Coding Style
if ([UIImagePickerController
       isSourceTypeAvailable:
         UIImagePickerControllerSourceTypeCamera])

    if ([[UIImagePickerController
       availableMediaTypesForSourceType:
           picker.sourceType] containsObject:
             kUTTypeMovie])

        self.cameraButton.hidden = NO;




                                                 2012
Coding Style
if ([UIImagePickerController
       isSourceTypeAvailable:
         UIImagePickerControllerSourceTypeCamera])

     self.title = @"Event Info";

    if ([[UIImagePickerController
       availableMediaTypesForSourceType:
           picker.sourceType] containsObject:
             kUTTypeMovie])

        self.cameraButton.hidden = NO;



                                                 2012
Coding Style
if ([UIImagePickerController
       isSourceTypeAvailable:
         UIImagePickerControllerSourceTypeCamera])

     self.title = @"Event Info";

if ([[UIImagePickerController
   availableMediaTypesForSourceType:
       picker.sourceType] containsObject:
         kUTTypeMovie])

    self.cameraButton.hidden = NO;



                                                 2012
Error vs. Exception
@try {
    // perform the request
    NSError *error;
    return [managedObjectContext
            executeFetchRequest:request
            error:&error];
}
@catch (NSException *exception) {
    NSLog(@"Problem Fetching: %@", exception);
}




                                                 2012
More NSError
- (BOOL) save {
    NSError *error = nil;
    BOOL res = [[self managedObjectContext]
                 save: &error];

    if (error != nil) {
        NSLog(@"Error saving data: %@", error);
    }
    return res;
}




                                                  2012
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
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
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
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
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
So, don't check error
 - (BOOL) save {
     NSError *error = nil;
     BOOL res = [[self managedObjectContext]
                  save: &error];

     if (error ! = nil) {
         NSLog(@"Error saving data: %@", error);
     }
     return res;
 }




                                                   2012
Check Return Value
- (BOOL) save {
    NSError *error = nil;
    BOOL res = [[self managedObjectContext]
                 save: &error];

    if (!res ) {
        NSLog(@"Error saving data: %@", error);
    }
    return res;
}




                                                  2012
Threading...
  [NSThread detachNewThreadSelector:
      @selector(fetchImageOnNewThread:)
        toTarget:self withObject:connDict];


-(void) fetchImageOnNewThread:(NSDictionary *) d {
    _image = [UIImage imageWithData:
      [NSData dataWithContentsOfURL:
           [d objectForKey:@"URL"]]];
}




                                                     2012
Asynchronous iOS
                           Programming Rules
                                         Threads are bad
                                         Use Queues instead
                                         Apple's 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
...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
Operation vs Dispatch
 I tend to use NSOperations for:
  things I'm going to do several times
  things that have non-trivial complexity




                                            2012
Operation vs Dispatch
 I tend to use NSOperations for:
  things I'm 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 won't need to change when spec changes



                                                2012
Waiting
  [NSThread sleepForTimeInterval:0.5];




! // wait until the operation is completed
  !
  [(NSConditionLock *) operation.doneLock
  lockWhenCondition:kXmlOperationComplete
    beforeDate:[NSDate dateWithTimeIntervalSinceNow:
        kGiveUpInterval]];



                                                       2012
Waiting
      [[NSRunLoop currentRunLoop]
            runUntilDate:[NSDate
           dateWithTimeIntervalSinceNow:2.0]];




- (void)main {
    //Do Stuff
    CFRunLoopRun();
}

-(void) finish {
    CFRunLoopStop(CFRunLoopGetCurrent());
}

                                                 2012
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
Password Storage



 Use the Keychain. These will help.   2012
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
Date Stuff

NSDateFormatter *dateFormatter =
                 [NSDateFormatter new];
monthsArray = [dateFormatter monthSymbols];




 Use NSDateFormatters. But not too many.      2012
Careful with Caching
fetcher = [fetcherMap objectForKey:@"type"];
if (!fetcher) {
        fetcher = [[Fetcher alloc] init];
        [fetcherMap setValue:fetcher
                 forKey:@"type"];
        [fetcher release];
}

[ fetcher fetchPicturesForDelegate:self
     callbackMethod:@selector(picsFound:error:)];




  Where's the (intermittent) crash here?            2012
Careful with Caching
fetcher = [ 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
Careful with Caching
fetcher = [ 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
Don't Cache That Way
    That's 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
"Tier 3" Bad Code




     "TL;DR"        2012
Tags
UITableViewCell *cell = [tableView
      dequeueReusableCellWithIdentifier:CellIdentifier];
UILabel *dateLabel = (UILabel *)[cell viewWithTag:1];
UIView *imageBackground = (UIView *)[cell viewWithTag:2];
UIImageView *thumbnail = (UIImageView *)[cell viewWithTag:3];




                                                            2012
Tags
UITableViewCell *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
Tags should be a Last Resort

  Primarily used for:
   Multiple Instances of the same Class
   With the same Delegate method




                                          2012
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
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
Don't "Remember"
          Core Data Results
- (void)viewDidLoad
{
    self.results =
       [self.fetchedResultsController fetchedObjects];
! //or
    self.results = [self.managedObjectContext
       executeFetchRequest:fetchRequest error:&error];
}

- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   cell.textLabel.text =
   [[self.results objectAtIndex:indexPath.row] name];




                                                          2012
Ask the
 NSFetchedResultsController

- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    cell.textLabel.text =
           [self.fetchedResultsController
              objectAtIndexPath:indexPath];




                                                          2012
Don't mix read-only and
    read-write data
Imagine an App that downloads bulk
data like phonebooks or store
locations or SKUs




                                     2012
Don't mix read-only and
    read-write data
Imagine an App that downloads bulk
data like phonebooks or store
locations or SKUs
Now imagine that App also lets the
local user comment/favorite/rate/
review those entries



                                     2012
Don't mix read-only and
    read-write data
Imagine an App that downloads bulk
data like phonebooks or store
locations or SKUs
Now imagine that App also lets the
local user comment/favorite/rate/
review those entries
Now imagine that every time you
updated 400K records, you had to
preserve local modifications...
                                     2012
NSOperations have Overhead


NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation =
             [[NSInvocationOperation alloc]
               initWithTarget:self
               selector:@selector(doSomeThing)
               object:nil];
[queue addOperation:operation];
[operation release];
[queue release];




                                                    2012
Use GCD for one-offs

dispatch_async(dispatch_get_global_queue(DISPATCH_
QUEUE_PRIORITY_BACKGROUND, 0), ^{
        [self
         performSelector:@selector(doSomeThing)];
    });




                                                     2012
"Tier 3" Bad Code




   "It's a Trap!!"   2012
"Tier 3" Bad Code




   "It's a Trap!!"   2012
This is my scariest slide




                            2012
This is my scariest slide




                            2012
Three20



http://twitter.com/joehewitt/status/118437722519121920   2012
Three20 cont.
the new Facebook for iOS marks our first
release in years without the Three20
framework. 




    https://www.facebook.com/notes/facebook-engineering/
under-the-hood-rebuilding-facebook-for-ios/10151036091753920   2012
asi-http-request

After giving it a lot of thought over the
last few weeks, I’ve decided that I’m not
going to continue working on
ASIHTTPRequest in future.


http://allseeing-i.com/%5Brequest_release%5D;   2012
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
"Rocket Engine" for
 Responsive Code




                      2012
"Rocket Engine" for
         Responsive Code


NSAssert(![NSThread isMainThread], @"BOOM");




                                           2012
"Rocket Engine" for
         Responsive Code
NSAssert(![NSThread isMainThread], @"BOOM");


        WARNING: Rocket Engines




         can EXPLODE in testing.
                                           2012
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
Refresh Incrementally

   Only Init the Subviews Where
   User Might Scroll Soon
    Think tableView and
    dequeueReusableCellWithIdentifier
   Don't Delete & Recreate
   Subviews that Already Exist


                                       2012
MVC
 Model




         2012
MVC
 Model

         Controller



 View
                      2012
NMVC
Network   Model (or at least "Disk")

                     Controller



          View
                                       2012
NMVC
Network   Model (or at least "Disk")

                     Controller



          View
                                       2012
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
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
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
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
In Summary
Program Sober and Rested, If Possible
Leave Other Languages' Patterns
    at the Door
Program Idiomatically
Don't Fight the Frameworks
Read the Fine Print
Look for Hidden Bugs
                                        2012
Thank You
 CarlB@PDAgent.com
      @CarlBrwn

                     2012

Mais conteúdo relacionado

Mais procurados

Getting started with the JNI
Getting started with the JNIGetting started with the JNI
Getting started with the JNIKirill Kounik
 
Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"Victor_Cr
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code DevelopmentPeter Gfader
 
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
 
Messages, Instances and Initialization
Messages, Instances and InitializationMessages, Instances and Initialization
Messages, Instances and Initializationadil raja
 
Enforce Consistentcy with Clean Architecture
Enforce Consistentcy with Clean ArchitectureEnforce Consistentcy with Clean Architecture
Enforce Consistentcy with Clean ArchitectureFlorin Coros
 
Using Xcore with Xtext
Using Xcore with XtextUsing Xcore with Xtext
Using Xcore with XtextHolger Schill
 
Building DSLs with Xtext - Eclipse Modeling Day 2009
Building DSLs with Xtext - Eclipse Modeling Day 2009Building DSLs with Xtext - Eclipse Modeling Day 2009
Building DSLs with Xtext - Eclipse Modeling Day 2009Heiko Behrens
 
Dependency Injection Why is it awesome and Why should I care?
Dependency Injection Why is it awesome and Why should I care?Dependency Injection Why is it awesome and Why should I care?
Dependency Injection Why is it awesome and Why should I care?ColdFusionConference
 
Introduction to OO, Java and Eclipse/WebSphere
Introduction to OO, Java and Eclipse/WebSphereIntroduction to OO, Java and Eclipse/WebSphere
Introduction to OO, Java and Eclipse/WebSphereeLink Business Innovations
 
iPhone Seminar Part 2
iPhone Seminar Part 2iPhone Seminar Part 2
iPhone Seminar Part 2NAILBITER
 
From C++ to Objective-C
From C++ to Objective-CFrom C++ to Objective-C
From C++ to Objective-Ccorehard_by
 
Condor overview - glideinWMS Training Jan 2012
Condor overview - glideinWMS Training Jan 2012Condor overview - glideinWMS Training Jan 2012
Condor overview - glideinWMS Training Jan 2012Igor Sfiligoi
 
Testing untestable code - oscon 2012
Testing untestable code - oscon 2012Testing untestable code - oscon 2012
Testing untestable code - oscon 2012Stephan Hochdörfer
 

Mais procurados (20)

The Xtext Grammar Language
The Xtext Grammar LanguageThe Xtext Grammar Language
The Xtext Grammar Language
 
Writing clean code
Writing clean codeWriting clean code
Writing clean code
 
Solid principles
Solid principlesSolid principles
Solid principles
 
Getting started with the JNI
Getting started with the JNIGetting started with the JNI
Getting started with the JNI
 
Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code Development
 
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
 
Messages, Instances and Initialization
Messages, Instances and InitializationMessages, Instances and Initialization
Messages, Instances and Initialization
 
S313431 JPA 2.0 Overview
S313431 JPA 2.0 OverviewS313431 JPA 2.0 Overview
S313431 JPA 2.0 Overview
 
Enforce Consistentcy with Clean Architecture
Enforce Consistentcy with Clean ArchitectureEnforce Consistentcy with Clean Architecture
Enforce Consistentcy with Clean Architecture
 
Using Xcore with Xtext
Using Xcore with XtextUsing Xcore with Xtext
Using Xcore with Xtext
 
Building DSLs with Xtext - Eclipse Modeling Day 2009
Building DSLs with Xtext - Eclipse Modeling Day 2009Building DSLs with Xtext - Eclipse Modeling Day 2009
Building DSLs with Xtext - Eclipse Modeling Day 2009
 
Dependency Injection Why is it awesome and Why should I care?
Dependency Injection Why is it awesome and Why should I care?Dependency Injection Why is it awesome and Why should I care?
Dependency Injection Why is it awesome and Why should I care?
 
Introduction to OO, Java and Eclipse/WebSphere
Introduction to OO, Java and Eclipse/WebSphereIntroduction to OO, Java and Eclipse/WebSphere
Introduction to OO, Java and Eclipse/WebSphere
 
iPhone Seminar Part 2
iPhone Seminar Part 2iPhone Seminar Part 2
iPhone Seminar Part 2
 
Iphone course 1
Iphone course 1Iphone course 1
Iphone course 1
 
From C++ to Objective-C
From C++ to Objective-CFrom C++ to Objective-C
From C++ to Objective-C
 
Reversing JavaScript
Reversing JavaScriptReversing JavaScript
Reversing JavaScript
 
Condor overview - glideinWMS Training Jan 2012
Condor overview - glideinWMS Training Jan 2012Condor overview - glideinWMS Training Jan 2012
Condor overview - glideinWMS Training Jan 2012
 
Testing untestable code - oscon 2012
Testing untestable code - oscon 2012Testing untestable code - oscon 2012
Testing untestable code - oscon 2012
 

Semelhante a 360iDev iOS AntiPatterns

Practical JavaScript Programming - Session 4/8
Practical JavaScript Programming - Session 4/8Practical JavaScript Programming - Session 4/8
Practical JavaScript Programming - Session 4/8Wilson Su
 
From clever code to better code
From clever code to better codeFrom clever code to better code
From clever code to better codeDror Helper
 
Dojo >= 1.7 Kickstart
Dojo >= 1.7  KickstartDojo >= 1.7  Kickstart
Dojo >= 1.7 KickstartHazem Saleh
 
Working with c++ legacy code
Working with c++ legacy codeWorking with c++ legacy code
Working with c++ legacy codeDror Helper
 
Jailbreak Detector Detector
Jailbreak Detector DetectorJailbreak Detector Detector
Jailbreak Detector DetectorNick Mooney
 
ONE MORE TIME ABOUT CODE STANDARDS AND BEST PRACTICES
ONE MORE TIME ABOUT CODE STANDARDS AND BEST PRACTICESONE MORE TIME ABOUT CODE STANDARDS AND BEST PRACTICES
ONE MORE TIME ABOUT CODE STANDARDS AND BEST PRACTICESDrupalCamp Kyiv
 
Supercharge Flutter declarative UI with code generation
Supercharge Flutter declarative UI with code generationSupercharge Flutter declarative UI with code generation
Supercharge Flutter declarative UI with code generationEmanuele Papa
 
AngularJS Architecture
AngularJS ArchitectureAngularJS Architecture
AngularJS ArchitectureEyal Vardi
 
AngularJS Internal
AngularJS InternalAngularJS Internal
AngularJS InternalEyal Vardi
 
Android | Busy Java Developers Guide to Android: Persistence | Ted Neward
Android | Busy Java Developers Guide to Android: Persistence | Ted NewardAndroid | Busy Java Developers Guide to Android: Persistence | Ted Neward
Android | Busy Java Developers Guide to Android: Persistence | Ted NewardJAX London
 
.NET Coding Standards For The Real World (2012)
.NET Coding Standards For The Real World (2012).NET Coding Standards For The Real World (2012)
.NET Coding Standards For The Real World (2012)David McCarter
 

Semelhante a 360iDev iOS AntiPatterns (20)

Practical JavaScript Programming - Session 4/8
Practical JavaScript Programming - Session 4/8Practical JavaScript Programming - Session 4/8
Practical JavaScript Programming - Session 4/8
 
Robots in Swift
Robots in SwiftRobots in Swift
Robots in Swift
 
From clever code to better code
From clever code to better codeFrom clever code to better code
From clever code to better code
 
Clean Code 2
Clean Code 2Clean Code 2
Clean Code 2
 
Thinking In Swift
Thinking In SwiftThinking In Swift
Thinking In Swift
 
Test02
Test02Test02
Test02
 
Dojo >= 1.7 Kickstart
Dojo >= 1.7  KickstartDojo >= 1.7  Kickstart
Dojo >= 1.7 Kickstart
 
Working with c++ legacy code
Working with c++ legacy codeWorking with c++ legacy code
Working with c++ legacy code
 
iOS training (basic)
iOS training (basic)iOS training (basic)
iOS training (basic)
 
Jailbreak Detector Detector
Jailbreak Detector DetectorJailbreak Detector Detector
Jailbreak Detector Detector
 
Android Dev Study Jam.pptx
Android Dev Study Jam.pptxAndroid Dev Study Jam.pptx
Android Dev Study Jam.pptx
 
Dependency injectionpreso
Dependency injectionpresoDependency injectionpreso
Dependency injectionpreso
 
IOS debugging
IOS debuggingIOS debugging
IOS debugging
 
ONE MORE TIME ABOUT CODE STANDARDS AND BEST PRACTICES
ONE MORE TIME ABOUT CODE STANDARDS AND BEST PRACTICESONE MORE TIME ABOUT CODE STANDARDS AND BEST PRACTICES
ONE MORE TIME ABOUT CODE STANDARDS AND BEST PRACTICES
 
Supercharge Flutter declarative UI with code generation
Supercharge Flutter declarative UI with code generationSupercharge Flutter declarative UI with code generation
Supercharge Flutter declarative UI with code generation
 
Android Dev Study Jam.pptx
Android Dev Study Jam.pptxAndroid Dev Study Jam.pptx
Android Dev Study Jam.pptx
 
AngularJS Architecture
AngularJS ArchitectureAngularJS Architecture
AngularJS Architecture
 
AngularJS Internal
AngularJS InternalAngularJS Internal
AngularJS Internal
 
Android | Busy Java Developers Guide to Android: Persistence | Ted Neward
Android | Busy Java Developers Guide to Android: Persistence | Ted NewardAndroid | Busy Java Developers Guide to Android: Persistence | Ted Neward
Android | Busy Java Developers Guide to Android: Persistence | Ted Neward
 
.NET Coding Standards For The Real World (2012)
.NET Coding Standards For The Real World (2012).NET Coding Standards For The Real World (2012)
.NET Coding Standards For The Real World (2012)
 

Mais de Carl Brown

GDPR, User Data, Privacy, and Your Apps
GDPR, User Data, Privacy, and Your AppsGDPR, User Data, Privacy, and Your Apps
GDPR, User Data, Privacy, and Your AppsCarl Brown
 
New in iOS 11.3b4 and Xcode 9.3b4
New in iOS 11.3b4 and Xcode 9.3b4New in iOS 11.3b4 and Xcode 9.3b4
New in iOS 11.3b4 and Xcode 9.3b4Carl Brown
 
Managing Memory in Swift (Yes, that's a thing)
Managing Memory in Swift (Yes, that's a thing)Managing Memory in Swift (Yes, that's a thing)
Managing Memory in Swift (Yes, that's a thing)Carl Brown
 
Better Swift from the Foundation up #tryswiftnyc17 09-06
Better Swift from the Foundation up #tryswiftnyc17 09-06Better Swift from the Foundation up #tryswiftnyc17 09-06
Better Swift from the Foundation up #tryswiftnyc17 09-06Carl Brown
 
Generics, the Swift ABI and you
Generics, the Swift ABI and youGenerics, the Swift ABI and you
Generics, the Swift ABI and youCarl Brown
 
Swift GUI Development without Xcode
Swift GUI Development without XcodeSwift GUI Development without Xcode
Swift GUI Development without XcodeCarl Brown
 
what's new in iOS10 2016-06-23
what's new in iOS10 2016-06-23what's new in iOS10 2016-06-23
what's new in iOS10 2016-06-23Carl Brown
 
Open Source Swift: Up and Running
Open Source Swift: Up and RunningOpen Source Swift: Up and Running
Open Source Swift: Up and RunningCarl Brown
 
Parse migration CocoaCoders April 28th, 2016
Parse migration CocoaCoders April 28th, 2016Parse migration CocoaCoders April 28th, 2016
Parse migration CocoaCoders April 28th, 2016Carl Brown
 
Swift 2.2 Design Patterns CocoaConf Austin 2016
Swift 2.2 Design Patterns CocoaConf Austin 2016Swift 2.2 Design Patterns CocoaConf Austin 2016
Swift 2.2 Design Patterns CocoaConf Austin 2016Carl Brown
 
Advanced, Composable Collection Views, From CocoaCoders meetup Austin Feb 12,...
Advanced, Composable Collection Views, From CocoaCoders meetup Austin Feb 12,...Advanced, Composable Collection Views, From CocoaCoders meetup Austin Feb 12,...
Advanced, Composable Collection Views, From CocoaCoders meetup Austin Feb 12,...Carl Brown
 
Cocoa coders 141113-watch
Cocoa coders 141113-watchCocoa coders 141113-watch
Cocoa coders 141113-watchCarl Brown
 
iOS8 and the new App Store
iOS8 and the new App Store   iOS8 and the new App Store
iOS8 and the new App Store Carl Brown
 
Dark Art of Software Estimation 360iDev2014
Dark Art of Software Estimation 360iDev2014Dark Art of Software Estimation 360iDev2014
Dark Art of Software Estimation 360iDev2014Carl Brown
 
Intro to cloud kit Cocoader.org 24 July 2014
Intro to cloud kit   Cocoader.org 24 July 2014Intro to cloud kit   Cocoader.org 24 July 2014
Intro to cloud kit Cocoader.org 24 July 2014Carl Brown
 
Welcome to Swift (CocoaCoder 6/12/14)
Welcome to Swift (CocoaCoder 6/12/14)Welcome to Swift (CocoaCoder 6/12/14)
Welcome to Swift (CocoaCoder 6/12/14)Carl Brown
 
Writing Apps that Can See: Getting Data from CoreImage to Computer Vision - ...
Writing Apps that Can See: Getting Data from CoreImage to Computer  Vision - ...Writing Apps that Can See: Getting Data from CoreImage to Computer  Vision - ...
Writing Apps that Can See: Getting Data from CoreImage to Computer Vision - ...Carl Brown
 
Introduction to Git Commands and Concepts
Introduction to Git Commands and ConceptsIntroduction to Git Commands and Concepts
Introduction to Git Commands and ConceptsCarl Brown
 
REST/JSON/CoreData Example Code - A Tour
REST/JSON/CoreData Example Code - A TourREST/JSON/CoreData Example Code - A Tour
REST/JSON/CoreData Example Code - A TourCarl Brown
 

Mais de Carl Brown (20)

GDPR, User Data, Privacy, and Your Apps
GDPR, User Data, Privacy, and Your AppsGDPR, User Data, Privacy, and Your Apps
GDPR, User Data, Privacy, and Your Apps
 
New in iOS 11.3b4 and Xcode 9.3b4
New in iOS 11.3b4 and Xcode 9.3b4New in iOS 11.3b4 and Xcode 9.3b4
New in iOS 11.3b4 and Xcode 9.3b4
 
Managing Memory in Swift (Yes, that's a thing)
Managing Memory in Swift (Yes, that's a thing)Managing Memory in Swift (Yes, that's a thing)
Managing Memory in Swift (Yes, that's a thing)
 
Better Swift from the Foundation up #tryswiftnyc17 09-06
Better Swift from the Foundation up #tryswiftnyc17 09-06Better Swift from the Foundation up #tryswiftnyc17 09-06
Better Swift from the Foundation up #tryswiftnyc17 09-06
 
Generics, the Swift ABI and you
Generics, the Swift ABI and youGenerics, the Swift ABI and you
Generics, the Swift ABI and you
 
Swift GUI Development without Xcode
Swift GUI Development without XcodeSwift GUI Development without Xcode
Swift GUI Development without Xcode
 
what's new in iOS10 2016-06-23
what's new in iOS10 2016-06-23what's new in iOS10 2016-06-23
what's new in iOS10 2016-06-23
 
Open Source Swift: Up and Running
Open Source Swift: Up and RunningOpen Source Swift: Up and Running
Open Source Swift: Up and Running
 
Parse migration CocoaCoders April 28th, 2016
Parse migration CocoaCoders April 28th, 2016Parse migration CocoaCoders April 28th, 2016
Parse migration CocoaCoders April 28th, 2016
 
Swift 2.2 Design Patterns CocoaConf Austin 2016
Swift 2.2 Design Patterns CocoaConf Austin 2016Swift 2.2 Design Patterns CocoaConf Austin 2016
Swift 2.2 Design Patterns CocoaConf Austin 2016
 
Advanced, Composable Collection Views, From CocoaCoders meetup Austin Feb 12,...
Advanced, Composable Collection Views, From CocoaCoders meetup Austin Feb 12,...Advanced, Composable Collection Views, From CocoaCoders meetup Austin Feb 12,...
Advanced, Composable Collection Views, From CocoaCoders meetup Austin Feb 12,...
 
Gcd cc-150205
Gcd cc-150205Gcd cc-150205
Gcd cc-150205
 
Cocoa coders 141113-watch
Cocoa coders 141113-watchCocoa coders 141113-watch
Cocoa coders 141113-watch
 
iOS8 and the new App Store
iOS8 and the new App Store   iOS8 and the new App Store
iOS8 and the new App Store
 
Dark Art of Software Estimation 360iDev2014
Dark Art of Software Estimation 360iDev2014Dark Art of Software Estimation 360iDev2014
Dark Art of Software Estimation 360iDev2014
 
Intro to cloud kit Cocoader.org 24 July 2014
Intro to cloud kit   Cocoader.org 24 July 2014Intro to cloud kit   Cocoader.org 24 July 2014
Intro to cloud kit Cocoader.org 24 July 2014
 
Welcome to Swift (CocoaCoder 6/12/14)
Welcome to Swift (CocoaCoder 6/12/14)Welcome to Swift (CocoaCoder 6/12/14)
Welcome to Swift (CocoaCoder 6/12/14)
 
Writing Apps that Can See: Getting Data from CoreImage to Computer Vision - ...
Writing Apps that Can See: Getting Data from CoreImage to Computer  Vision - ...Writing Apps that Can See: Getting Data from CoreImage to Computer  Vision - ...
Writing Apps that Can See: Getting Data from CoreImage to Computer Vision - ...
 
Introduction to Git Commands and Concepts
Introduction to Git Commands and ConceptsIntroduction to Git Commands and Concepts
Introduction to Git Commands and Concepts
 
REST/JSON/CoreData Example Code - A Tour
REST/JSON/CoreData Example Code - A TourREST/JSON/CoreData Example Code - A Tour
REST/JSON/CoreData Example Code - A Tour
 

Último

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
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
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
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
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
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
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
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
 
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
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
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
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 

Último (20)

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
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
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
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
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
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.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
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
 
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
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
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
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 

360iDev iOS AntiPatterns

  • 1. "Stop it! That Hurts!" Common iOS Anti-Patterns @CarlBrwn Carl Brown Missing final vowel (blame Flickr) 2012
  • 2. ObBio Carl Brown (@CarlBrwn) iOS Contractor Teach Intro to iOS classes Co-Organizer CocoaCoder.org Started Mobile Programming 2004 (Palm) Half of team (Nov. '08) that wrote LIVESTRONG.com Calorie Tracker 2012
  • 3. ObBio Carl Brown (@CarlBrwn) iOS Contractor Teach Intro to iOS classes Co-Organizer CocoaCoder.org Started Mobile Programming 2004 (Palm) Half of team (Nov. '08) that wrote LIVESTRONG.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 line Singletons ([Class sharedInstance]) 2012
  • 10. Not "Bad Code"? At least for purposes of this talk... Braces for 'if' on next line Singletons ([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 line Singletons ([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 line Singletons ([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 line Singletons ([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 enums General Programming 101 Stuff 2012
  • 15. Notice: All of the code you are about to see is real. All of it was either released to users, sold for real money or posted online. Variable names have been changed to protect the guilty. Some has been edited for brevity. 2012
  • 16. Bad Code while (self && [self retainCount] >= 0) { [self release]; } ///Carl's 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]; } ///Carl's 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]; } ///Carl's 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]; } ///Carl's 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]; } ///Carl's 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 Code Completely Useless 2012
  • 23. Tier1: D.U.I. Developing Under the Influence http://xkcd.com/323/ 2012
  • 25. Tier 1: Rage Against the Machine 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; // throws EDAMUserException *, EDAMSystemException *, EDAMNotFoundException *, TException 2012
  • 28. Method Naming - (EDAMNote *) getNote: (NSString *) authenticationToken : (EDAMGuid) guid : (BOOL) withContent : (BOOL) withResourcesData : (BOOL) withResourcesRecognition : (BOOL) withResourcesAlternateData; // throws EDAMUserException *, EDAMSystemException *, EDAMNotFoundException *, TException @selector(getNote::::::) 2012
  • 29. Class Naming @interface SettingsView : UIViewController <UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate> 2012
  • 30. Don't re-init existing objects NSArray *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 don't 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 don't 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 Style if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) if ([[UIImagePickerController availableMediaTypesForSourceType: picker.sourceType] containsObject: kUTTypeMovie]) self.cameraButton.hidden = NO; 2012
  • 34. Coding Style if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) self.title = @"Event Info"; if ([[UIImagePickerController availableMediaTypesForSourceType: picker.sourceType] containsObject: kUTTypeMovie]) self.cameraButton.hidden = NO; 2012
  • 35. Coding Style if ([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, don't 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 Apple's 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 I'm going to do several times things that have non-trivial complexity 2012
  • 49. Operation vs Dispatch I tend to use NSOperations for: things I'm 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 won't 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 Stuff NSDateFormatter *dateFormatter = [NSDateFormatter new]; monthsArray = [dateFormatter monthSymbols]; Use NSDateFormatters. But not too many. 2012
  • 56. Careful with Caching fetcher = [fetcherMap objectForKey:@"type"]; if (!fetcher) { fetcher = [[Fetcher alloc] init]; [fetcherMap setValue:fetcher forKey:@"type"]; [fetcher release]; } [ fetcher fetchPicturesForDelegate:self callbackMethod:@selector(picsFound:error:)]; Where's the (intermittent) crash here? 2012
  • 57. Careful with Caching fetcher = [ 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 Caching fetcher = [ 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. Don't Cache That Way That's 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. Tags UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; UILabel *dateLabel = (UILabel *)[cell viewWithTag:1]; UIView *imageBackground = (UIView *)[cell viewWithTag:2]; UIImageView *thumbnail = (UIImageView *)[cell viewWithTag:3]; 2012
  • 62. Tags UITableViewCell *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. Don't "Remember" Core Data Results - (void)viewDidLoad { self.results = [self.fetchedResultsController fetchedObjects]; ! //or self.results = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { cell.textLabel.text = [[self.results objectAtIndex:indexPath.row] name]; 2012
  • 67. Ask the NSFetchedResultsController - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { cell.textLabel.text = [self.fetchedResultsController objectAtIndexPath:indexPath]; 2012
  • 68. Don't mix read-only and read-write data Imagine an App that downloads bulk data like phonebooks or store locations or SKUs 2012
  • 69. Don't mix read-only and read-write data Imagine an App that downloads bulk data like phonebooks or store locations or SKUs Now imagine that App also lets the local user comment/favorite/rate/ review those entries 2012
  • 70. Don't mix read-only and read-write data Imagine an App that downloads bulk data like phonebooks or store locations or SKUs Now imagine that App also lets the local user comment/favorite/rate/ review those entries Now imagine that every time you updated 400K records, you had to preserve local modifications... 2012
  • 71. NSOperations have Overhead NSOperationQueue *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-offs dispatch_async(dispatch_get_global_queue(DISPATCH_ QUEUE_PRIORITY_BACKGROUND, 0), ^{ [self performSelector:@selector(doSomeThing)]; }); 2012
  • 73. "Tier 3" Bad Code "It's a Trap!!" 2012
  • 74. "Tier 3" Bad Code "It's a Trap!!" 2012
  • 75. This is my scariest slide 2012
  • 76. This is my scariest slide 2012
  • 78. Three20 cont. the new Facebook for iOS marks our first release in years without the Three20 framework.  https://www.facebook.com/notes/facebook-engineering/ under-the-hood-rebuilding-facebook-for-ios/10151036091753920 2012
  • 79. asi-http-request After giving it a lot of thought over the last few weeks, I’ve decided that I’m not going to continue working on ASIHTTPRequest 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 Code NSAssert(![NSThread isMainThread], @"BOOM"); 2012
  • 83. "Rocket Engine" for Responsive Code NSAssert(![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 Don't Delete & Recreate Subviews that Already Exist 2012
  • 86. MVC Model 2012
  • 87. MVC Model Controller View 2012
  • 88. NMVC Network Model (or at least "Disk") Controller View 2012
  • 89. NMVC Network 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 Summary Program Sober and Rested, If Possible Leave Other Languages' Patterns at the Door Program Idiomatically Don't Fight the Frameworks Read the Fine Print Look for Hidden Bugs 2012
  • 95. Thank You CarlB@PDAgent.com @CarlBrwn 2012

Notas do Editor

  1. Start ScreenFlow and Camera!!!\n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. Often, this is just code written by stupid people\n
  23. Developing Under the Influence...\n
  24. But there&apos;s not a lot we can learn from looking at Tier1 Badness, so on to...\n
  25. \n
  26. Useful Somewhere, but not Here\n
  27. This is from one of my favorite public APIs to pick on: Evernote\n
  28. Please don&apos;t name your ViewControllers &quot;SomethingView&quot;\n
  29. \n
  30. \n
  31. This was a fun bug I had to chase down.\nI&apos;m pretty sure the original file looked like this\n
  32. And then I think this happened\n
  33. Which resulted in this file, which would sometimes present the camera button on devices without the camera, which would then crash if clicked.\n
  34. \n
  35. \n
  36. So Imagine there&apos;s a framework for saving a file\n
  37. \n
  38. \n
  39. \n
  40. So Imagine there&apos;s a framework for saving a file\n
  41. \n
  42. \n
  43. iOS app for company with multi-billion dollar market cap.\n
  44. \n
  45. But, it could be worse. This was a Flash programmer on a video uploading app.\n\nApparently, Flash doesn&apos;t do threads...\n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. In this case, fetcherMap was nil, so it would occasionally crash\n
  55. In this case, fetcherMap was nil, so it would occasionally crash\n
  56. In this case, fetcherMap was nil, so it would occasionally crash\n
  57. \n
  58. Apparently Useful, but not practically so\n
  59. So much for type safety\n
  60. MKMapViewDelegate Needed when user taps button on Callout on MapView \n
  61. MKMapViewDelegate Needed when user taps button on Callout on MapView \n
  62. MKMapViewDelegate Needed when user taps button on Callout on MapView \n
  63. MKMapViewDelegate Needed when user taps button on Callout on MapView \n
  64. 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
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. No matter what you think about this spider...\n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. \n
  80. \n
  81. 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
  82. \n
  83. Network talks to the model, not the controller\n
  84. Network talks to the model, not the controller\n
  85. Network talks to the model, not the controller\n
  86. Network talks to the model, not the controller\n
  87. Network talks to the model, not the controller\n
  88. Network talks to the model, not the controller\n
  89. Network talks to the model, not the controller\n
  90. Network talks to the model, not the controller\n
  91. \n
  92. \n
  93. \n
  94. \n
  95. 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
  96. \n