GeekBand Objective-C編程語言學習筆記(第一周)

第一天視頻課程:


Objective-C 語言簡介

Objective-C 語言是一門在C語言基礎上做了面向對象擴展的編程語言,1983年由Brad Cox 和Tom Love發明,是目前蘋果開發平臺的主力語言,與Cocoa 和Cocoa Touch框架高度集成,支持開發Mac OS X、iOS應用。在蘋果開發平臺上通過LLVM(LowLevelVirtualMachine)編譯器架構支持與Swift語言雙向互操作。


iOS開發平臺

Cocoa框架部分包括了系統內核(Core OS)、內核服務(Core Service)、媒體(Media)、觸摸(Cocoa Touch)這幾個內庫。通過LLVM編譯框架和Objective-C運行時編譯和運行。目前主要有Objective-C、Swift和C/C++這幾種語言來進行編碼,常用的開發工具為Xcode。


掌握高級編程語言的思維方式

底層思維:從微觀、機器的層面理解語言的構造、編譯轉換、內存模型和運行時機制。

抽象思維:將我們周圍世界抽象為程序代碼,即面向對象的思維方式,組件封裝、設計模式、架構模式。


“時空人”三位一體分析方法

時間分析,發生在什么時候?編譯時還是運行時。

空間分析,變量放在那里?堆空間還是??臻g。

人物分析,代碼哪里來的?程序員還是編譯器、運行時、框架。


Objective-C 語言的兩種開發方式

Clang 或 GCC命令行:適合調試、研究、微觀探查。

Xcode項目:適合構建正規工程項目,使用大型框架,追求設計質量與代碼組織。


Objective-C 語言代碼學習

#import 導入頭文件(類似C語言的#include),可以避免相同頭文件的重復導入,推薦使用#import代替#include。

@autoreleasepool 支持ARC(Automatic Reference Counting)的一個池,用來表明啟用了內存自動回收機制。

NSlog(@"Hello,world!"); NSlog類似C語言里的printf用來打印字符串,OC語言里的字符串前需要加@符號(@"Hello,world!")。

?頭文件的擴展名是.h,主程序文件的擴展名是.m

編譯命名行:clang -fobjc-arc HelloWorld.m -o HelloWorld其中-fobjc-arc為ARC內存管理的開關命名,其中-o HelloWorld,-o 為output即輸出的意思,一起為將輸出的文件命名為HelloWorld。clang也可以換成gcc即用gcc編譯器編譯。(推薦用clang)

命名行:clang -help 用來顯示clang的設置幫助文檔,可以用來了解clang的設置。

命名行:./HelloWorld 執行生成的HelloWorld文件。


ObjC編譯過程

目前主流為LLVM-Clang的編譯過程,由OC、C\C++代碼通過Clang前端再通過LLVM優化和LLVM代碼生成器生成出X86-64機器碼。


學習資源

蘋果官方文檔:https://developer.apple.com/library/

programming with Objective-C: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/

iOS專區:https://developer.apple.com/library/ios/

蘋果開發者大會WWDC:https://developer.apple.com/videos/wwdc/2014/

??????????????????????WWDC:https://developer.apple.com/videos/wwdc/2015/


第二天視頻課程:


類型系統


引用類型 reference type:包括class、pointer、block。

值類型 value type:包括基礎數值類型、結構struct、枚舉enum。

類型裝飾:包括協議protocol、類別category、擴展extension


類 class VS. 結構 struct

類型與實例:類的實例是對象,結構的實例是值。

類是一個引用類型,是位于棧上的指針指向了一個位于堆上的實體對象。

結構是一個值類型,它直接位于棧中。

例子1:聲明一個類(建立一個對外接口)

@interface RPoint:NSObject? //聲明一個類,類名RPoint,繼承自類NSObject。:表示繼承。

@property int x; //聲明一個屬性 int X

@property int y;

-(void)print; //聲明一個實例方法 print

@end

在OC中創建類時要先在頭文件中(.h)創建一個對外借口,@interface來表示對外接口的起始,用@end來對應結束。

@property 在類中定義屬性的關鍵字,用來表示這個類的狀態。

-(void)print 是在類中定義方法的語句,其中-表示是一個實例方法,方法的返回值是void,方法的名字是print.類中的方法來表示這個類的行為。

例子2:實現一個類

#import<Foundation/Foundation.h> //導入Foundation.h頭文件

#import"rpoint.h" //導入rpoint.h頭文件,即上面我們創建的類聲明文件。

@implementation RPoint? //定義一個類名為RPoint?的類

-(void)print{

NSLog(@"[%d,%d]", self.x, self.y);? //print方法的實現

}

@end

OC的類需要在主文件中(.m)實現,@implementation 來表示實現的起始,用@end來對應結束。

NSLog(@"[%d,%d]", self.x, self.y);? NSLog表示打印一個字符串,self表示當前的事例,整句語句表示將當前事例的屬性x和y打印出來。

例子3:

#import<Foundation/Foundation.h>

#import"rpoint.h" //導入類所在的文件

#import"spoint.h"? //導入結構體所在的文件

void process(RPoint* rp3, SPoint sp3); //函數process的聲明

int main(int argc, const char * argv[]){ //入口函數

??? @autoreleasepool{

????? RPoint* rp1=[[RPoint alloc]init]; //生成一個RPoint類的對象rp1

????? rp1.x=10;

????? rp1.y=20;

????? [rp1 print]; //顯示結果為10, 20

????? SPoint sp1; //生成一個SPoint結構體實例。

????? sp1.x=10;

????? sp2.y=20;

????? NSLog(@"拷貝----------");

????? RPoint* rp2=rp1;

????? rp2.x++;

????? rp2.y++;

????? [rp1 print]; //顯示結果為11, 21

????? [rp2 print]; //顯示結果為11, 21

????? SPoint sp2=sp1;

????? sp2.x++;

????? sp2.y++;

????? NSLog(@"[%d,%d]",sp1.x, sp1.y);?//顯示結果為10, 20

????? NSLog(@"[%d,%d]",sp2.x, sp2.y); //顯示結果為11, 21

????? NSLog(@"傳參----------")

????? process(rp1, sp1);

????? [rp1 print]; //顯示結果為12, 22

????? NSLog(@"[%d,%d]",sp1.x, sp1.y); //顯示結果為10, 20

??? }

??? return0;

}

void process(RPoint* rp3, SPoint sp3){

? rp3.x++;

? rp3.y++;

? sp3.x++;

? sp3.y++;

? [rp3 print];

? NSLog(@"[%d,%d]",sp3.x, sp3.y);

}

RPoint* rp1=[[RPoint alloc] init]; //在內存??臻g創建了一個名字為rp1的RPpoint類實例對象。[]為調用符號,調用也可以稱為發送消息。alloc的用處是手動在堆空間申請內存空間,init為初始化所分配的空間。


拷貝行為內存視圖


傳參行為內存視圖

堆(heap):堆空間用于存儲引用類型對象,由程序員手動申請內存空間,釋放由運行時ARC機制自動釋放,函數之間通過拷貝引用(指針)傳遞。堆空間具有全局性,總體大小受制于系統內存整體大小。

由于rp1是一個類的實例對象,所以無論是復制還是傳參,都是由一個棧中的指針指向堆中的實體對象,復制副本和傳參參數的改變都能直接導致rp1指向的實際對象發生改變。

SPoint sp1; //在內存的堆空間創建了一個名字為sp1的結構體。

棧(stack):??臻g用于存儲值類型,無ARC負擔,由系統自動管理,以執行函數為單位。棧的空間大小在編譯時確定(根據參數+局部變量來計算),在函數執行時由系統自動分配一個棧,函數執行結束系統立即自動收回該棧空間,函數之間通過拷貝值傳遞。棧空間具有局部性,大小有限額(編譯工具可以設定棧的大小,一般為1M),超出會棧溢出(stack overflow)。

由于sp1是一個結構值,它存儲于棧中,無論復制還是傳參,都將在棧中復制一個sp1的副本,sp1的原始值保持不變。


第三天視頻課程:


OC類的類型成員

OC類所包含的類型成員(Type Member)主要分為兩大類,一類是數據成員(data member)用來描述對象的狀態,還有一類是函數成員(function member)用來描述對象的行為。其中數據成員又有實例變量(instance variable)和屬性(property)兩種。函數成員分為方法(method)、初始化器(init)和析構器(dealloc)三種。

認識屬性


屬性表達實例狀態,描述類型對外接口。相比直接訪問實例變量,屬性可以做更多控制。

默認情況下,編譯器會為屬性定義propertyName自動合成一個getter訪問器方法:propertyName、一個setter訪問器方法:setPropertyName還有一個實例變量_propertyName。

舉例:

在OC類中聲明一個屬性:@property NSString* firstName; //聲明一個類所包含的屬性。

此時編譯器會自動生成類似如下代碼,但是并不顯示出來:

-(NSString*)firstName{? //生成一個getter函數

???return _firstName;

}

-(void)setFirstName:(NSString *)newValue{? //生成一個setter函數

??_firstName=newValue;

}

NSString* _firstName; //創建一個以 _(下劃線)+屬性名的實例變量

由于編譯器自動生成了類似如上代碼,我們可以用編譯器生成的getter方法和setter方法來訪問或修改該屬性的內容。

例如:

Employee* employee=[[Employee alloc] init];

[employee setFirstName: @"Tom"]; //將employee類的FirstName屬性設置為“Tom”,setFirstName這個setter方法是編譯器自動生成的。

NSLog(@"First Name: %@", [employee firstName]); //打印出employee類的FirstName屬性,此處[employee firstName]是調用了編譯器自動生成的getter方法firstName。

除了以上的方法來訪問getter和setter方法外,可以用類名+.(點表達式)+屬性名來訪問屬性的getter和setter方法。

例如:

employee.lastName=@"Chen"; //訪問了lastName屬性的setter表達式,等價于[employee setFirstName: @"Chen"];

NSLog(@"First Name: %@", employee.lastName); //訪問了lastName屬性的getter表達式,等價于NSLog(@"First Name: %@", [employee firstName]);

兩種方法在本質上沒有什么區別,推薦用點表達式,使用比較方便。


可自定義訪問器方法,也可更改訪問器方法名或實例變量名。

例如:

@property (readonly) NSString* fullName; //在頭文件中定義了一個只讀屬性fullName

-(NSString *)fullName{

? return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];

} //在主文件中自定義了fullName屬性的getter訪問器方法。stringWithFormat函數是用來鏈接兩個字符串類實例。

@property (getter=GivenName, setter=GivenName:) NSString* firstName; //聲明firstName屬性時將該屬性的getter、setter訪問器的名字都設置為GivenName。

@synthesize firstName=givenName; //在主文件中將firstName屬性由系統自動生成的_firstName實例變量改名為givenName。

可以使用靜態全局變量(C語言)+類方法,模擬類型屬性。

static int _max=100; //在主文件中定義一個靜態變量_max

+(int)max; //在頭文件中聲明一個類方法(getter訪問器) +(int)max

+(void)setMax:(int)newValue; //在頭文件中聲明一個類方法(setter訪問器)? +(void)setMax

+(int)max{

return _max;? //在主文件中實現類方法+(int)max

}

+(void)setMax:(int)newValue{

????? _max=newValue;? //在主文件中實現類方法+(void)setMax

}

完成以上步驟后,可以實現訪問類型屬性。

[Employee setMax:400]; 等同于Employee.max=400; 模擬出來的類屬性。


實例變量

可以定義實例變量,而不定義屬性(這樣外部不能訪問到實例變量),只有實例變量,沒有類變量(使用靜態全局變量+類方法可以模擬出類變量的效果)。

如果同時自定義了getter和setter訪問器方法,或者針對只讀屬性定義了getter訪問器方法,編譯器將不再合成實例變量。

引用類型的實例變量在類外一律使用屬性來訪問,類內大多也通過self使用屬性訪問。只有以下情就卡了況使用實例變量來訪問:1、初始化器 init? 2、析構器 dealloc 3、自定義訪問器方法。?


實例變量的生存周期

實例變量的儲存:跟隨對象實例存儲在堆上。

值類型實例變量直接“內嵌”在對象實例中。跟隨對象實例內存釋放而被釋放。

引用類型實例變量通過指針“引用”堆上的引用類型實例,ARC針對引用進行計數管理,自動釋放引用計數為0的對象。


屬性的描述特性(Attribute)

屬性的描述特性可以指定屬性不同環境下的不同功能。

讀寫特性,默認情況屬性都是可讀寫(readwrite)的,也可以設置為只讀(readonly)屬性。

例如:

@property (readonly) NSString* fullName; //在頭文件中定義了一個只讀屬性fullName

多線程特性,默認情況下是屬性是原子性(atomic)的,表示多線程時原子性屬性不能被線程搶走,要么沒有運行,開始運行了必須運行到結束。也可以設置為非原子性(nonatomic).

例如:

@property (nonatomic) NSString* fullName; //在頭文件中定義了一個非原子性屬性fullName


內存管理特性

引用屬性默認為強(strong)引用屬性,弱(weak)引用阻止循環引用。當兩個實例對象屬性相互強引用時會形成循環引用,這時ARC內存管理將視這兩個互引用的屬性都占用,無法將這兩個實例的引用屬性釋放。

兩個類型相互強引用導致內存泄露。

為了避免上述情況發生把其中一個對象屬性設置為弱引用,這樣就不會出現不能釋放的問題了。


一個弱引用一個強引用就可以互相引用,并可以正常釋放內存


拷貝(copy)屬性創建獨立拷貝,當引用屬性不想被外界直接引用時,可以用拷貝屬性,讓外界引用一個拷貝副本,來確保原始數據不會被外界修改。

不使用拷貝特性時,被引用將多一條指針指向實例屬性


使用拷貝特性后,被引用時多一條指針指向實例屬性的副本


第四天視頻課程:


認識方法 Method

代碼段上的可執行指令序列就是函數,函數有全局函數(C語言函數),和成員函數(OC中也叫方法)。

方法是類的成員函數,表達實例行為或類型行為。

舉例:

以下聲明了4個方法

-(void) print; //-表示是實例方法,返回值是void, 方法名是print, 無參數

-(BOOL) isEqualToPoint: (BLNPoint*) point; //返回值是BOOL, 參數名是point, 參數類型是BLNPoint*

-(void) moveToX: (int)x toY: (int)y;? //有兩個(int)類型的參數x和y

+(BLNPoint*) getOriginPoint; //+表示getOriginPoint是一個類方法

所有方法默認為公有方法。沒有private或protected方法(可以在接口文件中不要聲明方法,而在實現文件中實現方法來做到類似private方法)。

動態消息發布:方法調用通過運行時動態消息分發實現,在對象上調用方法又稱“向對象發送消息”。

例子:

[p1 print]; //實例p1調用了print方法,也可以說向對象p1發送了一個print消息

[p1 moveToX:100 toY:200]; //向對象p1發送了一個moveToX消息,其中還包含了兩個參數,100和200

BLNPoint* origin=[BLNPoint getOriginPoint]; //向BLNPoint類發送了一個getOriginPoint消息,返回值賦值給BLNPoint的類型實例origin


實例方法或類型方法

實例方法用來表達實例的行為所以只能通過實例對象來調用,實例方法在內部實現時可以訪問實例成員包括實例屬性、實例變量和實例方法。也可以訪問類型方法和靜態變量。

類方法用來表達類的行為只能通過類來調用,類型方法在實現時可以訪問類型方法和靜態變量,不能訪問實例成員包括實例屬性、實例變量和實例方法。

編譯器背后對實例方法和類方法的不同處理:self指針

例子:

實例方法實現

-(void) print{

????? NSLog(@"[%d, %d]", self.x, self.y);

}

上面的實例方法實現中self實際上是一個隱藏的指針參數,用來傳遞當前實例地址,編譯器編譯后用C語言的表達方式可以寫成:

void print(BLNPoint* self){

????? NSLog(@"[%d, %d]", self.x, self.y);

}

調用該方法時:[p1 print]; //print(p1);

類方法實現

+(BLNPoint*) getOriginPoint{

????? BLNPoint* origin=[[BLNPoint alloc] init];

????? origin.x=0;

????? origin.y=0;

????? return origin;

}

上述的類方法實現編譯后用C語言表示為

BLNPoint* getOriginPoint(){

????? BLNPoint* origin=[[BLNPoint alloc] init];

????? origin.x=0;

????? origin.y=0;

????? return origin;

}

類方法里面不能用self關鍵字來訪問實例變量,但是依然可以使用self關鍵字,這時self關鍵字用來表示當前類。在類方法實現里面可以用[self process]來調用當前類中的process方法,也等同于[BLNPoint process]。


方法參數

如果參數類型是值類型,為傳值方式,如果參數類型為引用類型,則為傳指針方式。

方法可以沒有參數,也可以沒有返回值。

如果方法有參數,方法名約定包含第一個參數,從第二個參數開始需要顯示提供外部參數名。

-(void) moveToX: (int)x toY: (int)y;?//toY是第二個參數的外部參數名,x是第一個內部參數名,y是第二個內部參數名。

調用時,第一個參數名忽略,但后面的參數名必須顯示標明。如: [p1 moveToX:100 toY:200];


動態方法調用機制--消息分發表

在OC里所有的對象類型都可以聲明為id類型

例子:

id obj=[[BLNPoint alloc] init];

[obj moveToX:50 toY:60];

[obj print];

這里類型為id的對象obj可以調用類型為BLNPoint的對象方法,是由于OC的動態調用機制造成的。


消息分發機制

OC中調用所有方法都會通過消息分發表,上圖灰色的部分其中有一個指針,指向class再指向method list。這樣做可以增加靈活性,支持在運行時向方法表添加新的方法。缺點是每次調用方法都要多次尋址有性能損失。


第五天視頻課程:


初始化器與析構器

初始化器和析構器是類型的特殊函數成員,初始化器用于初始化對象實例或者類型。

對象初始化器:-(id)init 可以重載多個。

例子:

在頭文件中可以聲明多個有不同參數列表的-(id)init函數。

-(id)init;

-(id)initWithName:(NSString *)name;

-(id)initWithName:(NSString *)name WithPages:(int)pages;

-(id)initWithName:(NSString *)name WithPages:(int)pages WithCategory:(NSString *)category;

在主文件中實現聲明的init方法

-(id)init{

????? self = [super init];

????? if(self){? //如果父類初始化失敗self指針將等于Null

??????? NSLog(@"Book Object init“); //在調用了父類的init方法后可以添加自己所需的內容。

????? }

????? return self;

}

-(id)initWithName:(NSString *)name WithPages:(int)pages{

????? return [self initWithName:name WithPages:pages WithCategory:@"General"];

}

-(id)initWithName:(NSString *)name WithPages:(int)pages WithCategory:(NSString *)category{ //由于該初始化器的參數是最多的,作為主初始化器,其他參數少的初始化器可以直接調用主初始化器。

????? self = [super init];

????? if(self){

????? _name = [name copy]; //在初始化器中使用實例變量而不要使用實例屬性。

????? _pages = pages;

????? _category = [category copy];

????? }

????? return self:

}

初始化對象實例時,init通常和alloc搭配使用。

Book *b1 = [[Book alloc]init]; //alloc是一個從NSObject繼承過來的類方法。Tips: 按住commond健再點擊關鍵詞可以查看其類庫。

Book *b1 = [[Book alloc]init]; 也可以拆分為:

Book *b1 = [Book alloc];

b1 =[b1 init]; //這里等號左邊的b1是不可以省略的,因為[b1 init]有一個返回值,是返回一個地址,OC在這里返回的地址有可能和上一行Book *b1 = [Book alloc];其中的b1地址不一樣。

alloc所做的事情--NSObject已實現:1、在對上分配合適大小的內存。 2、將屬性或者實例變量的內存置0。

init所做的事情--可以自定義:1、調用父類初始化器[super init](前置調用)。 2、初始化當前對象實例變量。

Book *b1= [Book new]; //new相當于調用 alloc/init的無參數版本,不能傳遞參數。

類初始化器

類型初始化器:+(void)initialize 只能有一個,負責類型級別初始化,初始化類里面的靜態變量。

initialize在每個類使用之前被系統自動調用,且每個進程周期中只被調用一次。

子類的initalize會自動調用父類的initialize(前置調用)。

+(void)initialize{

????? if(self ==[Book class]){ //判斷該類是否是Book類

??????????? NSLog(@"Book Class initialize");

????? }

}

對象析構器

對象析構器 -(void)dealloc 只能有一個,用于釋放對象(沒有類型析構器)擁有的動態資源,無返回值。

-(void)dealloc{

自動調用:1.ARC將對象屬性引用計數減持(-1)

手動實現:2.釋放不受ARC管理的動態內存,如malloc分配的內存,關閉非內存資源,如文件句柄、網絡端口

自動調用:3.父類dealloc

}

dealloc由ARC根據對象引用計數規則,在釋放對象內存前自動調用,無法手工調用。

子類的dealloc會自動調用父類的dealloc(后置調用)。


第六天視頻課程:


認識面向對象

封裝 encapsulation:隱藏對象內部實現細節,對外部僅提供公共接口訪問。

繼承 inheritance:一個類型在另外類型基礎上進行的擴展實現。每一個類只能有一個基類,子類自動繼承基類的:實例變量、屬性、實例方法、類方法。NSObject類是所有類的根類,所有類向上追溯最上面的類都是NSObject類。繼承有兩層含義:1、成員復用,子類復用基類的成員。所有的成員都會被繼承,就算是私有成員也被繼承,只是成員訪問不到。2、類型抽象,將子類當作父類來使用。

例子:

建立一個類Shape

@interface Shape : NSObject{ //Shape類繼承于NSObject Tips:按住option鍵點擊關鍵字可以看到相關的參考文檔。

????? @public int _data; //定義了一個公開的實例變量

}

????? @property int no;

????? -(void)draw;

????? +(void)process;

@end

建立一個Shape的子類Circle

@interface Circle:Shape //Circle類繼承了Shape類

@property int radius; //Circle類自己的實例屬性

@end

由于Circle繼承了Shape類,所以Shape類的實例變量、屬性、實例方法、類方法Circle類都可以使用。

Circle* circle=[[Circle alloc]init];

circle.no=200;

circle->_data++; //在訪問父類實例變量時用->來訪問

[circle draw];

[Circle process]; //Circle類也可以調用父類的類方法。


Circle類繼承Shape類的內存模型


第七天視頻課程:


多態 polymorphism:不同類型針對同一行為接口的不同實現方式。

對比重寫(override)與重載:子類重寫父類同名同參數方法,子類只可以重寫父類方法。方法名相同、參數不同,OC不支持方法的重載(重載指的是方法名相同,參數不同。用不同的參數傳遞給相同名字的方法,達到不同的運行效果)。

在子類的代碼中,可以使用super類調用基類的實現,self具有多態性,可以指向不同子類,super沒有多態性,僅指向當前父類。

例子:

建立一個Shape的子類Rectangle

@interface Rectangle:Shape

@property int width;

@property int length;

@end

基類Shape中有一個實例方法move:

-(void)move{

????? NSLog(@"Shape object move");

????? [self draw];

}

針對Rectangle類增加了兩個屬性(width和length)重寫(override)繼承過來的方法

@implementation Rectangle

-(id)init{

????? self = [super init];? //重寫時子類初始化器中必須首先調用基類的初始化器

????? if(self){

??????????? _length = 10;

??????????? _width = 20;

????? }

????? return self;

}

-(void)draw{

????? NSLog(@"Rectangle object draw: length=%d, width=%d", self.length, self.width);

}

-(void)print{

????? NSLog(@"Rectangle Instance variable %d", _data);

}

+(void)process{

????? NSLog(@"Rectangle class process");

}

-(void)dealloc{

?????? NSLog(@"Rectangle dealloc");

}

當實例對象調用時,Rectangle實例將調用重寫的方法。Rectangle實例調用-(void)move時將調用父類Shape類的實例方法-(void)move,此方法中調用的draw方法[self draw],此時self有多態性,將調用Rectangle實例中的draw方法。

對于父類中的屬性也可以在子類中重寫。

父類Shape中的屬性:@property int no;

在子類Rectangle中重寫:

-(int)no{

????? return super.no;? //super表示調用父類的方法

}

-(int)setNo:(int)no{

????? super.no = no;

}

屬性的重寫本質上就是getter和setter兩個訪問器的重寫。

繼承中的init和dealloc

初始化器 init:子類自動繼承基類的初始化器,子類也可以重寫初始化器,重寫時子類初始化器中必須首先調用基類的初始化器(手工調用)再添加其他內容。

析構器 dealloc:子類可以選擇繼續繼承基類析構器,或者重寫基類析構器,子類析構器執行完畢后,會自動調用基類析構器(后置調用,且不支持手工調用)。子類析構器自動具有多態性。

Tips:盡量避免在父類init和dealloc中調用子類重寫的方法。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,732評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,214評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,781評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,588評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,315評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,699評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,698評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,882評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,441評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,189評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,388評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,933評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,613評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,023評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,310評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,112評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,334評論 2 377

推薦閱讀更多精彩內容