認(rèn)識(shí)oc字符串NSString
NSString是一個(gè)Unicode編碼簇爆、16位字符的字符序列
NSString被定義為類穷娱,引用類型,拷貝時(shí)具有引用語義
初始化方法:字面量初始化、初始化器砂缩、工廠方法
NSString擁有恒定性,所有的操作無法更改字符串本身三娩,如有更改都是返回新值的形式
NSString擁有共享機(jī)制庵芭,引用計(jì)數(shù)管理對其有特殊的管理規(guī)則
<small>恒定性與共享機(jī)制相輔相成,正因?yàn)橛辛斯蚕頇C(jī)制雀监,才需要恒定性來保證原字符串不發(fā)生變化双吆。同時(shí)共享機(jī)制也為系統(tǒng)內(nèi)存管理帶來了很大的好處,通常應(yīng)用中字符串的用量很大会前,如果每個(gè)相同的字符串都有一個(gè)自己的內(nèi)存空間好乐,那就會(huì)造成很大的資源浪費(fèi)。所以瓦宜,在oc中蔚万,當(dāng)我們申明一個(gè)字符串,而這個(gè)字符串在內(nèi)存中已經(jīng)存在临庇,那么該指針就會(huì)指向已存在的字符串地址上</small>
NSMutableString
NSMutableString具有可變性反璃,NSString具有恒定性
NSMutableString為NSString的子類
NSMutableString不具有共享性,NSString具有共享性
NSMutableString并不是在原有內(nèi)存上直接增長假夺,而是重新分配一個(gè)更大或更小的緩存容量存放字符
數(shù)組 列表 字典
<small>- 類型差不多淮蜈,這里主要詳細(xì)講數(shù)組</small>
認(rèn)識(shí)數(shù)組:
- 數(shù)組是一個(gè)有序的元素序列,支持隨機(jī)存取已卷。索引從0開始梧田,索引訪問越界會(huì)拋出運(yùn)行時(shí)異常。注意與C語言不通。
- NSArray被定義為class柿扣,引用類型肖方,拷貝時(shí)具有引用語義。
- NSArray的元素必須是對象未状,即NSObeject的子類:
1.如為基本數(shù)值類型俯画,須用NSNumber封裝為對象類型后,才能放入數(shù)組中司草。
2.如為C語言結(jié)構(gòu)類型艰垂,須用NSValue封裝為對象類型后,才能放入數(shù)組中埋虹。
3.數(shù)組元素可以是不用對象類型猜憎,可能會(huì)有類型不安全。
注:對于類型不安全問題搔课,我們可以使用泛型來限制數(shù)組類型胰柑。ClassName<T>
4.NSArra具有常量性:長度和元素指針都不能更改。但指針指向的對象內(nèi)部可以更改爬泥。
常用操作:
- 數(shù)組遍歷:
1.最快——Fast Enumeration 柬讨,直接訪問內(nèi)存,優(yōu)化索引檢查袍啡,快5-10倍踩官,用到了多線程。
2.較慢——NSEnumerator遍歷:索引檢查+動(dòng)態(tài)消息調(diào)用//快速枚舉 for ( BLNPoint* point in array5) { point.x++; point.y++; }
3.最慢——For循環(huán)訪問:索引檢查+動(dòng)態(tài)消息調(diào)用//迭代器模式 NSEnumerator *enumerator = [array5 objectEnumerator]; BLNPoint* item; while (item = [enumerator nextObject]) { item.x++; item.y++; }
//for循環(huán) for (int i=0; i<array5.count; i++) { NSLog(@"array5[%d],%@",i,array5[i]); }
- 注:for...in...利用了快速枚舉NSFastEnumerate
當(dāng)我們想要改變數(shù)組變量中的數(shù)據(jù)或者刪除數(shù)組中的數(shù)據(jù)的時(shí)候,不能用for...in...境输。Objective-C中的foreach循環(huán)與Java中的相似蔗牡,在內(nèi)部是用iterator(迭代器)實(shí)現(xiàn)遍歷的。而不管是在Java還是C++中嗅剖,一旦修改了被遍歷對象辩越,在修改前生成的iterator都會(huì)失效,所以在用iterator遍歷集合時(shí)增刪集合元素
NSArray的枚舉操作中有一條需要注意:對于可變數(shù)組進(jìn)行枚舉操作時(shí)信粮,你不能通過添加或刪除對象這類操作來改變數(shù)組容器黔攒。如果你這么做了,枚舉器會(huì)很困惑蒋院,而你將得到未定義的結(jié)果。 - 解決方法:當(dāng)我們需要改變數(shù)組中的內(nèi)容時(shí)(這里指NSMutableArray可變數(shù)組),可以使用enumerateObjectsUsingBlock莲绰。
[arr enumerateObjectsUsingBlock:^(NSMutableDictionary *obj, NSUInteger idx, BOOL *stop) { if (...) { // do sth *stop = YES; // 相當(dāng)于break ; stop控制跳出枚舉器. } }];
//使用enumerateObjectsUsingBlock快速迭代欺旧,比起forloop要快。但是要再block中如果需要改變外部變量蛤签,那么需要在外部變量前聲明__block
```
可變數(shù)組(NSMutableArray)
1.NSMutableArray支持更改數(shù)組長度和元素指針辞友。為NSArray子類。
2.NSMutableArray初始化后,會(huì)分配一個(gè)緩存容量capacity称龙,一般大于實(shí)際元素?cái)?shù)量留拾,當(dāng)長度增長時(shí),如實(shí)際需求大于capacity鲫尊,其capacity會(huì)以近似二倍的方式指數(shù)增長痴柔。伴隨代價(jià):(1)分配新的堆內(nèi)存2*capacity (2)將原來堆內(nèi)存上的元素拷貝到新內(nèi)存(3)釋放原來的堆內(nèi)存
3.最佳實(shí)踐:估計(jì)好capacity,預(yù)先分配一定容量疫向,避免以后增長
4.盡量避免使用insertObject:atIndex:和removeObjectAtIndex:等操作咳蔚,因?yàn)闀?huì)改變數(shù)組元素序列,涉及大量內(nèi)存拷貝操作搔驼,代價(jià)高谈火。
ARC
自動(dòng)引用計(jì)數(shù)(Automatic Reference Counting)是OC默認(rèn)的內(nèi)存管理機(jī)制,針對堆上的對象舌涨,由編譯器自動(dòng)生成操作引用計(jì)數(shù)的指令(retain和release)糯耍,來管理對象的創(chuàng)建與釋放
新創(chuàng)建一個(gè)對象時(shí),它的引用計(jì)數(shù)為1囊嘉,retain操作計(jì)數(shù)+1温技,release-1;
當(dāng)一個(gè)對象的引用計(jì)數(shù)變?yōu)?的時(shí)候哗伯,內(nèi)存自動(dòng)釋放
自動(dòng)釋放池(Autorelease Pool)
release會(huì)導(dǎo)致對象立即釋放荒揣。如果頻繁對對象進(jìn)行release,可能會(huì)造成瑣碎的內(nèi)存管理負(fù)擔(dān)焊刹。autorelease可以將release的調(diào)用延遲到自動(dòng)釋放池被釋放時(shí)系任。
推薦使用自動(dòng)釋放池(Autorelease Pool)Block,當(dāng)其結(jié)束時(shí)虐块,所有接受autorelease消息的對象將會(huì)被立即釋放
大多數(shù)情況下俩滥,這樣使用就行了,無需程序員干預(yù)
何時(shí)需要手工管理Autorelease Pool贺奠?
1.編寫的程序不基于UI框架霜旧,如命令行程序@autoreleasepool { block塊 todo
}
2.在循環(huán)中創(chuàng)建大量臨時(shí)對象,需要更早地釋放儡率,避免臨時(shí)對象聚集導(dǎo)致內(nèi)存峰值過大
3.在主線程之外創(chuàng)建新的線程挂据,在新線程開始執(zhí)行處,需要?jiǎng)?chuàng)建自己的Autorelease Pool儿普。
4.可以嵌套使用AutoreleasePool
認(rèn)識(shí)協(xié)議 Protocol
OC學(xué)習(xí)篇之---協(xié)議的概念和用法
協(xié)議:類型的合同約定崎逃,只描述外部申明,不提供具體實(shí)現(xiàn)眉孩。所以只有h文件
協(xié)議可以包含以下成員:
1.屬性
2.實(shí)例方法
3.類方法
4.初始化器——不常用
5.析構(gòu)器——不常用
協(xié)議中無法包含實(shí)例變量成員(實(shí)例變量是在m文件中)
協(xié)議中定義的屬性本質(zhì)上是訪問器方法个绍,編譯器不會(huì)合成實(shí)例變量
使用協(xié)議
@interface ClassName : NSObject<ProtocolName>
在聲明類文件時(shí) 勒葱,在類名后面用<ProtocolName>
一個(gè)類遵守協(xié)議,需要實(shí)現(xiàn)協(xié)議約定的所有@required成員
<small>協(xié)議中的屬性須在實(shí)現(xiàn)類的.h文件中申明(編譯器合成實(shí)例變量需要巴柿,而方法可以省略)</small>
注意編譯警告信息:
遵守協(xié)議后卻沒有實(shí)現(xiàn)必選協(xié)議方法時(shí)凛虽,會(huì)出現(xiàn)警告提示
協(xié)議類型變量被賦值非協(xié)議類型對象時(shí),會(huì)出現(xiàn)警告提示協(xié)議本質(zhì)上是一種類型广恢,可以作為聲明類型凯旋,但不能創(chuàng)建實(shí)例
檢查協(xié)議類型
使用conformToProtocol:檢查對象是否實(shí)現(xiàn)了協(xié)議
if([obj conformToProtocol:@protocol(Aprotocol)])
OC中的協(xié)議就是相當(dāng)于Java中的接口(抽象類),只不過OC中的名字更形象點(diǎn)袁波,因?yàn)槲覀冊趯W(xué)習(xí)Java中的接口時(shí)候瓦阐,看可以知道其實(shí)接口就相當(dāng)于一種契約(協(xié)議),給他的實(shí)現(xiàn)類打上標(biāo)記了,當(dāng)然這個(gè)活在Java5.0之后篷牌,被注解替代了睡蟋,因?yàn)樽⒔饩褪菫榱舜斯δ苷Q生的。
協(xié)議就是定義了一組方法枷颊,然后讓其他類去實(shí)現(xiàn)
下面來看代碼:
WithProtocol.h#import <Foundation/Foundation.h>
@protocol WithProtocol <NSObject>
//默認(rèn)是必須實(shí)現(xiàn)的
//必須實(shí)現(xiàn)
@required
- (void)finshTask;
- (void)dontLate;
//可選實(shí)現(xiàn)
@optional
- (void)wearNeat;
@end
>
>這里就定義了一個(gè)協(xié)議WithProtocl
協(xié)議的定義格式:
@protocol 協(xié)議名 <父協(xié)議>
定義方法
@end
- 注:定義協(xié)議的關(guān)鍵字是@protocol,同時(shí)協(xié)議也是可以繼承父協(xié)議的
>
協(xié)議中定義的方法還有兩個(gè)修飾符:
@required:這個(gè)表示這個(gè)方法是其他類必須實(shí)現(xiàn)的戳杀,也是默認(rèn)的值
@optional:這個(gè)表示這個(gè)方法對于其他類實(shí)現(xiàn)是可選的
這個(gè)就和類似與Java中的抽象類了,如果是abstract修飾的就必須實(shí)現(xiàn)夭苗,所以如果一個(gè)協(xié)議中沒有@optional修飾的方法信卡,那么這個(gè)協(xié)議就相當(dāng)于Java中的接口了。
>
- 這里要注意的是题造,上面的代碼中NSObject不是我們之前說的NSObject類了傍菇,而是NSObject協(xié)議,他也是OC中第一個(gè)協(xié)議界赔,這個(gè)名字相同在OC中是沒有關(guān)系的丢习。
再看一下協(xié)議的使用:
>```
>**Student.h**
>#import <Foundation/Foundation.h>
>
>#import "WithProtocol.h"
>
>@interface Student : NSObject <WithProtocol>
>
>- (void)study;
>
>@end
>```
- 使用協(xié)議很簡單,直接在繼承類(NSObject)后面 <協(xié)議名>即可
>
>```
>#import "Student.h"
>@implementation Student
- (void)study{
NSLog(@"study");
}
//直接在.m文件中實(shí)現(xiàn)即可淮悼,不需要在.h文件中再次定義
#pragma mark - WithProtocol
//一般協(xié)議的方法咐低,在這里標(biāo)記下,用途是在導(dǎo)航欄快速地定位到這個(gè)方法是協(xié)議里的袜腥,起到分類的作用
- (void)finshTask{
NSLog(@"完成任務(wù)");
}
>- (void)dontLate{
//#warning 代碼過幾天在補(bǔ)充
NSLog(@"不遲到");
}
>- (void)wearNeat{
NSLog(@"穿戴整潔");
}
>@end
類別 Categroy
類別支持在沒有源代碼的情況下见擦,基于某些特定場合,為一個(gè)類增加功能
可以添加:1.類方法羹令;2.實(shí)例方法鲤屡;3.重寫基類方法
不能添加:1.屬性;2.實(shí)例變量福侈;3.已存在的同名方法
命名規(guī)范:類名+擴(kuò)展方法酒来,如:NSString+Drawing.h/.m使用類別:
1.使用場景:
- 適合在沒有源代碼的情況下,向已經(jīng)封裝的類中添加方法
- 為一個(gè)類在某些特殊場景下增加功能
- 對于復(fù)雜的大型文件分割實(shí)現(xiàn)
2.添加類別:
- 自己創(chuàng)建的類
- 系統(tǒng)的類
- 第三方庫
BLNPoint.h #import <Foundation/Foundation.h> @interface BLNPoint : NSObject { float _weight; } @property NSInteger x; @property NSInteger y; -(void)move;
@end
BLNPoint+Drawing.h #import <Foundation/Foundation.h> #import "BLNPoint.h" @interface BLNPoint(Drawing) -(void)draw; //@property NSInteger weight; -(void)setWeight:(NSInteger)weight; -(NSInteger)weight; @end
擴(kuò)展Extension
擴(kuò)展支持在編譯時(shí)癌刽、有類的源代碼的情況下,向類添加功能显拜≡盾可以將擴(kuò)展看做匿名的類別
接口定義在.m文件中@implementation前聲明,實(shí)現(xiàn)代碼仍然在@implementation中實(shí)現(xiàn)
擴(kuò)展支持添加以下成員:
- 添加屬性
- 添加實(shí)例成員
- 添加類方法
- 添加實(shí)例方法
- 改寫屬性的讀寫屬性
@interface ClassName() { 聲明定義 } @end @implementation ClassName { 具體實(shí)現(xiàn) } @end
使用擴(kuò)展:
- 擴(kuò)展實(shí)現(xiàn)的成員都只能在.m實(shí)現(xiàn)文件內(nèi)部訪問档址,在類外不可以直接訪問
- 擴(kuò)展的主要用途在于信息隱藏邻梆,隱藏一些外部無需訪問,而內(nèi)部實(shí)現(xiàn)又需要使用的屬性尼摹、方法:
1.類的主接口主要用于“對類外公開”的接口
2.類的擴(kuò)展接口用于“對類內(nèi)可見”的接口
<small>比如在類的主接口.h文件中有個(gè)屬性聲明為只讀屬性剂娄,我們可以在擴(kuò)展中升級(jí)這個(gè)屬性為讀寫屬性阅懦,這樣在類內(nèi)實(shí)現(xiàn)可以使用讀寫屬性,而對外只能是只讀屬性</small>