Oc基礎
1、#import的用途
1>#import與#include一樣,拷貝文件的內容
2>可以自動防止文件的內容被重復拷貝
2、#import
? ? ? ? NSLog(<#NSString * _Nonnull format,…#>)聲明的函數(shù)
3、Foundation框架頭文件路徑
1>、Xcode右擊,顯示報內容
2>、/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks
4、主頭文件
1>、最主要的頭文件,名字一般跟框架名一樣,包含框架中所有的其他文件
2>、Foundation框架的主頭文件名稱就是Foundation.h
3>、只要包含了Foundation的主頭文件,就可以使用整個框架的東西
5、運行過程
1>編寫代碼? .m .c
2>編譯? xxx.m xxx.c
3>鏈接? xxx.o xxx.o
4>運行? ? ./a.out
6、在使用類的時候,會將類加載到內存中
沒有對象內部都有一個isa指針,這個指針指向類的方法列表
7、方法與函數(shù)的區(qū)別
方法:
1>對象方法以-號開頭
2>方法的聲明必須寫在@interface和@end之間
?? ? ? 方法的實現(xiàn)必須寫在@implementation和end之間
3>對象方法只能又對象來調用
4>對象方法歸對象和類擁有
函數(shù):
1>函數(shù)可以寫在文件的任意位置,函數(shù)歸文件所有
2>函數(shù)的調用不依賴于對象
8、匿名對象
就是創(chuàng)建對象的時候,沒有指針去指向這個對象
9、類方法和對象方法可以同名
類方法的執(zhí)行效率比較高,但是類方法不能訪問成員變量
10、工具類:基本沒有任何成員變量的時候,里面的方法都是類方法。
11、繼承
1>子類不能擁有和父類相同的成員變量
2>父類必須聲明在子類之前
3>調用某個對象的方法,優(yōu)先從該對象中查找,如果找不到再去父類中查找方法的實現(xiàn)
每個類中都有一個superClass指針,指向自己的父類,進而才可以去
super關鍵字的使用
1>super直接調用父類的方法
2>具體調用super的對象方法還是類方法,完全取決于當前的環(huán)境
3>子類中想先調用父類的方法之后,才去調用子類的方法時候,可以調用下super的方法
12、多態(tài):父類的指針指向子類的對象 (狗 是DOG類型 ,它的父類是animation。所以一個狗的對象既可以用狗類的對象指針指向,也可以用動物類對象的指針指向)
1>沒有繼承就沒有多態(tài)
2>如果函數(shù)的參數(shù)是父類,那么參數(shù)對象可以傳子類、父類對象
3>局限性:父類類型的變量不能直接調用子類類型特有的方法
13、成員變量的作用域
局部變量、全局變量有自己的作用域,成員變量也不例外。
成員變量的作用域:
@public:在任何地方都能訪問對象的成員變量? ? ? ? ? ? ?
@private:只有當前類的對象方法中訪問? ? 或者是用set/get方法 (@implementation中聲明的成員變量默認是private)
@protected:可以在當前類以及子類的對象中直接訪問(默認就是@protected)或者是用set/get方法
@package:只要處于同一框架,就可以直接訪問對象的成員變量
在@implementation中也能定義一個成員屬性,但是默認是私有的
@interface和@implementation不能聲明同名的成員屬性
14、@property? int age;會自動生成setAge和age方法的聲明
@synthesizeage = _age;會自動聲明setAge和age方法的實現(xiàn),而且這句話會訪問_age這個屬性,如果不存在就會自動幫我們創(chuàng)建一個@private的_age屬性。
@synthesizeage(如果不寫=_age)會自動聲明setAge和age方法的實現(xiàn),而且這句話會訪問_age這個屬性,如果不存在就會自動幫我們創(chuàng)建一個@private的age屬性。
Xcode4.3之后@property? int age這一句代碼就會幫我們生成 _age 以及setAge、age的方法聲明與實現(xiàn),但是這個方法生成的成員屬性是私有的,不能讓子類進行訪問,如果想讓子類進行訪問,那么就需要在.h中聲明聲明一個protected的_age屬性
如果手動實現(xiàn)了set方法,那么編譯器就只會生成get方法和下劃線屬性
如果手動實現(xiàn)了get方法,那么編譯器就只會生成set方法和下劃線屬性
如果手動生成了set和get方法,那么編譯器就不會幫你生成下劃線屬性
15、構造方法
用來初始化對象的方法,是一個對象方法
重寫init方法:
1>調用【super init】方法初始化父類的屬性,并賦值給self
2>判斷self是否為空,不為空則進行初始化屬性操作
3>返回self
重寫構造方法的目的:為了創(chuàng)建對象的時候,成員變量就有值
-(instancetype)init{
? ? if(self=[superinit]){
? ? ? ? _age? =10;
? ? }
? ? returnself;
}
自定義構造方法:
1>一定是對象方法,以 - 開頭
2>返回類型是 id類型
3>方法名以initWith開頭
-(instancetype)initWithAge:(int)age{
? ? if(self=[superinit]){
? ? ? ? _age = age;
? ? }
? ? returnself;
}
16、修改Xcode創(chuàng)建文件的時候的一些配置屬性
/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates在這里面修改
17、分類:可以給某一類擴展一些方法,在不改變原來類的基礎上,為類增加一寫方法。
分類的使用注意:
1>只能增加方法,不能只能成員變量
2>分類方法的實現(xiàn)中可以訪問原來類的成員變量
3>分類可以重新實現(xiàn)原來類中的方法,但是會覆蓋掉原來類中的方法,會導致原來類中的方法無法使用
4>方法調用的優(yōu)先級: 分類(最后編譯的分類優(yōu)先) —> 原類 —> 父類
18、
1>當程序啟動時,就會加載項目中所有的類和分類,而且加載后會調用類和分類的+ (void)load{? ?
}方法,只會調用一次
2>當?shù)谝淮问褂媚硞€類的時候,會調用當前類的+(void)initialize
}方法
3>先加載父類,再加載子類,最后加載分類的(先調用父類的load方法,再調用子類的load方法)
先初始化父類,再初始化子類(先調用父類的initialize方法,再調用子類的initialize方法)
19、類也是個對象
類也是一個對象,是一個class類型的對象,簡稱類對象
Class類型的定義
typedefstructobjc_class * Class
類名就代表類對象,每個類只有一個對象
20、-(NSString *)description{}方法
默認情況下,利用NSLog和%@輸出對象的時候,結果是<類名:內存地址>
1>會調用對象的description方法
2>拿到description方法的返回值展示到屏幕上
3>description默認返回的是“類名+內存地址”
+(NSString *)description{}方法,類的-(NSString *)description{}方法,默認返回的是類名
21、? ? NSLog(@"%s",__FILE__);
NSLog輸出c語言字符串的時候,不可以包含中文
22、SEL
typedefstructobjc_selectorSEL
SEL s = NSSelectorFromString(@"test")
NSStringFromSelector(@selector(test))
_cmd代表當前方法
?NSString *s = NSStringFromSelector(_cmd);
SEL其實是對方法的一個包裝,去找到對應的方法地址就可以調用此方法
內存管理? ?
1、局部變量的對象是放在棧中的,系統(tǒng)會管理他們的內存
?? ? 一個oc對象的內存是放在堆中的,需要我們去手動管理他的內存
2、每個對象的內部都有四個字節(jié)來存儲對象的內存空間
當一個對象alloc /new /copy的時候引用計數(shù)器會+1
給對象發(fā)送 retain 消息的時候,對象的引用計數(shù)器+1
? ? ? ? 給對象發(fā)送release消息的時候,對象的引用計數(shù)器-1
? ? ? ? 給對象發(fā)送 retainCount 消息的時候,返回對象的引用計數(shù)器的個數(shù)
3、對象銷毀
?? ? ? 當一個對象的引用計數(shù)器為0的時候,系統(tǒng)會給對象發(fā)送一個dealloc消息,一般重寫此方法在其中做一些釋放性的操作
4、野指針: 指針指向了一塊已經(jīng)釋放的內存對象(這個對象成為僵尸對象)給野指針發(fā)送消息會報錯 野指針經(jīng)常報錯為 EXC_BAD_ADRESS
? ? ? 空指針:沒有指向任何對象的指針(存儲的為nil/NULL/0) oc中給nil 發(fā)送消息不會報錯
? ? ? 僵尸對象:所占用的內存已經(jīng)被回收的對象,僵尸對象不能再繼續(xù)使用
5、retain方法會返回對象本身
? ? ? release方法不會有返回值
6、delloc
? ? ? 當對象要被回收的時候會調用、一定要調用【super delloc】,因為【super delloc】中也要做一些釋放操作,而且這一句一定要寫在最后
7、alloc/new/mutableCopy來創(chuàng)建對象的時候,引用計數(shù)器會+1,不使用這個對象的時候,需要將引用計數(shù)器-1
8、誰retain了,誰就要release
9、當你想使用或者占有某個對象的時候,需要對對象進行一次retain操作
? ? ? 當你不想使用或者占有某個對象的時候,需要對對象進行一個release操作
? ? ? 誰retain誰release
? ? ? 誰alloc誰release
10、假如person? 有一個car屬性
_car:直接訪問成員屬性
self->_car:直接訪問成員屬性
self.car? :get方法
[self car]:get方法
11、MRC中的set方法?
@interfacePerson : NSObject
{
? ? Car *_car;
}
-(void)setCar:(Car *)car;
-(Car *)car;
@end
@implementationPerson
-(void)setCar:(Car *)car{
? ? if(_car != car){? ? ? ? //這個判斷是為了防止調用多次[self car]此時的car為同一個car,先給_car做一次release操作,此時car已經(jīng)被釋放了,然后再去調用【car retain】方法,這個相當于是給一個僵尸對象發(fā)送了一個retain消息。
? ? ? ? [_car release];? ? //這個是為了防止在你給對象賦值新的car的時候,原有的car沒有做release操作,而導致的原有的car不會被釋放
? ? ? ? _car =[car retain];//這段代碼是為了誰擁有誰就要去retain
? ? }
}
-(Car *)car{
? ? return_car;
}
@end
12、內存管理的原則
1>只要調用了alloc,就必須調用release或者autorelease
2>set方法的代碼規(guī)范
?? 基本數(shù)據(jù)類型:
-(void)setAge:(int)age{
_age = age;? 直接賦值
}
? ? 對象類型:
-(void)setCar:(Car*)car{
if(_car != car){
[_car release];//對舊對象進行release操作
_car =[car retain];//對新對象進行retain操作
}
}
3>delloc //對self所擁有的所有對象進行一次release操作
-(void)delloc{
[_car? release];
//最后調用【super delloc】
[super delloc];
}
13、property默認生成的set和get方法是直接賦值assign
14、property(retain)就是相當于在set方法中先release舊值,再retain新值
15、property的參數(shù)有四個
1>set方法內存管理的相關參數(shù)
*retain:先release舊值,再retain新值
*assign:直接賦值
*copy
2>多線程管理
nonatomic :(性能高,set方法的時候不加線程鎖)
atomic :(性能低,加線程鎖)
3>是否只生成set和get方法
*readwrite:同時生成set和get方法的聲明與實現(xiàn)
*readolny:只生成get的聲明與實現(xiàn)
4>set和get的方法名稱
setter:決定了set:的方法名,一般是需要帶冒號的
getter:決定了getter方法名(一般用在bool類型)
例如:
@property(nonatomic,retain,readwrite,setter=setCarrrrr:,getter=carrrrr)Car *car;
16、
定義一個枚舉
typedefenum{
? ? SexMan,
? ? SexWoman
} Sex;
定義一個結構體
typedefstruct{
? ? intyear;
? ? intmonth;
? ? intday;
} Date;
17、@class只是告訴對象 這是一個類 , 但是不包含.h中的屬性與方法
?1>@class只是告訴編譯器某個名稱是一個類,例如@class person僅僅告訴編譯器person是一個類
2>開發(fā)中引用一個類的規(guī)范
在.h中用@class來聲明
在.m中用import來包含類的聲明
3>兩端循環(huán)引用的解決方案
一端用retain一端用assign
在.h中用@class來聲明可以解決循環(huán)包含的錯誤?
例如
#import <Foundation/Foundation.h>
#import "Person.h"
@interfaceCar : NSObject
@property(nonatomic,retain)Person *p;
@end
#import <Foundation/Foundation.h>
#import "Car.h"
@interfacePerson : NSObject
@property(nonatomic,retain)Car *car;
@end
這樣會報錯,編譯不通過
#import <Foundation/Foundation.h>
@classPerson;
@interfaceCar : NSObject
@property(nonatomic,retain)Person *p;
@end
#import <Foundation/Foundation.h>
@classCar;
@interfacePerson : NSObject
@property(nonatomic,retain)Car *car;
@end
這樣才不會報錯,編譯可以通過,然后在.m文件中用#import “”來包含頭文件
這樣做編譯效率也比較高,如果按照第一種方式,一旦包含的類種的屬性或者方法修改過了,就會造成每一個只要#import “”的.h都會重新編譯一遍,造成效率比較低
18、autorelease的使用
autorelease方法會返回對象本身
autorelease 會把對象放在一個自動釋放池中,當自動釋放池被銷毀的時候,會對池中的對象做一次release操作
? ? @autoreleasepool{
? ? ? ? Person *p =? [[[Person alloc]init]autorelease];
? ? }
會在池子結束的時候,對person對象調用一次release操作
autoreleasepool是可以嵌套使用的,而且autoreleasepool是放在棧內存中的,先進后出。
autoreleasepool的基本用法:
1>會將對象放入一個自動釋放池中
2>當自動釋放池銷毀的時候,會對池中的對象進行一次release操作
3>會返回對象本身
4>調用完autorelease方法,對象的引用計數(shù)器不變,只有當autoreleasepool執(zhí)行完畢之后,才會對池中的所有對象進行一次release操作
autorelease的好用:
1>不用關心對象釋放的時間
2>不用關心什么調用對象的release
autorelease的使用注意:
1>占用較大內存的對象,不要隨便的使用autorelease
2>占用較小內存的對象使用autorelease沒有太大的影響
池子autoreleasepool的錯誤寫法:
1>? ? @autoreleasepool{
? ? ? ? Person *p =? [[[[Person alloc]init]autorelease]autorelease];//調用兩次autorelease會出現(xiàn)野指針錯誤
? ? }
2>? ? @autoreleasepool{
? ? ? ? Person *p =? [[[Person alloc]init]autorelease];
? ? ? ? [p release];
? ? }? ? ? ? 也會出現(xiàn)也指針錯誤
3>? ? ? ? Person *p =? [[[Person alloc]init]autorelease];這樣寫沒有任何的意義,因為autorelease不放到autoreleasepool中是不會調用release的
自動釋放池:
1>ios程序中也會創(chuàng)建自動釋放池,這些自動釋放池以棧的形式存在
2>當一個對象調用autorelease方法的時候,會將這個對象放到棧頂?shù)尼尫懦?/p>
自動釋放池的創(chuàng)建方法:
#pragma mark ios5之前
? ? NSAutoreleasePool *pool =[[NSAutoreleasePool alloc]init];
? ? Person *p =? [[[Person alloc]init]autorelease];
? ? [pool release];
#pragma mark ios5之后
? ? @autoreleasepool{
? ? ? ? Person *p =? [[[Person alloc]init]autorelease];
? ? ? ? [p release];
? ? }
}
19、
1>系統(tǒng)自帶的方法沒有alloc/new/copy,說明返回的對象都是autorelease的
例如? NSString *str =[NSString stringWithFormat:@"string"];
? ? NSString *str1 =[NSString stringWithString:@"string"];
2>開發(fā)中經(jīng)常提供一些類方法快速創(chuàng)建一個已經(jīng)autorelease的對象
創(chuàng)建對象的時候,不要直接用類名,要用self,以滿足子類的需求
例如
+(id)person{
? ? return? [[[selfalloc]init]autorelease];
}
內存管理的總結:
一、計數(shù)器操作:
1>retain +1;
2>release -1;
3>retaincount? :獲取計數(shù)器
二、set方法的內存管理
1>set的實現(xiàn)
-(void)setCar:(Car *)car{
? ? if(_car != car){
? ? ? ? [_car release];
? ? ? ? _car =[car retain];
? ? }
}
2>delloc方法的實現(xiàn)(不要直接調用delloc)
-(void)dealloc{
? ? [_car dealloc];
? ? [superdealloc];
}
三、property參數(shù)
oc對象:
@property(nonatomic,retain)類名*屬性名;
非oc對象:
@property(nonatomic,assign)類型名稱屬性名;
四、@autoreleasepool
1、系統(tǒng)的方法中如果不帶有alloc、new、copy,這些方法返回的對象都是已經(jīng)autorelease過的
2、在開發(fā)過程中用類方法創(chuàng)建對象的時候,不要直接使用類名。可以用self(利用類方法快速創(chuàng)建一個autorelease對象)
ARC
ARC的判斷準則:只要沒有強指針指向對象,就會釋放對象
1>ARC的特點是不允許調用retain/release/retainCount
2>允許重寫delloc,但是不允許調用【super delloc】
3>property參數(shù)
*strong 成員變量是強指針 ,相當于之前retain(只適用于oc對象)
*weak成員變量是弱指針,相當于之前的assign(適用于oc對象)
*assign:適用于非oc對象
指針分為兩種:
強指針:__strong 默認情況下就是強指針
弱指針:__weak? 當弱指針指向的對象消失后,默認會指向nil
ARC與MRC的轉換
1>mrc項目 轉 arc
xcode -> edit ->convert -> to object ARC
2>查看項目當前是否為 ARC
buildSetting ->搜索auto -> objectc automatic reference counting ->yes代表arc No代表mrc
3>將項目中某個文件改為 arc或者mrc
build phases ->compile source ->-fno-objc-arc不需要arc或者-f-objc-arc需要ARC
當兩端循環(huán)引用的時候,解決的方案
1、ARC
一端用strong一端用weak
2、非arc
一端用retain一端用assign
Block:
intsum(inta,intb){
? ? returna+b;
}
-(void)viewDidLoad {
? ? [superviewDidLoad];
? ? int(*p)(int,int)= sum;
? ? intsum = p(10,12);
? ? NSLog(@"%d",sum);
}
指向函數(shù)的指針
int(^sumBlock)(int,int)=^(inta,intb){
? ? ? ? returna+b;
? ? };
? ? sumBlock(100,100);
1>如何定義block變量
Int(^SumBlock)(int,int);
void(^myBlock)();
2>如何利用block封裝代碼塊
^(int a,int b){
return a-b
};
^(){
NSLog(@“111111”);
};
3>block訪問外部變量
*block內部可以訪問外面的變量
*默認情況下,block內部不能修改外面的變量
*給局部變量上加上__block關鍵字,這個局部變量才可以在block內部修改
4>利用typedef定義block類型
typedefint(^MyBlock)(int,int);
以后就可以利用MyBlock這種類型來定義block變量
協(xié)議Protocol
1>基本用途
*可以用來聲明一大堆方法
*只要某各類遵守了這個協(xié)議,就相當于擁有了這個協(xié)議的所有方法
*只要父類遵守了某個協(xié)議,就相當于子類也遵守了
2>格式
@protocol協(xié)議名稱
//協(xié)議方法
@end
某個類遵守某個協(xié)議
@interface類名:父類<協(xié)議名稱1,協(xié)議名稱2>
@end
3>關鍵字
@required:這個方法是必須實現(xiàn)的(若不實現(xiàn),編譯器會發(fā)出警告)
@optional這個方法不一定實現(xiàn)
4>協(xié)議遵守協(xié)議
*一個協(xié)議可以遵守其他多個協(xié)議,多個協(xié)議之間用逗號隔開
*一個協(xié)議遵守了其他協(xié)議,就相當于擁有了其他以協(xié)議中的方法聲明
@protocol協(xié)議名稱<協(xié)議1,協(xié)議2>
@end
5>基協(xié)議
*nsobject是一個基類,最根本最基礎的類,熱河其他類都要繼承它
*其實還有一個協(xié)議,名字也叫NSobject,它是一個基協(xié)議,最根本的協(xié)議
*nsobject協(xié)議中聲明很多最基本的方法,比如description、retain、release等
*建議每一個新協(xié)議都要遵守nsobject協(xié)議
6>定義一個變量的時候,限制這個變量保存的對象遵守某個協(xié)議
類名<協(xié)議名稱>*變量名;
id<協(xié)議名稱>變量名;
NSObject*object;
Idobj2;
如果沒有遵守協(xié)議,編譯器會報警
7>@propety中聲明的屬性也可以用作一個遵守協(xié)議的限制
@property(nonatoimic,strong)類名<協(xié)議名稱>*屬性名
8>協(xié)議可以定義在單獨的.h中,也可以定義在某個類型中
*如果這個協(xié)議只用在某個類中,應該定義在該類中
*如果某個協(xié)議用在很多類中,就應該把協(xié)議定義在單獨的文件中
9>分類可以定義在單獨.h和.m文件中,也可以定義在原類中
1>一般情況下,都是定義在單獨文件
2>定義在原類中的分類,只要求看懂語法
集合中的對象的內存管理
1>當對象被添加到集合中的時候,對象的引用計數(shù)器會加一
2>當集合被銷毀的時候,會對集合中的對象發(fā)送一次release消息
3>當對象被移除的時候,也會給對象發(fā)送一次release消息
@property內存管理的策略
1非ARC
1>copy:只用于nsstring/block
2>retain:除nsstring/block以外的oc對象
3>assign:基本數(shù)據(jù)類型、枚舉、結構體(非oc對象)當兩個對象相互引用的時候,一端用retain一端用assign
2ARC
1>copy:只用于nsstring/block
2>strong:除nsstring/block以外的oc對象
3>assign:基本數(shù)據(jù)類型、枚舉、結構體(非oc對象)
4>weak當兩個對象相互引用的時候,一端用retain一端用assign
自定義類實現(xiàn)copy操作
1>類遵守NSCopying協(xié)議
2>實現(xiàn)-(id)copyWithZone:(nullableNSZone *)zone;方法
3>在- (id)copyWithZone:(nullableNSZone *)zone方法中創(chuàng)建一個新的對象,并設置該對象數(shù)據(jù)與現(xiàn)有對象一致,并返回該對象
單例模式
alloc方法其實調用的是allocWithZone
Static修飾局部變量,只創(chuàng)建一次
static修飾的全局變量,只有當前文件才可以訪問,并且只創(chuàng)建一次
1>永遠只分配一塊內存來創(chuàng)建對象
2>提供一個類方法,返回內部唯一的一個對象
3>最好保證init方法也只初始化一次
Dispath_once方法是線程枷鎖的,能保證線程安全
非ARC單例模式的實現(xiàn)比ARC單例模式的實現(xiàn)多了
-(id)retain{
}
-(NSUInteger)retainCount{
}
-(onewayvoid)release{
}
-(instancetype)autorelease{
}
// ## : 連接字符串和參數(shù)
#if __has_feature(objc_arc)判斷編譯環(huán)境是ARC還是MRC
#define singleton_h(name)+(instancetype)shared##name;
#if __has_feature(objc_arc)// ARC?
#define singleton_m(name)\
static id _instance;\
+(id)allocWithZone:(struct _NSZone *)zone \
{ \
? ? static dispatch_once_t onceToken;\
? ? dispatch_once(&onceToken,^{ \ dispatch_once線程安全,枷鎖了
? ? ? ? _instance =[super allocWithZone:zone];\
? ? });\
? ? return _instance;\
} \
?\
+(instancetype)shared##name \
{ \
? ? static dispatch_once_t onceToken;\
? ? dispatch_once(&onceToken,^{ \
? ? ? ? _instance =[[self alloc]init];\
? ? });\
? ? return _instance;\
} \
+(id)copyWithZone:(struct _NSZone *)zone \
{ \
? ? return _instance;\
}
#else// 非ARC
#define singleton_m(name)\
static id _instance;\
+(id)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken;\
dispatch_once(&onceToken,^{ \
_instance =[super allocWithZone:zone];\
});\
return _instance;\
} \
\
+(instancetype)shared##name \
{ \
static dispatch_once_t onceToken;\
dispatch_once(&onceToken,^{ \
_instance =[[self alloc]init];\
});\
return _instance;\
} \
\
-(oneway void)release \
{ \
\
} \
\
-(id)autorelease \
{ \
return _instance;\
} \
\
-(id)retain \
{ \
return _instance;\
} \
\
-(NSUInteger)retainCount \
{ \
return 1;\
} \
\
+(id)copyWithZone:(struct _NSZone *)zone \
{ \
return _instance;\
}
#endif
控制器的生命周期
-(void)loadView{
? ? [superloadView];
}
-(void)viewDidLoad{
? ? [superviewDidLoad];
}
-(void)viewWillAppear:(BOOL)animated{
? ? [superviewWillAppear:animated];
}
-(void)viewDidAppear:(BOOL)animated{
? ? [superviewDidAppear:animated];
}
-(void)viewWillDisappear:(BOOL)animated{
? ? [superviewWillDisappear:animated];
}
-(void)viewDidDisappear:(BOOL)animated{
? ? [superviewDidDisappear:animated];
}
-(void)viewWillUnload{
? ? [superviewWillUnload];
}
銷毀view
-(void)viewDidUnload{
? ? [superviewDidUnload];
}
-(void)didReceiveMemoryWarning{
? ? [superdidReceiveMemoryWarning];
}
Block可以使用在定義之前聲明的局部變量
? ? inti=10;
? ? void(^myBlock)(void)= ^(){
? ? ? ? NSLog(@"%d",i);
? ? };
? ? i = 100;
? ? myBlock();
打印的結果是 10;
1>在定義block的時候,會在block中建立當前局部變量的內容的副本(拷貝)
2>后續(xù)對該值進行修改不會影響block中的數(shù)值
3>如果需要在block中保持局部變量的數(shù)值變化,需要使用————block關鍵字
4>使用————block關鍵字之后,同樣可以在block中修改變量的值
runtime
運行時機制:比較高級的特性,純C語言
平時的oc代碼——>C語言的運行時代碼
默認情況下任何block的內存都是分配在棧中的,隨時可能被回收。
對block進行一次copy操作就會把內存分配到堆中。
block會對代碼塊中的對象進行一次強引用,例如
self.block = ^{
self.age = 20;
}
這個時候,block會對self進行一次強引用,而block又是self的一個copy屬性,也屬于強引用,所以造成了循環(huán)引用;
因此當block中使用了對象的時候,需要判斷是否造成了循環(huán)引用。如果造成了循環(huán)引用,就需要用——weak 來重新用指針指向對象
或者__unsafe_unretained? 來重新修飾?
例如
__unsafe_unretainedPerson *p2 = p1;
? ? __weakPerson *p3 = p1;
? ? __weaktypeof(self)weakSelf =self;
? ? typeof(self) 就是用來判斷類型,即等價于 self的類型*
KVC
利用kvc可以隨意的修改一個對象的屬性或者成員變量(并且私有的也可以)
Person *p1 =[[Person alloc]init];
? ? Dog *dog =[[Dog alloc]init];
? ? [p1.dog setValue:@"dogname" forKey:@"name"];
? ? [p1.dog setValue:@"dogname" forKeyPath:@"dog.name"];
人對象有一個狗的屬性,狗又有name的屬性;
? ? [p1.dog setValue:@"dogname" forKey:@"name”];中的key只能是屬性名,否則會報錯;
? ? [p1.dog setValue:@"dogname" forKeyPath:@"dog.name"];
可以是路徑,又可以是屬性名
forKeyPath包含了for的功能,以后用forkeyPath
iOS中的多線程
1>一個NSTread對象就代表一條線程
2>創(chuàng)建和啟動線程
NSThread *thread =[[NSThread alloc]initWithTarget:selfselector:@selector(run:)object:@"hah"];
? [thread start];
3>主線程相關的用法
[NSThread mainThread];
[NSThread isMainThread];
?[thread isMainThread];
4>設置線程的優(yōu)先級
? ? [NSThread threadPriority];查看當前線程的優(yōu)先級
? ? [NSThread setThreadPriority:0.5];設置當前線程的優(yōu)先級
5>設置線程的名字
? ? thread.name = @"線程一";
6>創(chuàng)建線程的時候就啟動線程
?[NSThread detachNewThreadWithBlock:^{
? ? }];
? ? [NSThread detachNewThreadSelector:@selector(run:)toTarget:selfwithObject:@"哈哈"];
7>隱shi創(chuàng)建
? ? [selfperformSelectorInBackground:@selector(run:)withObject:@"哈哈”];
線程的狀態(tài)
當線程在阻塞和死亡狀態(tài)的時候,會退出可調度線程池中。但是內存還在。
線程狀態(tài)的控制
最后的參數(shù)是說這個performSelector方法是否等待執(zhí)行完畢,才繼續(xù)跳出子線程操作
GCD
會自動幫我們創(chuàng)建線程
MRC中隊列是需要釋放的? 當調用creat方法的時候,要調用dispatch_release(queue)方法去釋放隊列
在ios中凡是函數(shù)帶有create、copy/new/retain等字眼,都需要在不需要使用這個數(shù)據(jù)的時候調用release操作
?CFArrayRef array = CFArrayCreate(0,0,11,0);
? ? CFRelease(array);在調用CF函數(shù)的時候,即使是在arc環(huán)境下也需要調用一下release操作
CF(core Facation)框架在ARC中也需要手動release
同步函數(shù):
*串行隊列:不開啟新的線程,任務串行執(zhí)行
*串行隊列(主隊列)會出現(xiàn)死鎖
*并行隊列:不開啟新線程,任務串行執(zhí)行
異步函數(shù):
*串行隊列 :開啟一條新的線程,任務并行執(zhí)行
*串行隊列(主隊列)不會開啟新的線程
*并行隊列: 開啟新的線程,任務并行執(zhí)行
? ? dispatch_queue_t mainqueue = dispatch_get_main_queue();
? ? dispatch_sync(mainqueue,^{
? ? ? ? NSLog(@"這樣會死鎖");
? ? });
dispatch_queue_t mainqueue = dispatch_get_main_queue();
? ? dispatch_async(mainqueue,^{
? ? ? ? NSLog(@"這樣不會發(fā)生死鎖");
? ? });
因為異步函數(shù)雖然也是放在了主線程中,但是比較特殊,會將block中的代碼緩后執(zhí)行,所以不會出現(xiàn)死鎖
延遲執(zhí)行:
第一GCD:
?//全局并發(fā)隊列
? ? dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
? ? //計算執(zhí)行任務的時間
? ? dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW,(int64_t)(3.0 * NSEC_PER_SEC));
? ? //在when的這個時間點去執(zhí)行queue的任務
? ? dispatch_after(when,queue,^{
? ? });
第二:
? ? [selfperformSelector:@selector(run:)withObject:@"hahha" afterDelay:3.0];
一次性代碼
?staticdispatch_once_t onceToken;
? ? dispatch_once(&onceToken,^{
? ? });
#define global_queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)
#define main_queue dispatch_get_main_queue()
?dispatch_group_t group = dispatch_group_create();
? ? dispatch_group_async(group,global_queue,^{
? ? ? ? //下載圖片1
? ? });
? ? dispatch_group_async(group,global_queue,^{
? ? ? ? //下載圖片2
? ? });
? ? dispatch_group_notify(group,main_queue,^{
? ? ? ? //當任務一 與 任務二 完成之后,回到主線程中去操作
? ? });
NSOpertion:
多線程
1.NSThread
1> 開線程的幾種方式
* 先創(chuàng)建,后啟動
NSThread *thread =[[NSThread alloc]initWithTarget:selfselector:@selector(run)object:nil];
[thread start];
* 直接啟動
[NSThread detachNewThreadSelector:@selector(run)toTarget:selfwithObject:nil];
[selfperformSelectorInBackground:@selector(run)withObject:nil];
2> 其他用法
NSThread *current =[NSThread currentThread];
+(NSThread *)mainThread;// 獲得主線程
3> 線程間通信
performSelectorOnMainThread.....
2.GCD(重點)
1> 隊列的類型
* 并發(fā)隊列
獲得全局的并發(fā)隊列: dispatch_get_global_queue
* 串行隊列
a.自己創(chuàng)建
dispatch_queue_create
b.主隊列
dispatch_get_main_queue
2> 執(zhí)行任務的方法類型
*同步(sync)執(zhí)行
*異步(async)執(zhí)行
3> 了解隊列和方法的配合使用
4> 線程間通信
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
?? // 執(zhí)行耗時的異步操作...
?? dispatch_async(dispatch_get_main_queue(),^{
?? ? ? // 回到主線程,執(zhí)行UI刷新操作
?? });
});
5> 其他用法
dispatch_once
dispatch_after
dispatch_group_async\dispatch_group_notify
3.NSOperation
1> 基本使用
NSInvocationOperation
NSBlockOperation
2> NSOperationQueue(重點)
* 最大并發(fā)數(shù)設置
-(void)setMaxConcurrentOperationCount:(NSInteger)cnt;
* 設置依賴(面試題)
[operationB addDependency:operationA];// 操作B依賴于操作A
3>自定義Operation(了解基本流程)
4> 如何解決一張圖片(一個url)重復下載的問題(面試題)