一、OC簡介

Objective_C簡稱OC,是 C語言的超集(兼容 C 的代碼)
OC是擴(kuò)充自C語言的面向?qū)ο缶幊陶Z言
面向?qū)ο缶幊蹋篛OP (Object Oriented(面向) Programming)
面向?qū)ο筇攸c包括:封裝 、繼承 、多態(tài)
面向?qū)ο?與 面向過程 :是兩種不同的編程思想
類和對象
流程:定義類—>創(chuàng)建對象—>使用對象
類:具有相同特征或行為的事物的抽象
對象:就是類的實例(類是對象的類型)
1.定義類
類的定義:
①接口部分:對外聲明類的特征和行為 // 接口部分和實現(xiàn)部分要分開寫
標(biāo)識: @interface…@end
包含內(nèi)容:類名、父類名、實例變量、方法等
②實現(xiàn)部分:對內(nèi)實現(xiàn)行為
標(biāo)識:@implementation...@end
包含內(nèi)容:實現(xiàn)方法 即實現(xiàn)類的行為
.h文件(接口文件或頭文件)
@interface person/*類名*/ : NSObject/*父類名*/{
@public //實例變量(特征)
NSString *_name; //姓名
NSString *_sex; //性別
NSString *_hobby; //興趣
int _age; //年齡
}
/************方法(行為部分)************/
- (void)sayHi;- (void)eat;
@end
.m文件(實現(xiàn)文件)
@implementation person//實現(xiàn)方法(實現(xiàn)行為)
- (void)sayHi{ NSLog(@"你好,我叫%@,今年%d歲,喜歡%@",_name,_age,_hobby);
}
- (void)eat{
NSLog(@"我要去吃飯");
}
@end
2.創(chuàng)建對象
①分配內(nèi)存空間:根據(jù)類中聲明的實例變量為對象分配內(nèi)存,將所有實例變量置為默認(rèn)值0,并返回首地址
person *p = [person alloc];
②初始化:為對象的實例變量設(shè)置初始值
p = [p init];
以上兩步可寫在一起: person *p = [[person alloc]init];
+(id)alloc; +號表示這個方法屬于類,只能類執(zhí)行。id返回值類型,表示任意類型的對象,即創(chuàng)建好的對象
-(id)init; -號表示這個方法屬于對象,只能對象執(zhí)行。id返回值類型,表示初始化完成的對象
子類可以重寫父類的方法:

二、實例變量可見度和方法
實例變量的可見度:
@public(公有的) :實例變量可以在類的外部和內(nèi)部操作
@protected(受保護(hù)的,默認(rèn)的) : 實例變量只能在該類和其子類內(nèi)操作
@private(私有的) : 實例對象只能在該類內(nèi)訪問
方法:
①類方法:只能類使用 例:+(id)alloc 注:類方法不能使用實例變量
②實例方法:只能對象使用,例如:-(void)sayHi
例:- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject
包括:方法類型標(biāo)示符,返回類型 ,參數(shù)形容詞:參數(shù)類型,參數(shù)名
“ : ”標(biāo)識參數(shù)不能省略。由冒號必須有參數(shù)
③方法使用:
[people sayHi]; 給people發(fā)送sayHi消息,或者使用點語法 people.sayHi;
1.setter:設(shè)置器(為實例變量賦值的方法)
如果一個實例變量是 int age 或者 _age.
setter書寫格式:-(void)setAge:(int)age;(忽略下劃線)
//傳參時有幾個冒號 ,就是傳幾個參數(shù)
2.getter:訪問器(讀取實例變量值的方法)
getter書寫格式:-(int)age;(忽略下劃線)
注意:無論是setter還是getter,內(nèi)部操作都是實例變量,(每個實例變量都需要一對setter和getter方法)
3.自定義初始化方法:
-(id)initWithName:(NSString *)name sex:(NSString * )sex;
類的引用:
#import :導(dǎo)入頭文件
#import “”導(dǎo)入自定義類
#import <>導(dǎo)入類庫中的頭文件
// 類似于C語言中的 #include 但是可以避免頭文件重復(fù)導(dǎo)入
@class:
告訴編譯器@class后的字符串作為類名使用,并未導(dǎo)入類的接口內(nèi)容
有效避免嵌套循環(huán)導(dǎo)入
三、繼承、初始化、遍歷構(gòu)造器

1.繼承:父類 、子類
①繼承是單向的,不可相互繼承
②傳遞性:A繼承于B,B繼承于C,則A 同時具有 B和C的特征和行為
③子類可以繼承父類全部的特征和行為(也可具備部分特征或行為)//@private標(biāo)識的父類特征 不能被繼承
④OC中只允許單繼承(即每個類只能有一個父類)
⑤沒有父類的類稱為根類。OC中基類是NSObject(祖宗)
⑥繼承的內(nèi)容:所有實例變量和方法
⑦如果子類不滿意父類方法的實現(xiàn),可以重寫父類的方法。
2.初始化方法
兩步:①開辟空間alloc ②初始化init
作用:為某些實例變量賦初值
初始化方法在對象的整個生命周期里只是用一次
3.super 編譯器指令,并非對象
作用:給super發(fā)消息,可以執(zhí)行父類中實現(xiàn)的方法
子類可以重寫父類的方法,即子類既有自己的實現(xiàn),又有父類繼承下來的實現(xiàn),如果想使用父類的實現(xiàn),向super發(fā)送消息
完整初始化方法:
@implementation Student
- (instancetype)init{
//給super發(fā)送init消息,即執(zhí)行父類中實現(xiàn)的init方法
self = [super init];
if (self) {
//初始化設(shè)置
}
return self; //返回初始化完成的對象
}
//便利構(gòu)造器:(+方法)
//封裝了alloc和初始化方法,使用起來更加簡潔
+(instancetype)girlFriendWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age{
GirlFriend *g = [[GirlFriend alloc]initWithName:name gender:gender age:age];
return g;
}
四、字符串、數(shù)組
#pragma mark ------------- NSString -----------
#pragma mark賦值
NSString*s1 =@"123";
NSLog(@"s1 = %@",s1);
#pragma mark初始化方法
//一般初始化
NSString*s2 = [[NSString alloc]initWithFormat:@"%@今年%@歲",@"小明",@"18"];
NSLog(@"s2 = %@",s2);
//便利構(gòu)造器初始化
NSString*s3 = [NSString stringWithString:s2];
NSLog(@"s3 = %@",s3);
NSString*s4 = [NSString stringWithFormat:@"%@你好",@"美女"];
NSLog(@"s4 = %@",s4);
#pragma mark通過文件路徑獲取文件中的字符串
NSString*s5 = [NSString stringWithContentsOfFile:@"/Users/王勝利/Objective_C/OC_課堂及作業(yè)/OCLesson4_課后/OCLesson4_課后/1.txt"encoding:NSUTF8StringEncodingerror:nil];
NSLog(@"s5 = %@",s5);
//usedEncoding :表示不知道編碼方式 寫nil
#pragma mark length
NSUIntegerui = [s5 length];
NSLog(@"lenthOfs5 is %lu",ui);
#pragma mark前后綴
BOOLb1 = [s4 hasPrefix:@"美女"];//判斷前綴
BOOLb2 = [s4 hasSuffix:@"約么"];//判斷后綴
NSLog(@"前綴%d,后綴%d",b1,b2);
#pragma mark大小寫轉(zhuǎn)換
NSString*s6 =[s5 capitalizedString];
NSLog(@"首字母大寫:%@",s6);
NSString*s7 = [s6 uppercaseString];
NSLog(@"所有字母大寫:%@",s7);
NSString*s8 = [s7 lowercaseString];
NSLog(@"所有字母小寫:%@",s8);
#pragma mark比較字符串大小
NSComparisonResult b3 = [s6 compare:s7];
NSLog(@"compareResult = %ld",b3);
#pragma mark判斷字符串是否相等
BOOLb4 = [s6 isEqualToString:s8];
#pragma mark 獲取某個index的字符(遍歷)
NSLog(@"%c",[s6 characterAtIndex:3]);
#pragma mark截取字符串
NSString*s9 = [s6 substringFromIndex:3];//截取index = 3往后的內(nèi)容(包含index = 3)
NSString*s10 = [s6 substringToIndex:2];//截取到index = 2(不包含index = 2)
NSString*s11 = [s6 substringWithRange:NSMakeRange(5,4)];//從index = 5開始截取4個字符
#pragma mark ----------NSMutableString---------
//NSMutableString 繼承于NSString 上面NSString方法NSMutableString同樣適用
NSMutableString*mS1 = [[NSMutableString alloc]initWithFormat:@"abc123"];
#pragma mark改
[mS1 setString:@"ABC123"];
#pragma mark拼接
[mS1 appendString:@"def"];
#pragma mark 替換掉某一范圍的字符串
[mS1 replaceCharactersInRange:NSMakeRange(3,3) withString:@"456"];
#pragma mark刪除
[mS1 deleteCharactersInRange:NSMakeRange(3,3)];
#pragma mark插入
[mS1 insertString:@"hijk"atIndex:5];
#pragma mark ---------------NSArray----------------
#pragma mark初始化方法
NSArray*a1 = [[NSArray alloc]initWithObjects:@"1",@"2",@"3",nil];
//便利構(gòu)造器
NSArray*a2 = [NSArray arrayWithObjects:@"4",@"5",@"6",nil];
NSArray*a3 = [NSArray arrayWithArray:a2];
//字面量(語法糖)
NSArray*a4 =@[@"a",@"b",@"c"];
#pragma mark獲取元素個數(shù)
NSUInteger ui1 = [a1 count];
#pragma mark取出元素下標(biāo)
NSUInteger ui2 = [a4 indexOfObject:@"b"];
#pragma mark根據(jù)下標(biāo)取出下標(biāo)所有的元素
NSString*s = [NSString stringWithString:[a4 objectAtIndex:2]];
#pragma mark -----------NSMutableArray-----------
NSMutableArray*mA =[NSMutableArray arrayWithArray:a1];
#pragma mark 增加元素
[mAaddObject:@"4"];
#pragma mark 刪除元素
[mA removeLastObject];
[mA removeObjectAtIndex:2];
#pragma mark插入元素
[mAinsertObject:@"3"atIndex:2];
#pragma mark替換
[mA replaceObjectAtIndex:2withObject:@"a"];
#pragma mark -------------NSNumber-----------
inti =2;
NSNumber*_i = [NSNumber numberWithInt:i];//將int基本數(shù)據(jù)類型轉(zhuǎn)換成對象類型
[_i stringValue];//將對象類型 轉(zhuǎn)換成 字符串
inta = [_i intValue];//將對象類型轉(zhuǎn)換成基本數(shù)據(jù)類型
五、 字典、集合

1 .NSDictionory字典
定義:字典是用于保存具有映射關(guān)系(key - value對)數(shù)據(jù)的集合
特征:
①key- value 在 dictionary中認(rèn)為是一個條目(Entry)
②key不能重復(fù),value必須是對象
③鍵值對在字典中是無序存儲的
NSDictionary不可變字典:
字典一旦創(chuàng)建,鍵值對就無法改變,不可添加,不可刪除, 只讀
2.NSMutableDictionary可變字典:
可以對字典進(jìn)行 <增><刪><改> 操作
3.NSSet集合
特征:
①集合中元素唯一
②存儲的數(shù)據(jù)是無序存儲
③存儲元素必須是對象類型
NSSet:
NSMutableSet:
NSCountedSet:
- 集合類型的快速枚舉
快速枚舉:
for(<#type*object#> in <#collection#>){ }
①object是遍歷得到的元素對象
②collection是集合類型的對象:數(shù)組,字典,集合.
特點:
①數(shù)組枚舉得到數(shù)組中的元素對象
②字典枚舉得到字典中的key值
③集合枚舉得到集合中的元素對象
2.數(shù)組排序
- (NSArray *)sortedArrayUsingSelector:(SEL)comparator;
- (void)sortUsingSelector:(SEL)comparator;
六、 Block

代碼塊本質(zhì)上是和其他變量類似。不同的是,代碼塊存儲的數(shù)據(jù)是一個函數(shù)體。使用代碼塊是,你可以像調(diào)用其他標(biāo)準(zhǔn)函數(shù)一樣,傳入?yún)?shù)數(shù),并得到返回值。
脫字符(^)是塊的語法標(biāo)記。按照我們熟悉的參數(shù)語法規(guī)約所定義的返回值以及塊的主體(也就是可以執(zhí)行的代碼)。下圖是如何把塊變量賦值給一個變量的語法講解:
按照調(diào)用函數(shù)的方式調(diào)用塊對象變量就可以了:int result = myBlock(4); // result是 28
1.參數(shù)是NSString*的代碼塊
void (^printBlock)(NSString *x);
printBlock = ^(NSString* str) {
NSLog(@"print:%@", str);
};
printBlock(@"hello world!");
運行結(jié)果是:print:hello world!
2、代碼用在字符串?dāng)?shù)組排序
NSArray *stringArray = [NSArray arrayWithObjects:@"abc 1", @"abc 21", @"abc 12",@"abc 13",@"abc 05",nil];
NSComparator sortBlock = ^(id string1, id string2) {
return [string1 compare:string2];
};
NSArray *sortArray = [stringArray sortedArrayUsingComparator:sortBlock];
NSLog(@"sortArray:%@", sortArray);
運行結(jié)果:sortArray:(
** "abc 05",**
** "abc 1",**
** "abc 12",**
** "abc 13",**
** "abc 21"**
)
3、代碼塊的遞歸調(diào)用
代碼塊想要遞歸調(diào)用,代碼塊變量必須是全局變量或者是靜態(tài)變量,這樣在程序啟動的時候代碼塊變量就初始化了,可以遞歸調(diào)用
static void (^ const blocks)(int) = ^(int i) {
if (i > 0) {
NSLog(@"num:%d", i);
blocks(i - 1);
}
};
blocks(3);
運行打印結(jié)果:
num:3
num:2
num:1
4、在代碼塊中使用局部變量和全局變量
在代碼塊中可以使用和改變?nèi)肿兞?/p>
int global = 1000;
int main(int argc, const char * argv[]) {
@autoreleasepool {
void(^block)(void) = ^(void) {
global++;
NSLog(@"global:%d", global);
};
block();
NSLog(@"global:%d", global);
}
return 0;
}
運行打印結(jié)果:
global:1001
而局部變量可以使用,但是不能改變。
int local = 500;
void(^block)(void) = ^(void) {
local++;
NSLog(@"local:%d", local);
};
block();
NSLog(@"local:%d", local);
在代碼塊中改變局部變量編譯不通過。怎么在代碼塊中改變局部變量呢?在局部變量前面加上關(guān)鍵字:__block
__block int local = 500;
void(^block)(void) = ^(void) {
local++;
NSLog(@"local:%d", local);
};
block();
NSLog(@"local:%d", local);
運行結(jié)果:local:501
七、 時間日期

1. NSDate
NSDate *date = [NSDate date];//初始化 獲取0時區(qū)現(xiàn)在日期時間
NSTimeZone *zone = [[NSTimeZone alloc]init]; zone = [NSTimeZone localTimeZone];//獲取本地時區(qū)
NSInteger offest = [zone secondsFromGMT];//獲取本地時區(qū)和0時區(qū)的時間差 (以 分鐘 算)
NSTimeInterval subTime = [date1 timeintervalSinceDate: date2];//計算兩個日期的時間差
2. NSDateFormatter
//作用:iOS中的時間日期格式類 用于實現(xiàn)NSString和NSDate的互相轉(zhuǎn)化
NSDateFormatter *formatter = [[NSDateFormatteralloc]init];
[formatter setDateFormat:@"yyyy年MM月dd日 HH點mm分ss秒"];
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:8]];
// 1.將日期轉(zhuǎn)換成字符串輸出
NSString *date1 = [formatter stringFromDate:[NSDate date]];
NSLog(@"%@",date1);
NSString *s = @"2014年05月01日 10點23分18秒";
// 2.將字符串轉(zhuǎn)換為日期
NSDate *date2 = [formatter dateFromString:s];
NSLog(@"%@",date2);
蘋果系統(tǒng)內(nèi)部,時間是以零時區(qū)為基準(zhǔn)存儲
默認(rèn)情況下
stringFormDate:(把日期轉(zhuǎn)換成字符串顯示) 系統(tǒng)會自動 算 零時區(qū)時間加上 時區(qū)差(GTM) 的時間顯示
dateFromString:(把時間字符串轉(zhuǎn)換成日期) 系統(tǒng)存儲零時區(qū)時間,,默認(rèn)會把我們輸入的時間減去 時區(qū)差(GTM)存儲在系統(tǒng)中
使用 NSDateFormatter 時 格式化格式 還有時區(qū)
3. Category 類目
- 為沒有源代碼的類添加方法
- 添加的類會成為原類的一部分 可以被繼承
4. Extension 類的延展
為自定義類定義"私有的”方法 外部不可訪問
兩種定義方法:
- 定義一個 Extension 文件 只有.h文件 在里面添加 方法
- 在需要的類的.m 文件上面 添加 @Interface 類名() 方法名 @end
5. Protocol 協(xié)議
就是一套標(biāo)準(zhǔn)(一堆方法聲明),,只有.h文件
在接受協(xié)議的對象的類的.m中實現(xiàn)協(xié)議中定義的方法
關(guān)鍵字:
@required 默認(rèn)的,方法 代理必須實現(xiàn)
@optional 可以選擇實現(xiàn),,也可以不實現(xiàn)
遵守協(xié)議步驟:
- 在類的.h文件 父類名后寫上<協(xié)議名>
- 在.m文件中實現(xiàn)協(xié)議中的方法
delegate 代理
Protocol 的核心使用場景是實現(xiàn)delegate設(shè)計模式
八、屬性

1.屬性 @property
為實例變量提供了setter getter 方法的默認(rèn)實現(xiàn)
.h文件中 @property 聲明了兩個方法 (setter getter)
.m文件中 使用@synthesize實現(xiàn)屬性
注意:使用@property聲明屬性 可以省略 @synthesize和實例變量
2.屬性的屬性 attribute
//1.讀寫設(shè)置
//讀寫性控制:readwrite 讀寫 (默認(rèn)設(shè)置) 即聲明setter 又聲明getter
@property(readwrite) NSString *name;
//readonly 只讀 只聲明getter方法
@property(readonly) NSString *sex;
//setter 給getter重命名
@property(getter= fun1)NSString * address;
//getter 給setter重命名
/*自定義方法名后面加冒號 (setter有參數(shù))*/
@property(setter=setPhoneNum:)NSString *phoneNum;
//2.原子能設(shè)置
//原子性控制atomic (默認(rèn)設(shè)置) setter getter內(nèi)部做了多線程訪問處理,多線程訪問下比較安全 (缺點:暫用系統(tǒng)線程資源,單線程下不建議適用)
@property(atomic)NSString *hobby;
//nonatomic : setter getter內(nèi)部沒有做多線程訪問處理,,(程序通常使用nonatomic,只有當(dāng)屬性需要線程安全是,才定義 atomic)
@property (nonatomic)NSString *job;
//3.類型設(shè)置
//語義設(shè)置assign :(在setter getter 內(nèi)部直接復(fù)制)當(dāng)屬性是非對象類型(int float 等基本數(shù)據(jù)類型)時使用
@property (nonatomic ,assign)NSInteger age1;
//retain : setter getter 內(nèi)部會做內(nèi)存優(yōu)化 (當(dāng)屬性是對象時使用)
@property (nonatomic ,retain)NSString *name1;
//copy : 同 retain 一樣,setter getter內(nèi)部會做內(nèi)存優(yōu)化,,,但是copy遵循(NSCopying協(xié)議) 當(dāng)屬性是對象類型,并且想要得到參數(shù)時,使用copy 關(guān)鍵字
@property(nonatomic ,copy)NSString *address1;
// 4.點語法(配合setter getter 或者屬性一起使用)
SingleDog *sdog1 = [[SingleDog alloc]init]; [sdog1 setName:@"zhangsan"];
[sdog1 name];
// 直接使用點語法賦值 (只要有setter getter方法)
sdog1.name = @"lisi"; NSLog(@"%@",sdog1.name); sdog1.gender = @"nan";
NSLog(@"%@",sdog1.gender);
//5.KVC(Key - Value - Coding) 鍵值編碼
是一種間接訪問實例變量的方法
key : 鍵 (用于標(biāo)識實例變量)
value : 實例變量的值
①//使用KVC給實例變量賦值
//類似于setter方法
[sdog1 setValue:@"wangwu" forKey:@"name"];
//獲取值
//類似于getter方法
NSLog(@"%@",[sdog1 valueForKey:@"name"]);
//②KVC可以給私有變量(@private修飾的實例變量)賦值和取值 (key不能寫錯,字符串匹配)
[sdog1 setValue:@"dasfafa" forKey:@"phoneNum"];
//③ 當(dāng)key不存在的時候,系統(tǒng)會執(zhí)行setValue:forUndefinedKey:
//然后拋出一個異常,但是 該方法只與 setValue:ForKey搭配使用
//注意:一般從網(wǎng)絡(luò)上請求下來的數(shù)據(jù),一般都是數(shù)組套字典,字典套數(shù)組之類的,直接用KVC去取值賦值這時候一定要加上 setValue :forUndefinedKey這個方法(防止崩潰)
//④setValue:forKeyPath使用點語法 ,,引用路徑 設(shè)置或輸出值
Pig *p1 = [[Pigalloc]init];
Food *f1 = [[Foodalloc ]init];
[p1 setValue:f1 forKey:@"food"];
[p1 setValue:@"白菜" forKeyPath:@"[food.name](http://food.name/)"];
NSLog(@"%@",[p1 valueForKeyPath:@"[food.name](http://food.name/)"]);
NSLog(@"%@",[f1 valueForKey:@"name"]);
//⑤setValue:ForKeysWithDictionary借用字典同時設(shè)置讀取多個key 和 value
NSMutableDictionary *dic1 = [NSMutableDictionarydictionary];
NSDictionary *dic2 =[NSDictionary dictionaryWithObjectsAndKeys:@"zhaoda",@"name",@"nan",@"gender", nil];
[dic1 setValuesForKeysWithDictionary:dic2];
NSLog(@"%@",dic1);
[sdog1 setValuesForKeysWithDictionary:dic2];
NSLog(@"%@ %@",sdog1.name,sdog1.gender);
九、內(nèi)存管理初級

iOS應(yīng)用出現(xiàn) Crash(閃退) ,90%原因是因為內(nèi)存問題
//主要有 :內(nèi)存溢出 野指針異常 過早釋放等
//垃圾回收(gc):java 里的內(nèi)存管理機(jī)制(程序員只負(fù)責(zé)開辟,由系統(tǒng)自己判斷哪些空間不再使用并收回)
OC中的兩種內(nèi)存管理方式:
MRC:(Manual Reference Count)手動引用計數(shù)
內(nèi)存的開辟和釋放都是有程序代碼進(jìn)行控制.(對程序員要求較高)
ARC:(Auto Reference Count)自動引用計數(shù)
iOS 5 之后新加的編譯器特性,程序員只負(fù)責(zé)開辟空間,不用去釋放
// ARC的本質(zhì)還是MRC,只是編譯器加了自動釋放的代碼
C語言中
:使用malloc和free 進(jìn)行堆內(nèi)存的創(chuàng)建和釋放,,堆內(nèi)存只有使用和銷毀兩種狀態(tài)
OC中
:引用引用計數(shù)機(jī)制來管理內(nèi)存(多個指針同時放問一款內(nèi)存)當(dāng)一個新的引用指向?qū)ο髸r,引用計數(shù)器就遞增,當(dāng)去掉一個引用時,引用計數(shù)就遞減.當(dāng)引用計數(shù)到零時,該對象就將釋放占有的資源
影響引用計數(shù)的方法:
1.alloc:開辟內(nèi)存空間 引用計數(shù)從0到1
Person *p1 = [[Person alloc]init];
2.retain:引用計數(shù) + 1
Person*p2 = [p1 retain];
//實際開發(fā)中不用
//注意:當(dāng)使用retain是若不找另一個指針子向它,則會出現(xiàn)內(nèi)存泄露問題
retainCount方法:獲取當(dāng)前對象的引用計數(shù).
NSLog(@"%lu",[p1 retainCount]);
//注意:1.實際開發(fā)中 retainCount不要用 2.即使要用也只能用在自定義的類上
3.copy :將某一內(nèi)存區(qū)域的內(nèi)容拷貝一份,拷貝到新的內(nèi)存空間中,(被拷貝的引用計數(shù)不變,新的內(nèi)存區(qū)域引用計數(shù)為1)
4.release:引用計數(shù) -1
//當(dāng)一個對象用完之后,要用 release 或者 autoRelease 去釋放
//release 到0之后不能再繼續(xù) release 過度釋放也會崩潰
5.dealloc:銷毀對象
他是繼承自父類的方法,當(dāng)引用計數(shù)為0的時候,由對象自動調(diào)用
//一般我們要在類的.m文件中重寫一下dealloc方法,,把我們聲明的屬性也銷毀
- (void)dealloc{
//[_age release];//assign
修飾非對象類型,,沒有對引用計數(shù)產(chǎn)生影響,,,無需釋放
[_name release];
//對象銷毀了,
屬性沒有用,也要銷毀
[_gender release];
NSLog(@"%@被銷毀",self);
[super dealloc];
}
6.autorelease:在未來的某一時刻引用計數(shù) -1.
autorelease對象的釋放收 autoreleasepool 的控制
NSAutoreleasePool*pool = [[NSAutoreleasePool alloc]init];
Person*p6 = [[Person alloc]init];
[p6 retain];
[p6 autorelease];
NSLog(@"++++%lu",[p6 retainCount]);
[pool release];
NSLog(@"====%lu",[p6retainCount]);
// 從開辟空間初始化autoreleaepool對象,到pool對象被release 就相當(dāng)于@autoreleasepool加上{}
//但自iOS 5之后推薦使用 @autoreleasepool { }
//@autoreleasepool { }出了大括號,自動釋放池才向各個對象發(fā)送release消息
//如果使用了@autoreleasepool{} ,,,自動釋放池是一種棧的結(jié)構(gòu)
總之,凡是使用了alloc retain copy 讓內(nèi)存的引用計數(shù)增加了,就需要使用release或者autorelease讓內(nèi)存的引用計數(shù)減少,在一段代碼內(nèi),增加和減少的次數(shù)要相等
copy方法 :
**一個對象想要copy,生成自己的副本,需要遵守NSCopying協(xié)議,定義copy的細(xì)節(jié),,(如果類沒有接受NSCopying協(xié)議而給對象發(fā)送copy消息,會引起carsh)**
.h文件
@interfacePerson :NSObject<NSCopying>//手動添加遵守NSCopying協(xié)議
@property(nonatomic,copy)NSString*name;
@end
.m文件
@implementation Person
- (void)dealloc{
[_name release];
NSLog(@"銷毀");
[super dealloc];
}
//- (id)copyWithZone:(NSZone *)zone{
// //[self retain]把引用計數(shù)+1
// return [self retain];
// //淺拷貝相當(dāng)于只拷貝了指針 (retain只不過它遵循了NSCopying協(xié)議)
//}
- (id)copyWithZone:(NSZone*)zone{
Person*p = [[ Person alloc]init];
p.name=self.name;
return p;
//深拷貝新建了一個對象,并將對象return出去
//真正意義上得拷貝,他開辟了一個新的空間對象也return了出去
}
@end
main.m文件
Person*p1 = [[Person alloc]init];
Person*p2 = [p1 copy];
NSLog(@"%p",p1);
NSLog(@"%p",p2);
NSLog(@"%lu",[p1 retainCount]);
NSLog(@"%lu",[p2 retainCount]);
打印結(jié)果

十、內(nèi)存管理高級

屬性內(nèi)部實現(xiàn)
assign:
- (NSInteger)age{
return _age;
}
- (void)setAge:(NSInteger)age{
_age = age;
}
retain:
- (NSString *)name{
return [[_name retain] autorelease];
}
- (void)setName:(NSString *)name{
if (_name != name) {
[_name release];
_name = [name retain];
}
}
copy:
- (NSString *)gender{
return [[_gender retain]autorelease];
}
- (void)setGender:(NSString *)gender{
if (_gender != gender) {
[_gender release];
_gender = [gender copy];
}
}
delloc://由系統(tǒng)自動調(diào)用,,永遠(yuǎn)不要自己手動調(diào)用
- (void)dealloc{
[_name release];
[_gender release];
[super dealloc];//最后一定要調(diào)用父類的delloc方法
}
便利構(gòu)造器的內(nèi)存管理
+(instancetype)personWithName:(NSString *)name Age:(NSInteger)age Gender:(NSString *)gender{
Person *p = [[Person alloc]initWithName:name Age:age Gender:gender];
// [p release];//release 寫在上面,下面return是,,p就成了野指針
// return p;
// [p ralease];//release寫在下面,,會出現(xiàn)內(nèi)存泄露
return [p autorelease];
}
//如果是便利構(gòu)造器聲明的對象,無需釋放,因為便利構(gòu)造器內(nèi)部謝了autorelease方法,,出了花括號自動釋放
Collection(NSArray等容器類)的內(nèi)存管理
- 加入collection的對象會被retain
- 移除collection的對象會被release
- collection被釋放時,會對內(nèi)部所有對象release
多態(tài):
父類指針可以指向子類對象
