作為每個初學者99.9%會接觸到的UIViewController,這篇文章主要來講講UIViewController的生命周期。
我們從一個例子來證明這個結論:
如下是storyBoard的配置:
ViewController.m
@interface ViewController ()
@property (nonatomic,strong)NSString *str;
@property (weak, nonatomic) IBOutlet UIButton *button;
@end
下面是生命周期有關的方法:
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
NSLog(@"0");
}
return self;
}
-(void)awakeFromNib{
NSLog(@"1");
}
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"2");
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSLog(@"3");
}
-(void)viewWillLayoutSubviews{
NSLog(@"4");
}
-(void)viewDidLayoutSubviews{
NSLog(@"5");
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
NSLog(@"6");
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
NSLog(@"7");
}
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
NSLog(@"8");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
運行后點擊按鈕跳轉到第二個控制器,打印如下:
2015-03-24 00:00:44.771 test[2925:305854] 0
2015-03-24 00:00:44.772 test[2925:305854] 1
2015-03-24 00:00:44.778 test[2925:305854] 2
2015-03-24 00:00:44.779 test[2925:305854] 3
2015-03-24 00:00:44.785 test[2925:305854] 4
2015-03-24 00:00:44.785 test[2925:305854] 5
2015-03-24 00:00:44.788 test[2925:305854] 6
2015-03-24 00:00:47.982 test[2925:305854] 7
2015-03-24 00:00:47.987 test[2925:305854] 4
2015-03-24 00:00:47.988 test[2925:305854] 5
2015-03-24 00:00:48.489 test[2925:305854] 8
也就是說,ViewController的生命周期基本是下面的步驟:
Instantiated :初始化
awakeFromNib:主要做一些viewDidLoad之前的事情
outlets 的配置
viewDidLoad
viewWillLayoutSubviews和viewDidLayoutSubviews:
viewWillAppear和viewDidAppear
viewWillDisappear: and viewDidDisappear
didReceiveMemoryWarning:收到內存警告
現在不存在“unload”方法
你可能會問為什么outlets 的配置介于awakeFromNib和viewDidLoad之間呢,我們可以通過下面的代碼證實一下:
-(void)awakeFromNib{
NSLog(@"1");
[_button setTitle:@"哈哈" forState:UIControlStateNormal];
}
運行結果發現按鈕的標題并沒有發生變化,我們再看:
- (void)viewDidLoad {
[super viewDidLoad];
[_button setTitle:@"呵呵" forState:UIControlStateNormal];
NSLog(@"2");
}
運行結果發現按鈕的標題發生變化了,所以可以知道outlets 的配置是介于awakeFromNib和viewDidLoad,這點比較重要。
1.initWithCoder ,
關于initWithCoder ,你是不是覺得它更應該出現在數據持久化中呢?確實它是一個NSCoding protocol, 所以你在UIViewController的文檔中不會找到它。initWithCoder 是一個類在IB中創建但在xocde中被實例化時被調用的。你可以理解為是一個解固過程,所以在這個時候view還沒初始化,你可以完成一些需要在view未初始化之前調用的方法。注意這個方法在生命周期中只會調用一次。
2.awakeFromNib
當.nib文件或storyBoard文件被加載的時候,會發送一個awakeFromNib的消息到.nib文件或storyBoard文件中的每個對象,每個對象都可以定義自己的awakeFromNib函數來響應這個消息,執行一些必要的操作。也就是說通過nib文件創建view對象時執行awakeFromNib
如果你不是從.nib文件或storyBoard文件中加載view,你可以在loadView方法通過代碼初始化view。
3.viewWillLayoutSubviews和viewDidLayoutSubviews
viewWillAppear和viewDidAppear前會調用改方法,主要是和布局相關。在當幾何方向改變時也會再次調用以下方法,例如旋轉方向變化。
(當選擇方向改變還會收到 will/didRotateTo/From messages)
再說下可能會看到的initWithNibName 和 loadNibNamed。
主要是用于加載子view,使用此方法加載用戶界面(xib文件)到我們的代碼中,這樣,可以通過操作這個加載進來的(xib)對象,來操作xib文件內容。 它們之間的區別是initWithNibName方法:是延遲加載,這個View上的控件是 nil 的,只有到 需要顯示時,才會不是 nil 。
loadNibNamed方法:即時加載,用該方法加載的xib對象中的各個元素都已經存在。
- (void)submitShare:(id)sender
{
if (![self checkInputContentLegal]) {
return;
}
[_textView resignFirstResponder];
if (!_locationEnable) {//如果不顯示地理位置
_latitude = 0;
_longtitude = 0;
NSLog(@"不顯示地理位置");
}else{
NSLog(@"顯示地理位置,%f,%f",_latitude,_longtitude);
}
NSString *accseeToken = [AccountTool sharedAccountTool].account.accessToken;
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:kUploadURL]];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
__weak typeof(self) weakSelf = self;
NSString *encodeStatus = _textView.text;
if (_images.count == 0) {
[manager POST:@"2/statuses/update.json"
parameters:@{@"access_token": accseeToken,
@"status" : encodeStatus,
@"visible" : @(_intVisible),
@"lat" : @(_latitude),
@"long" : @(_longtitude)}
success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"發送成功");
[self showSuccessHUD];
[self performSelector:@selector(back) withObject:self afterDelay:1.5];
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
[self showFailHUD];
NSLog(@"發送失敗");
}];
}else{
[manager POST:@"2/statuses/upload.json"
parameters:@{@"access_token": accseeToken,
@"status" : encodeStatus,
@"visible" : @(_intVisible),
@"lat" : @(_latitude),
@"long" : @(_longtitude)}
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
NSMutableArray *images = [NSMutableArray arrayWithArray:weakSelf.images];
for (id asset in images) {
NSData *data = nil;
if ([asset isKindOfClass:[UIImage class]]) {
data = UIImageJPEGRepresentation(asset, 0.4);
}
if ([asset isKindOfClass:ALAsset.class]) {
UIImage *original = [UIImage imageWithCGImage: [[asset defaultRepresentation] fullScreenImage]];
data = UIImageJPEGRepresentation(original, 0.4);
}
[formData appendPartWithFileData:data name:@"pic" fileName:@"pic.jpg" mimeType:@"multipart/form-data"];
//新浪開放的API一次只能上傳一張圖片,選擇多張的時候會使用最后一張,通過調用[http://open.weibo.com/wiki/2/statuses/upload_pic]() 接口生成高級接口statuses/upload_url_text中的參數pic_id,可以實習上傳多張圖片
}
} success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"發送成功");
[self back];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[self showFailHUD];
}];
}
}