字符串 NSString
OC的字符串具有共享性,和恒定性扮念。
<pre><code>
//其實(shí)這兩個(gè)變量都指向了同一個(gè)地址
NSString *str1 = @"Hello World!";
NSString *str4 = @"Hello World!";
</pre></code>為了避免內(nèi)存浪費(fèi)锤岸,編譯器會(huì)做優(yōu)化踢械,將對(duì)象的指針指向同一個(gè)地方沃暗。但是魁兼,這種情況只會(huì)在字面量初始化時(shí)出現(xiàn)
字符串的初始化:
<pre><code>NSString *str1 =@"Hello World!";//字面量初始化
NSString*str2 = [[NSStringalloc]initWithCString:"Hello
World!" encoding:NSUTF8StringEncoding];
//初始化器初始化
NSString*str3 = [NSStringstringWithCString:"Hello
World!" encoding:NSUTF8StringEncoding];
//工廠初始化
//其中坐搔,工廠初始化方法藏研,
是一個(gè)類方法,通過類方法內(nèi)部返回一個(gè)新的對(duì)象
</pre></code>
字符串基本操作
<pre><code>
[str1 stringByAppendingString: @"Hello World"] //加字符串
[str1 stringByReplacingCharactersInRange: @"Hello World"]//替換字符串
[str1 isEqualToString:str2]// 比較值是否相等
str1 == str2
比較指針是否相等
</pre></code>
<pre><code>
for(int i =0 ;i < [str1 length];i
++){
NSLog(@"%c",[str1 characterAtIndex:i]); //遍歷字符串
}
str1 = str1.uppercaseString;//大寫
str1 = str1.lowercaseString;//小寫
str1 = str1.capitalizedString;//首字母大寫
NSRange range = [str1 rangeOfString:@"Hello"];//查找字符串某處是否包含其它字符,返回location和length概行。
NSLog(@"location: %lu,length:%lu",range.location,range.length);
NSString* substr = [str1 substringFromIndex:6];//從索引6開始取他的子字符串
BOOLyOrN = [str1 hasPrefix:@"Hello"];//判斷是否有這個(gè)字符串前綴
NSString* format=[NSString stringWithFormat:@"[%d,
%d]",100,200];//格式化字符串方法
</pre></code>
<pre><code>[str1 stringByAppendingString:@" Yes!"];
//偽更改蠢挡,不會(huì)去真正的更改str1所指的堆上的值本身,只會(huì)返回一個(gè)新值凳忙,
str1=[str1 stringByAppendingString:@" Yes!"];
//所以要重新給str1
賦值业踏。
</pre></code> 如果在st1
的字符串后面再加一點(diǎn)字符串,這個(gè)字符串也不會(huì)更改涧卵,這是字符串的恒定性勤家,無(wú)法改變字符串本身。
還有一個(gè)可變字符串 NSMutableString
NSMutableString
具有可變性柳恐,它的值是可以被更改的伐脖,因此它也不具備共享性热幔。
注意:
它是NSString
的子類
所以當(dāng)用NSMutableString
定義一個(gè)字符串空間mstr1
,
我們可以把mstr1
賦值給NSString
類型的str1
讼庇,
因?yàn)?code>mstr1的值是NSMutableString
類型绎巨,具有可變性,
所有當(dāng)用appendString
去更改mstr1
的值時(shí)蠕啄,str1
的值也會(huì)跟著改變认烁,
這就違反了NSString
的恒定性。
所以針對(duì)這個(gè)就要用拷貝屬性[copy str1]
去賦值
<pre><code>
NSMutableString mustr3 =[NSMutableStringstringWithCapacity:100];//手動(dòng)分配空間
[mustr3 appendString:@"Hello Objective"]; //增加字符串內(nèi)容
[mustr3 insertString:@"-C" atIndex:mustr3.length];//在指定位置增加內(nèi)容
[mustr3 setString:@"Hi Objective"];//重新設(shè)置字符串
NSRange replaceRange = NSMakeRange(0, 2);//取指定區(qū)間的字符串
[mustr3 replaceCharactersInRange:replaceRange withString:@"Hello"];//替換字符串
NSRange deleteRange = NSMakeRange(5, 10);//刪除指定區(qū)間的字符串
[mustr3 deleteCharactersInRange:deleteRange];//刪除字符串
</pre></code>
以上這些操作都會(huì)直接改變字符串的值
Sizeof(str1)
指的是指針的大小
Str1.length
指的是字符串值的長(zhǎng)度
集合類型
數(shù)組 Array
OC的數(shù)組被定義為一個(gè)class介汹,和C的數(shù)組不同却嗡,
而當(dāng)訪問越界時(shí),會(huì)報(bào)錯(cuò)嘹承。
數(shù)組的初始化有三種方法:
<pre><code>
NSArray *array1=[NSArray arrayWithObjects:@"Shanghai",@"Beijing",@"New York",@"Paris", nil];
//工廠方法窗价,會(huì)返回一個(gè)新的值
NSArray *array2=[[NSArray alloc] initWithObjects:@"Shanghai",@"Beijing",@"New York",@"Paris", nil];
//初始化器方法
NSArray *array3=@[@"Shanghai",@"Beijing",@"New York",@"Paris"];
//字面量方法
</pre></code>
在工廠和初始化器最后的nil
表示輸入結(jié)束。
array里的元素必須是對(duì)象(NSObject的子類)
如果想在array里放值叹卷,那么必須用NSNumber封裝成類對(duì)象再放入array
NSNumber *numberObject1 =[NSNumber numberWithInteger:number ];
NSInteger
是整數(shù)值類型撼港,跟隨CPU架構(gòu)變換長(zhǎng)度
當(dāng)用字面量初始化時(shí)要加@
,用u
結(jié)尾骤竹。
NSNumber *numberObject2=@300u;//使用字面常量初始
<pre><code>
Point point;
point.h=100;
point.v=200;
NSValue *pointObject= [NSValue value:&point withObjCType:@encode(Point)];
//使用NSValue將struct包裝為對(duì)象 再放入數(shù)組
</pre></code>
如果想放空值得話,可以用下面的方法
NSNull *nsnull = [NSNull null];
因?yàn)槊恳粋€(gè)數(shù)組元素的對(duì)象類型可以不一樣帝牡,所以在取元素的時(shí)候,可能存在類型不安全
數(shù)組具有常量性:
數(shù)組的 長(zhǎng)度 和 元素指針 都不可以被更改(一但這個(gè)數(shù)組初始化完畢后蒙揣,長(zhǎng)度和元素指針全都不可以更改) 但是元素指針?biāo)赶虻膶?duì)象內(nèi)部可以更改
可變數(shù)組 NSMutableArray
NSMutableArray是NSArray的子類
它的初始化方式也和NSArray一樣
因?yàn)槭强勺償?shù)組靶溜,它可以執(zhí)行以下操作
[muArray1 addObject:p5];
在數(shù)組結(jié)尾增加一個(gè)元素
[muArray1 removeObjectAtIndex:2];
移除指定索引上的元素
[muArray1 insertObject:p6 atIndex:1];
在指定索引上插入元素
muArray1[0]=p7;
替換指定索引的元素
和可變字符串一樣,可變數(shù)組在初始化后懒震,會(huì)分配一個(gè)緩存容量Capacity
罩息,一般大于實(shí)際元素?cái)?shù)量,當(dāng)實(shí)際容量大于Capacity
時(shí)个扰,Capacity
會(huì)以兩倍的方式增長(zhǎng)瓷炮。
最好的方法是在初始化初期就預(yù)估分配合理的空間給數(shù)組。
intcount=100; NSMutableArray*muArray2=[NSMutableArrayarrayWithCapacity:count];
在實(shí)際操作過程中递宅,盡量避免使用removeObjectAtIndex:
和insertObject: atIndex:
因?yàn)闀?huì)改變數(shù)組序列娘香,涉及大量的內(nèi)存拷貝操作,代價(jià)太大办龄。
數(shù)組的遍歷
<pre><code>
for( BLNPoint* point inarray5)
{
point.x++;
point.y++;
}
//快速遍歷法 for-in 所有遍歷方法中烘绽,速度最快,因?yàn)樗苯釉L問內(nèi)存土榴,優(yōu)化了索引檢查诀姚。
</pre></code>如果不知道數(shù)組元素的類型的話,要寫成id*point
或者NSObject* point
<pre><code>NSEnumerator *enumerator = [array5 objectEnumerator];
BLNPoint* item;
while(item = [enumerator nextObject])
{
item.x++;
item.y++;
}
//迭代枚舉法玷禽,相比于for-in會(huì)慢一點(diǎn)
</pre></code>array5
上面會(huì)有一個(gè) objectEnumerator
方法得到一個(gè)NSEnumerator
對(duì)象類型赫段,那這個(gè)對(duì)象類型去調(diào)用 nextObject
方法 呀打,再把返回的值賦給 用NSEnumerator
創(chuàng)建的對(duì)象 item
,當(dāng)沒有元素的時(shí)候糯笙,他的值就是nil
贬丛,也就不會(huì)再繼續(xù)while
循環(huán)。
<pre><code>for(inti=0; i<array5.count; i++)
{
NSLog(@"array5[%d],%@",i,array5[i]);
}
for循環(huán)遍歷给涕,最慢的方法豺憔。
</pre></code>
所有遍歷方法中,推薦使用for-in够庙。
數(shù)組查找:
<pre><code>BLNPoint* target=[[BLNPointalloc] initWithX:33WithY:63];
NSUIntegerindex1=[array5 indexOfObject:target];
// 在 array5 中查找是否有和 tearget 值相同的元素恭应,并且返回索引
NSUIntegerindex2=[array5 indexOfObjectIdenticalTo:p3];
// 這個(gè)方法只能用數(shù)組內(nèi)的元素名查找,并返回索引
NSLog(@"find at%lu", index1);
NSLog(@"find at
%lu", index2);
</pre></code>
數(shù)組排序:
<pre><code>NSArray* sortArray1=[array1 sortedArrayUsingSelector:@selector(compare:)];</pre></code>我們指定了一個(gè)方法 compare:
它可以實(shí)現(xiàn)數(shù)組里元素的比較
因?yàn)闊o(wú)法改變?cè)瓟?shù)組耘眨,所以要取它的返回值給 sortArray1
它是通過返回一個(gè)新數(shù)組來表達(dá)排序的結(jié)果
set集合
NSSet
和數(shù)組不一樣昼榛,是一個(gè)無(wú)序集合,存儲(chǔ)的對(duì)象不能重復(fù)
被定義為class
剔难,引用類型胆屿,拷貝時(shí)有引用語(yǔ)句
有常量集合NSSet
,可變集合NSMutableSet
偶宫,和數(shù)組一樣非迹。
初始化方式也和數(shù)組類似
<pre><code>NSSet*set1 =
[NSSetsetWithObjects:@"Shanghai",@"Beijing",@"New York",@"Paris", nil];
NSMutableSet*set2 =
[NSMutableSetsetWithObjects:@"Shanghai",@"Beijing",@"New York",@"Paris", nil];
</pre></code>
Capacity
set
容量??
<pre><code>int count=100;
NSMutableSet*muArray2=[NSMutableSetinitWithCapacity:count];
</pre></code>
set
的一下操作
<pre><code>
[set2 addObject:@"London"];//加元素
[set2 removeObject:@"Beijing"];//移除元素
NSLog(@"set2 count:%lu", set2.count);
</pre></code>
<pre><code>
if([set2 containsObject:@"Shanghai"])//判斷是否包含某個(gè)對(duì)象
</pre></code>
字典
Dictionary 字典 是一個(gè)存儲(chǔ)Key-Value
的無(wú)序集合
Key
唯一,value
可重復(fù)
和Array
纯趋、Set
一樣憎兽,
有常量字典NSDictionary
和可變字典NSMutableDictionary
。
初始化方式也和數(shù)組差不多
字面常量初始化:
value
在 Key
之前结闸,中間用:
隔開<pre><code>
NSDictionary *dictionary1 = @{
@"Shanghai": p1,
@"Beijing": p2,
@"NewYork" : p3,
@"Paris": p4 };
</pre></code>
工廠方法:
Value
在key
之后唇兑,中間用" ,
"隔開
<pre><code>
NSMutableDictionary*dictionary2 =
[NSMutableDictionarydictionaryWithObjectsAndKeys:
p1,@"Shanghai",
p2,@"Beijing",
p3,@"New York",
p4,@"Paris",
nil];
</pre></code>
<pre><code>
BLNPoint* result1=[dictionary1 objectForKey:@"Beijing"];
BLNPoint* result2=dictionary1[@"Shanghai"];
</pre></code>可以用這種方式查詢Key
來得到對(duì)應(yīng)的value
。
** tip **:所有的可變集合都是其對(duì)應(yīng)的一個(gè)常量集合的子類桦锄。
自動(dòng)引用計(jì)數(shù)ARC
ARC 是OC的默認(rèn)內(nèi)存管理機(jī)制,針對(duì)堆上的對(duì)象蔫耽,由編譯器自動(dòng)生成操作ARC指令(retina
或release
)來管理對(duì)象的創(chuàng)建和釋放结耀。
retina
和release
在后期的高級(jí)編程內(nèi)容里會(huì)深入了解
受ARC管理的有:
- OC的對(duì)象指針
- Block 指針
- Attribute((NSObject))定義的typedef
不受ARC管理的有:
- 值類型(如C語(yǔ)言的結(jié)構(gòu))
- 使用其他方式分配的堆對(duì)象(如malloc)
- 非內(nèi)存資源
實(shí)際上,指針本身不受ARC管理匙铡,因?yàn)锳RC管理的是堆上的對(duì)象图甜,而指針是存放在棧上的。所有ARC管理的實(shí)際上是指針?biāo)赶虻哪莻€(gè)對(duì)象鳖眼。
而值類型的對(duì)象也是存放在棧上黑毅,所以也不受ARC管理。
引用計(jì)數(shù)管理
引用計(jì)數(shù)+1的操作 (retain
操作)
當(dāng)將對(duì)象執(zhí)行對(duì)其他對(duì)象的
- 賦值
- 傳參
- 加入集合操作
引用計(jì)數(shù)-1 (release
操作)
- 全局(局部)變量被賦值為nil 或其他值
- 屬性被賦值為nil或其他值
- 將對(duì)象從集合中刪除
自動(dòng)釋放池 AutoRelease Pool
release
會(huì)導(dǎo)致對(duì)象立即釋放钦讳,如果頻繁的release
矿瘦,會(huì)造成瑣碎的內(nèi)存管理負(fù)擔(dān)枕面。這時(shí)候,用autorelease
可以將release
的調(diào)用推遲到autorelease
被釋放時(shí)缚去。
Appkit
和 UIkit
框架在每一次事件迭代時(shí)潮秘,都會(huì)將這個(gè)代碼放入autoreleasepool
中。大多數(shù)情況都不需要人為干預(yù)易结。
在main
函數(shù)內(nèi)枕荞,編譯器都會(huì)在開始加上一個(gè)autorelease
的塊當(dāng)程序運(yùn)行到autorelease
結(jié)束時(shí),所有引用了release
的對(duì)象都會(huì)被立即釋放
<pre><code>
int main(int argc, const char * argv[]) {
@autoreleasepool{
NSLog(@"-------ARC Demo: ----------");
arcDemo();
//當(dāng)函數(shù)內(nèi)執(zhí)行完后搞动,會(huì)引用release躏精,然后這個(gè)釋放信號(hào)會(huì)暫存在autorelease內(nèi)
NSLog(@"-------Autorelease Pool Demo: ----------");
poolDemo();
}
//當(dāng)這個(gè)autorelease執(zhí)行完后,就會(huì)被釋放鹦肿,隨之存在其中的release也會(huì)被立即釋放矗烛。
return0;
}
</pre></code>每一個(gè)事件處理,都是一個(gè)autoreleasepool
的建立和釋放
需要手工管理autorelease pool
的情況
- 編寫的程序不基于UI框架(如命令行程序)
- 在循環(huán)中創(chuàng)建了大量臨時(shí)變量狮惜,需要提早釋放高诺,避免臨時(shí)對(duì)象聚集而導(dǎo)致內(nèi)存峰值過高。
- 在主線程之外創(chuàng)建了新的線程碾篡,需要自己手工添加autorelease pool 塊
- 可以嵌套使用
<pre><code>
void poolDemo(){
@autoreleasepool{
for (int i = 0; i < 10; i++) {
__unused BLNRectangle *rect = [[BLNRectangle alloc]init];
}
}
}
</pre></code>
__unused
修飾符虱而,通知編譯器,如果這個(gè)變量未被使用就不參與編譯(消除黃色警告團(tuán))
協(xié)議protocol
協(xié)議是一種約定开泽,它只提供外部描述牡拇,不提供具體實(shí)現(xiàn),所以只在.h文件內(nèi)寫穆律,不用去寫.m文件
協(xié)議里可以放
- 屬性
- 實(shí)例方法
- 類方法
- 初始化器和析構(gòu)器(一般不放)
但是不能放實(shí)例變量惠呼。編譯器會(huì)自動(dòng)生成setter和getter方法,但是不會(huì)合成實(shí)例變量峦耘。
定義協(xié)議
<pre><code>@protocol Drawable
//內(nèi)容
@end
</pre></code>
使用協(xié)議
<pre><code>
@interface BLNPoint : NSObject<Drawable>//把協(xié)議名放中括號(hào)里
//內(nèi)容
@end
</pre></code>
** 必選協(xié)議required **
** 可選協(xié)議optional **
協(xié)議里的成員默認(rèn)都是@required
的剔蹋,當(dāng)一個(gè)類遵守協(xié)議時(shí),必須要實(shí)現(xiàn)協(xié)議內(nèi)的所有成員辅髓。.h
文件里不用去再次聲明協(xié)議內(nèi)的方法泣崩,只需要在.m
文件內(nèi)實(shí)現(xiàn)就可以了。
** 但是屬性必須再次聲明 **洛口。如果不聲明的話矫付,就沒法自動(dòng)合成實(shí)例變量。
如果要自己寫一個(gè)@required的話第焰,那個(gè)在這個(gè)@required后面的成員就是必選成員了
與之相對(duì)的@optional表示的是可選協(xié)議买优。他之后的成員會(huì)被認(rèn)為成可選協(xié)議
如果遵守協(xié)議但是沒有去實(shí)現(xiàn)協(xié)議方法,會(huì)出現(xiàn)警告運(yùn)行時(shí)就會(huì)報(bào)錯(cuò)。
協(xié)議類型變量被賦值非協(xié)議類型對(duì)象時(shí)杀赢,會(huì)出現(xiàn)警告
比如這樣賦值就會(huì)報(bào)錯(cuò)process1(@"x");
烘跺,process1
是協(xié)議類型的函數(shù)
協(xié)議可以作為變量聲明類型,但是不能創(chuàng)建實(shí)例void process1(id<Drawable> obj)
有時(shí)不確定這個(gè)對(duì)象是否遵守了協(xié)議葵陵,那么可以用這段代碼來驗(yàn)證這個(gè)對(duì)象背后的類型是否遵守了協(xié)議液荸。
<pre><code>
void process2(id obj){
if([obj conformsToProtocol:@protocol(AProtocol) ]) {
[obj methodA];
}
</pre></code>
一個(gè)協(xié)議也可以繼承多個(gè)協(xié)議。
實(shí)現(xiàn)子協(xié)議的類型脱篙,也必須實(shí)現(xiàn)父類協(xié)議的成員娇钱。
也可以遵守多個(gè)協(xié)議
<pre><code>
@interface ClassC : NSObject<AProtocol,CProtocol>
@end
</pre></code>
常用的協(xié)議
NSObject
:包含對(duì)象的常用操作,相等绊困、字符串表示文搂、哈希。
NSCopying
:支持復(fù)制的類型必須遵守該協(xié)議秤朗。
NSMutableCopying
:在NSCopying的基礎(chǔ)上煤蹭,支持復(fù)制數(shù)據(jù)的可變性。
NSFastEnumeration
:實(shí)現(xiàn)快速美劇for-in的類型采用該協(xié)議取视。
NSCoding
:支持將對(duì)象圖進(jìn)行編碼/解碼以支持對(duì)象序列化
類別與擴(kuò)展
類別category
類別就不知道源代碼的情況下硝皂,想給原有的類再添加了一些成員,并去實(shí)現(xiàn)他們
定義類
@interface BLNPoint : NSObject
定義類別
@interface BLNPoint(Drawing)
** tip **:category
的實(shí)現(xiàn)文件不寫在class
的實(shí)現(xiàn)文件內(nèi),而是寫在category
的實(shí)現(xiàn)文件內(nèi)
命名規(guī)范:
文件名 == class
名+category
名
category
可以添加的成員
- 類方法
- 實(shí)例方法
- 重寫基類方法
category
不能添加的成員
- 屬性
- 實(shí)例變量
- 已存在的同名方法(已經(jīng)被定義過的)
加了屬性的話作谭,編譯能通過稽物,但是在運(yùn)行的時(shí)候就會(huì)報(bào)錯(cuò)(坑爹啊這是)
不能加屬性,實(shí)際上是因?yàn)椴荒芗訉傩员澈蟮哪莻€(gè)實(shí)例變量折欠。
雖然不能加屬性贝或,但是可以去定義一個(gè)setter
和一個(gè)getter
訪問器方法。
-(void)setWeight:(NSInteger)weight;
-(NSInteger)weight;
調(diào)用class
內(nèi)的實(shí)例變量
適用場(chǎng)景:
- 在沒有源代碼的情況下锐秦,向已經(jīng)封裝的類里添加方法
- 在一些特殊場(chǎng)合下
- 對(duì)復(fù)雜的大型文件分割實(shí)現(xiàn)
都一下位置可以添加category
- 自己創(chuàng)建的
- 系統(tǒng)的
- 第三方庫(kù)
擴(kuò)展extension
和category
最大的區(qū)別在于苍凛,這是在有class
的源代碼的情況下在class
內(nèi)添加固翰,可以看做是一個(gè)沒有名字的class
,不用定義在 .h
文件鹉动,直接在需要擴(kuò)展的.m
文件內(nèi)定義.
<pre><code>
@interface Circle ()//加個(gè)小括號(hào)笙瑟,寫在.m 文件里
{
NSString* _name;
}
@property (readwrite )NSInteger radius;//修改讀寫屬性
@property
NSIntegercenter;//添加屬性
-(float)getDiameter;//實(shí)例方法
+(void)process:(Circle*) circle;//類方法
@end
</pre></code>
如果在主接口定義了文件的讀寫屬性客税,那么在擴(kuò)展內(nèi)可以更改讀寫屬性赫蛇,
有一點(diǎn)需要注意的是阿纤,只能往更高的權(quán)限更高,** 不能把權(quán)限改低揍堕。 **
注意:
最重要的一點(diǎn)區(qū)別,擴(kuò)展的成員只針對(duì)類(那個(gè) .m
文件)內(nèi)可以訪問汤纸,在類外不能訪問擴(kuò)展衩茸!
擴(kuò)展的主要用途就是信息隱藏,可以把一些外部無(wú)需訪問贮泞,但是類內(nèi)又要用到的成員私有化楞慈。
類的主接口用于 ** 對(duì)外公開訪問 **
類的擴(kuò)展用于 ** 對(duì)內(nèi)訪問 **