Objective-C語法

一、OC簡介

OC_類與對象.png

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)造器

繼承.初始化.便利構(gòu)造器.png
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ù)類型

五、 字典、集合

NSDictionary NSSet.png
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:


  1. 集合類型的快速枚舉
    快速枚舉:
    for(<#type*object#> in <#collection#>){ }
    ①object是遍歷得到的元素對象
    ②collection是集合類型的對象:數(shù)組,字典,集合.
    特點:
    ①數(shù)組枚舉得到數(shù)組中的元素對象
    ②字典枚舉得到字典中的key值
    ③集合枚舉得到集合中的元素對象

2.數(shù)組排序

  • (NSArray *)sortedArrayUsingSelector:(SEL)comparator;
  • (void)sortUsingSelector:(SEL)comparator;

六、 Block

block.png

代碼塊本質(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

七、 時間日期

類的擴(kuò)展.png
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 類目
  1. 為沒有源代碼的類添加方法
  1. 添加的類會成為原類的一部分 可以被繼承
4. Extension 類的延展

為自定義類定義"私有的”方法 外部不可訪問

兩種定義方法:

  1. 定義一個 Extension 文件 只有.h文件 在里面添加 方法
  2. 在需要的類的.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é)議步驟:

  1. 在類的.h文件 父類名后寫上<協(xié)議名>
  2. 在.m文件中實現(xiàn)協(xié)議中的方法

delegate 代理

Protocol 的核心使用場景是實現(xiàn)delegate設(shè)計模式

八、屬性

屬性.png
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)存管理初級

OC_內(nèi)存管理低級.png

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é)果


打印結(jié)果

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

OC_內(nèi)存管理高級.png

屬性內(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):

父類指針可以指向子類對象

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 蘋果官方文檔翻譯 《Objective-C語言編程》(Programming with Objective-C) ...
    fever105閱讀 26,323評論 19 129
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,696評論 18 399
  • 定義類: 使用:(冒號)表示繼承一個類 使用()定義一個Catagory(類別) 作用:在不改變原有類結(jié)構(gòu)的基礎(chǔ)上...
    GoGooGooo閱讀 602評論 0 1
  • 莫回顧 遙望天涯昏暮 此途疏 走遍一生未卜 倚雪竹 蕭笛共吹一曲誰來舞 便入凡俗 將木石之盟放逐 我妄圖棄天下參這...
    下海經(jīng)商的哪咤閱讀 221評論 0 0
  • 放過自己的過去 曾經(jīng)的丑陋和不堪 也放下那些 曾讓自己驕傲放肆的東西 向前看 也向錢看 裝點自己 充實自己 收...
    一山二樹閱讀 181評論 0 2

友情鏈接更多精彩內(nèi)容