2011年7月7日 星期四

Stanford CS193P Note-04

View-based Application

main.m
    1. Basically just the C entry point function int main(int argc, char *argv[])
    2. Calls UIApplicationMain which creates a UIApplication object and starts the
       run loop
    3. Also creates a catch-all autorelease pool

MainWindow.xib
    1. Contains a UIWindow (top of the view hierarchy) for things to be installed in
    2. Contains the Application Delegate
       (just an NSObject with its class set to xxxAppDelegate)
    3. Application Delegate also has a couple of outlets wired up
       (notably to xxxViewController)
  
◎ xxx-Info.plist
    A variety of application configuration properties

◎ xxxAppDelegate.[mh]
   1. Has an instance variable for the UIWindow in MainWindow.xib called window.
   2. Has an instance variable for xxxViewController called viewController.
   3. Has stubs for a lot of applicationDidThis and applicationWillDoThat.
   4. Most importantly application:didFinishLaunchingWithOptions:.
      (1). This is the method where xxxViewController's view is added to the UIWindow.
      (2). Also where the UIWindow is made visible ... [window makeKeyAndVisible]
     
-----------------------------------------------------------------------------------------------------

Application Lifecycle


◎ After application:didFinishLaunchingWithOptions:, then what?
    Application enters a "run loop" repeatedly doing the following ...
    1. An autorelease pool is created
    2. Application waits for events (touch, timed event, I/O, etc.)
    3. Events are dispatched through UIKit objects and often on to your objects
       (via delegates, etc.)
    4. When all is done, the screen is updated
       (appropriate drawRect: methods are called)
    5. The autorelease pool is drained

    Rinse, repeat.
-----------------------------------------------------------------------------------------------------

View Controller

VERY important property in UIViewController
    @property (retain) UIView *view;
    This is a pointer to the top-level UIView in the Controller's View (in MVC terms)
After the UIViewController is initialized, viewDidLoad is called
    - (void)viewDidLoad;
    1. This is an exceptionally good place to put a lot of setup code.
    2. But be careful because the geometry of your view (its bounds) is not set yet.

Just before the view appears on screen, you get notified
    - (void)viewWillAppear:(BOOL)animated;
    1. When this is called, your bounds has been set
       (via your frame by your superview or some such).
    2. Your view will probably only get "loaded" once, but it might appear and
       disappear a lot.
    3. So don't put something in this method that really wants to be in viewDidLoad.

You already know about viewDidUnload
    - (void)viewDidUnload;
    1. Called in low-memory situations.
    2. Be sure to release your outlets
       (or other data tied to the view and its subviews) here.

-----------------------------------------------------------------------------------------------------

IBOutlet Memory Management

◎ set outlets to be private & do't call your outlet's "setter" from dealloc

   //
interface
   @interface MyVC : UIViewController {
       IBOutlet UILabel *outlet;
   }
   @end

   // implementation
   @interface MyVC()
   @property (retain) IBOutlet UILabel *outlet;
   @end

   @implementation MyVC
   @synthesize outlet;
   - (void)viewDidUnload {
      
self.outlet = nil;
       [self releaseOutlets];
   }
   - (void)dealloc {
       [outlet release];
       [self releaseOutlets];
       [super dealloc];
   }

  //@add
  - (void)releaseOutlets {
     
self.outlet = nil;
  }
   @end
-----------------------------------------------------------------------------------------------------

Memory Management

Alarm should go off in your head when you type alloc/copy/new
    You should immediately drop everything and go figure out where this object
    will be released
    1. If it's an instance variable, probably you're looking at dealloc
    2. If it's a local variable, release it as soon as you're done using it
       (at least just before return)
    3. If it's a local variable that you are returning, autorelease it
Go immutable! // 儘量使用不可修改的
    It's simpler and less error-prone than allocing a mutable object, modifying it,
    then releaseing it
◎ Try to use methods other than alloc/copy/new
    // Fine:
    - (NSDictionary *)testVariableValues {
        NSMutableDictionary *returnValue = [[NSMutableDictionary alloc] init];
        [returnValue setObject:[NSNumber numberWithFloat:3.5] forKey:@"x"];
        [returnValue setObject:[NSNumber numberWithFloat:23.8] forKey:@"y"];
        return [returnValue autorelease]; // set
autorelease
    }

    // Better:
    - (NSDictionary *)testVariableValues {
       
// autorelease
        NSMutableDictionary *returnValue = [NSMutableDictionary dictionary];

        [returnValue setObject:[NSNumber numberWithFloat:3.5] forKey:@"x"];
        [returnValue setObject:[NSNumber numberWithFloat:23.8] forKey:@"y"];
        return returnValue;
    }

    // Best:
    - (NSDictionary *)testVariableValues {
       
       
// immutable & autorelease
        return [NSDictionary dictionaryWithObjectsAndKeys: 
               [NSNumber numberWithFloat:3.5], @"x",
               [NSNumber numberWithFloat:23.8], @"y",
               nil];

    }

◎ But don't abuse autorelease by creating a huge pool
    // Bad:
    - (NSString *)tenThousandGs {
        NSString *s = "";
        for (int i = 0; i < 10000; i++)
            s = [s stringByAppendingString:@"G"]; // 10000 個
autorelease
        return s;
    }

    // Good:
    - (NSString *)tenThousandGs {
        NSMutableString *s = [[NSMutableString alloc] init];
        for (int i = 0; i < 10000; i++)
            [s appendString:@"G"];
        return [s autorelease];
    }

    // Best:
    - (NSString *)tenThousandGs {
       
NSMutableString *s = [NSMutableString string]; // 產生 autorelease 的 obj
        for (int i = 0; i < 10000; i++)
            [s appendString:@"G"];
        return s;

    }

3 則留言:

  1. 我覺得這段有點疑問,
       - (void)viewDidUnload {
           self.outlet = nil;
       }
       - (void)dealloc {
           [outlet release];
           [super dealloc];
    }
    因為 outlet 已設為 nil ,再 release 已無意義,應在設為 nil 之前先呼叫一次 release 以便釋放記憶體。

    回覆刪除
  2. 嗯, 在 dealloc 裡, 直接 release outlet, 是有可能造成 crash.
    原始內容是建議在 dealloc 裡, 也將 outlet 設為 nil 即可.

    回覆刪除

注意:只有此網誌的成員可以留言。