字符串處理NSString
認(rèn)識(shí)字符串NSString
- NSString是一個(gè)Unicode編碼、16位字符的字符序列
- NSString被定義為類,引用類型,拷貝時(shí)具有引用語(yǔ)義。
- 初始化方法:字面初始化、初始化器、工廠方法
- NSSring擁有恒定性,所有的操作無(wú)法更改字符串本身,如果有更改,都是返回新值的形式。
- NSString擁有共享機(jī)制,引用計(jì)數(shù)管理對(duì)其有特殊的管理規(guī)則
oc的NSString和c語(yǔ)言的區(qū)別
- NSString是一個(gè)oc對(duì)象,OC字符串是一個(gè)字符串對(duì)象,字符串常量需要用@""包含。
- C語(yǔ)言字符串是一個(gè)數(shù)據(jù)類型,用""包含
- OC中的字符串以Unicode編碼,C語(yǔ)言的字符串以字符的ASCII碼形式。
- 打印OC字符串用%@,打印C語(yǔ)言字符串用%s
三種初始化方法:
NSString *str1 = @"Hello World!";
//字面常量,加@才是OC的字符串
NSString *str2 = [[NSString alloc]initWithCString:"Hello World!" encoding:NSUTF8StringEncoding];
//用內(nèi)存分配搭配初始化器
NSString *str3 = [NSString stringWithCString:"Hello World!" encoding:NSUTF8StringEncoding];
//工廠方法,是一個(gè)類方法,通過類方法內(nèi)部返回一個(gè)對(duì)象
NSString *str4= @"Hello World!";
上面運(yùn)行結(jié)果str1和str4的存放地址是一樣的(共享機(jī)制)。只要用字面常量創(chuàng)立的字符串才會(huì)共享。
- 判斷相等
isEqualToString值是否相等 -
str1 == str2比較指針(引用)是否相等
NSMutableString
- NSMutableString具有可變性,NSString具有恒定性
- NSMutableString不具有共享機(jī)制,NSString具有共享機(jī)制
- NSMutableString不是在原有內(nèi)存上直接增長(zhǎng),而是重新分配一個(gè)更大或更小的緩存容量存放字符
- NSMutableString是NSString的子類
NSMutableString *mustr1 = [NSMutableString stringWithString: @"Hello,World!"];
//工場(chǎng)方法停止初始化
NSLog(@"mustr1:%p",mustr1);
NSMutableString *mustr2 = [NSMutableString stringWithString: @"Hello,World!"];
NSLog(@"mustr2:%p",mustr2);
NSString *str5=mustr1;
NSLog(@"str5:%@",str5);
[mustr1 appendString:@" Very Good!"];
NSLog(@"str5:%@",str5);
//NSMutableString的改動(dòng),使他的父類NSString發(fā)作了改動(dòng)
存在的固有問題:通過mustr1的改動(dòng),使的父類NSString發(fā)生了改變(而上面提到NSString具有不變性)

緩存容量與增長(zhǎng)
- 字符串初始化后,會(huì)分配一個(gè)緩存容量capacity,其長(zhǎng)度一般大于實(shí)際的字符串?dāng)?shù)量,當(dāng)然也可以自己給它一個(gè)緩存容量
- 當(dāng)字符串增長(zhǎng)時(shí),如果實(shí)際需求大于capacity,其capacity會(huì)以兩倍的方式指數(shù)增長(zhǎng),代價(jià)是:
- 分配新的堆內(nèi)存2*capacity
- 將原來(lái)堆內(nèi)存的內(nèi)容拷貝到新內(nèi)存,
- 釋放原來(lái)堆內(nèi)存
- 最佳實(shí)踐:估計(jì)好capacity,預(yù)先分配好一定容量,避免以后capacity的增長(zhǎng)
常見操作
- NSString常見操作
- 訪問字符串:獲取字符串、字符串長(zhǎng)度、字面量、大小寫轉(zhuǎn)換
- 查詢字符串:定位子串、獲取子串、是否包含子串、查詢字符集
- 其他操作:比較字符串、替換字符串、分解字符串
- NSMutableString:
- 添加字符串
[mustr3 appendString:@"Hello Objective"]; - 刪除字符串
- 修改字符串
- 添加字符串
集合類型
數(shù)組
- 數(shù)組是一個(gè)有序的元素序列,支持隨機(jī)存取。索引從0開始,索引訪問越界會(huì)拋出運(yùn)行時(shí)異常。注意與C語(yǔ)言數(shù)組不同。
NSArray *array1=[NSArray arrayWithObjects:@"Shanghai",@"Beijing",@"New York",@"Paris", nil];
NSArray *array2=[[NSArray alloc] initWithObjects:@"Shanghai",@"Beijing",@"New York",@"Paris", nil];
NSArray *array3=@[@"Shanghai",@"Beijing",@"New York",@"Paris"];
可以通過
count方法訪問數(shù)組中元素的個(gè)數(shù),返回一個(gè)NSInteger.NSArray被定義為class,引用類型,拷貝時(shí)具有引用語(yǔ)義。
-
NSArray的元素必須是對(duì)象,即NSObject的子類。
- 如果為基本數(shù)值類型,須要用NSNumber 封裝為對(duì)象類型后,才能放入數(shù)組中。
NSInteger number=100; NSNumber *numberObject1= [NSNumber numberWithInteger:number ];- 如果為C語(yǔ)言結(jié)構(gòu)類型,須要用NSValue 封裝為對(duì)象類型后,才能放入數(shù)組中。
NSValue *pointObject = [NSValue value:&point withObjCType:@encode(Point)];- 數(shù)組元素可以是不同對(duì)象類型,可能會(huì)有類型不安全。
NSArray具有常量性:長(zhǎng)度和元素指針都不能更改。但指針指向的對(duì)象內(nèi)部可以更改。
NSArray內(nèi)存模型

數(shù)組遍歷
- 最快 for in 直接訪問內(nèi)存,優(yōu)化索引檢查,比f(wàn)or循環(huán)快5-10倍
- 較慢 NSEnumeration遍歷迭代的方法
NSEnumerator *enumerator = [array5 objectEnumerator];
BLNPoint* item;
while (item = [enumerator nextObject]){
item.x++;
item.y++;
}
- for循環(huán)最慢
數(shù)組查找的方法
-
indexOfObject查找是否存在“值相等”的對(duì)象(類型需要實(shí)現(xiàn)isEqual)。NSUInteger index1=[array5 indexOfObject:target]; -
indexOfObjectIdenticalTo查找是否存在“指針想等”的對(duì)象。NSUInteger index2=[array5 indexOfObjectIdenticalTo:p3]; objectAtIndex:方法訪問數(shù)組中的單個(gè)元素,返回給定索引處的單個(gè)元素。lastObject:方法返回?cái)?shù)組的最后一個(gè)元素。
數(shù)組排序
不改變?cè)瓟?shù)組(常量性),返回新數(shù)組。
NSArray* sortArray1=[array1 sortedArrayUsingSelector:@selector(compare:)];
使用NSMutableArray
- NSMutableArray支持更改數(shù)組長(zhǎng)度和元素指針,為NSArray的子類。
- capacity與NSMuatbalString一樣
- 估計(jì)好capacity預(yù)先分配一定容量,避免以后增長(zhǎng)
- 盡量避免使用
insertObject:atIndex:和removeObjectAtIndex:等操作,因?yàn)闀?huì)改變數(shù)組元素序列,涉及大量?jī)?nèi)存拷貝操作,代價(jià)高。
set
- NSSet 是一個(gè)無(wú)序的集合,其存儲(chǔ)的對(duì)象不能重復(fù)。
- 常量性:長(zhǎng)度和元素指針都不能更改。但指針指向的對(duì)象內(nèi)部可以更改。
- 創(chuàng)建NSMutableSet時(shí)用initWithCapacity提前設(shè)置capacity。
Dictionary字典類型
NSDictionary是一個(gè)存儲(chǔ)key-value的無(wú)序集合,key唯一,value可重復(fù)。
NSDictionary被定義為class,引用類型,拷貝時(shí)具有引用意義。
常量集合 NSDictionary,可變集合: NSMutableDictionary:
常量性:長(zhǎng)度和元素指針都不能更改。但指針指向的對(duì)象內(nèi)部可以更改。
創(chuàng)建NSMutableDictionary 時(shí)用initWithCapacity 提前設(shè)置capacity
支持Fast Enumeration和NSEnumerator遍歷,前者較快。
-
排序方法
- sortedArrayUsingSortDescriptors:
- sortedArrayUsingFunction:context:
- sortedArrayUsingSelector:
其他類型
- NSMumber類是用來(lái)封裝基本數(shù)據(jù)類型。
- 裝箱(boxing)是一個(gè)基本類型的數(shù)據(jù)封裝成對(duì)象的過程
- 開箱(unboxing)從對(duì)象中提取基本類型的數(shù)據(jù)
+(NSNumber *) numberWithChar:(char) value;
+(NSNumber *) numberWithInt:(int) value;
+(NSNumber *) numberWithFloat:(float) value;
+(NSNumber *) numberWithBool:(BOOL) value;
//可以通過下面的實(shí)例方法重新獲得基本類型數(shù)據(jù):
-(char) charValue;
-(int) intValue;
-(float) floatValue;
-(BOOL) boolValue;
-(NSString *) stringValue;
- NSValue可以封裝任意值,可以使用NSValue將結(jié)構(gòu)體放入NSArray和NSDictionary中。
+(NSValue *) valueWithBytes: (const void *) value objCType:(const char *) type;
自動(dòng)引用計(jì)數(shù)ARC
ARC
- 自動(dòng)引用計(jì)數(shù)(Automatic Reference Counting)是Objective-C默認(rèn)的內(nèi)存管理機(jī)制,其針對(duì)堆上的對(duì)象,由編譯器自動(dòng)生成操作引用計(jì)數(shù)的指令(retain或release),來(lái)管理對(duì)象的創(chuàng)建與釋放。
- 哪些對(duì)象受ARC管理:
- OC對(duì)象指針
- Block指針
- 使用attribute((NSObject))定義的typedef
- 哪些對(duì)象不受ARC管理:
- 值類型(簡(jiǎn)單值類型,C語(yǔ)言struct)
- 使用其他方式分配的堆對(duì)象(如使用malloc分配)
- 非內(nèi)存資源
引用計(jì)數(shù)管理
- 新創(chuàng)建(使用alloc,new,copy等)一個(gè)引用類型對(duì)象,引用計(jì)數(shù)為1
BLNPoint *p1 = [[BLNPoint alloc]init];
BLNRectangle *rect = [[BLNRectangle alloc]init]; - 對(duì)象引用計(jì)數(shù)增1——retain操作:
- 將對(duì)象引用賦值給其他變量或常量。
BLNPoint *p2 = p1; - 將對(duì)象引用賦值給其他屬性或?qū)嵗兞俊?br>
rect.center = p1; - 將對(duì)象傳遞給函數(shù)參數(shù),或者返回值。
draw(p1); - 將對(duì)象加入集合中。
array=[[NSMutableArray alloc]initWithCapacity:10];
[array addObject:p1];
- 將對(duì)象引用賦值給其他變量或常量。
- 對(duì)象引用計(jì)數(shù)減1——release操作:
- 將局部變量或全局變量賦值為nil或其他值。
p1 = nil;
p2 = nil; - 將屬性賦值為nil或其他值。
rect.center = nil; - 實(shí)例屬性所在的對(duì)象被釋放。
- 參數(shù)或局部變量離開函數(shù)。
- 將對(duì)象從集合中刪除。
[array removeObjectAtIndex:0];
- 將局部變量或全局變量賦值為nil或其他值。
- 引用計(jì)數(shù)變?yōu)?時(shí),內(nèi)存自動(dòng)被釋放
自動(dòng)釋放池(Autorelease Pool)
release會(huì)導(dǎo)致對(duì)象立即釋放。如果頻繁對(duì)對(duì)象進(jìn)行release,可能會(huì)造成瑣碎的內(nèi)存管理負(fù)擔(dān)。autorelease可以將release的調(diào)用延遲到自動(dòng)釋放池被釋放時(shí)。
推薦使用自動(dòng)釋放池(AutoreleasePool)Block,當(dāng)其結(jié)束時(shí),所有接受autorelease消息的對(duì)象將會(huì)被立即釋放(即發(fā)送release消息)。
AppKit和UIKit框架在處理每一次事件循環(huán)迭代時(shí),都會(huì)將其放入一個(gè)Autorelease Pool中。大多數(shù)情況,無(wú)需程序員干預(yù)。
-
什么時(shí)候需要手工管理Autorelease Pool
- 編寫的程序不基于UI框架,如命令行程序。
- 在循環(huán)中創(chuàng)建大量臨時(shí)對(duì)象,需要更早地釋放,避免臨時(shí)對(duì)象聚集導(dǎo)致內(nèi)存峰值過大。
- 在主線程之外創(chuàng)建新的線程,在新線程開始執(zhí)行處,需要?jiǎng)?chuàng)建自己的Autorelease Pool.
- 可以嵌套使用Autorelease Pool.
類型合同:協(xié)議
認(rèn)識(shí)協(xié)議 Protocol
- 協(xié)議:類型的合同約定,只描述外部接口,不提供具體實(shí)現(xiàn)。
- 協(xié)議可以包含以下成員:
- 屬性
- 實(shí)例方法
- 類方法
- 初始化器-不常用
- 析構(gòu)器-不常用
@protocol Drawable
@property NSInteger x;
@property NSInteger y;
-(void)draw;
+(void)createShape;
@optional
-(void)moveToX:(NSInteger)x withY:(NSInteger)y;
@end
- 協(xié)議中無(wú)法包含實(shí)例變量成員
- 協(xié)議中定義的屬性本質(zhì)上是訪問器方法,編譯器不會(huì)合成實(shí)例變量。
協(xié)議關(guān)鍵字
-
@required:表明其后所有的方法是實(shí)現(xiàn)該協(xié)議的必須方法。協(xié)議的默認(rèn)行為,如果沒有指定@required ,協(xié)議中聲明的所有方法都默認(rèn)是必須實(shí)現(xiàn)的。 -
@optional:表明實(shí)現(xiàn)類時(shí)可以選擇性實(shí)現(xiàn)該方法。實(shí)現(xiàn)了該協(xié)議的類可以選擇不實(shí)現(xiàn)任何在@optional后所有聲明的方法。
使用協(xié)議
- 一個(gè)類遵守協(xié)議,需要實(shí)現(xiàn)協(xié)議約定的的所有@required成員
@interface BLNPoint : NSObject<Drawable>
@implementation BLNPoint
-(void)draw
{
NSLog(@"%@",self);
}
+(void)createShape{
NSLog(@"Create a Shape");
}
-(void)moveToX:(NSInteger)x withY:(NSInteger)y
{
self.x = x;
self.y = y;
}
@end
- 協(xié)議中的屬性須在實(shí)現(xiàn)類的.h文件中聲明(編譯器合成實(shí)例變量需要)。
@property NSInteger x;
@property NSInteger y;
- 注意編譯警告?:
- 遵守協(xié)議后卻沒有實(shí)現(xiàn)必選協(xié)議方法時(shí),會(huì)出現(xiàn)警告提示。
- 協(xié)議類型變量被賦值非協(xié)議類型對(duì)象時(shí),會(huì)出現(xiàn)警告提示。
- 協(xié)議本質(zhì)上是一種類型,可以作為聲明類型,但不能創(chuàng)建實(shí)例。
- 檢查協(xié)議類型
-->使用conformsToProtocol:檢查對(duì)象是否實(shí)現(xiàn)了協(xié)議。
void process2(id obj){
if ([obj conformsToProtocol:@protocol(AProtocol) ]) {
[obj methodA];
}
}
更多協(xié)議形式
- 協(xié)議繼承
- 一個(gè)協(xié)議可以繼承一個(gè)或多個(gè)協(xié)議
- 實(shí)現(xiàn)子協(xié)議的類型,也必須實(shí)現(xiàn)父協(xié)議中約定的成員
- 協(xié)議組合
- 可以使用protocol<A,B,...>來(lái)組合多個(gè)協(xié)議
- 實(shí)現(xiàn)組合協(xié)議的類型,必須實(shí)現(xiàn)組合協(xié)議中的每一個(gè)協(xié)議
- 可選協(xié)議
- 協(xié)議的 某些成員可以定義為optional,不必實(shí)現(xiàn)
- 常用協(xié)議
- NSObject:包含對(duì)象的常用操作,想等、字符串表示、哈希
- NSCopying:支持復(fù)制的類型必須遵守該協(xié)議
- NSFastEnumeration:實(shí)現(xiàn)快速枚舉 for-in的類型采用
- NSCoding協(xié)議:支持將對(duì)象圖進(jìn)行編碼/解碼以支持對(duì)象序列化
類別與擴(kuò)展
類別Category
- 類別支持在沒有源代碼的情況下,基于某些特定的場(chǎng)合,為一個(gè)類增加功能。
- 可以添加
- 類方法
- 實(shí)例方法
- 重寫基類方法
- 不能添加
- 屬性
- 實(shí)例變量
- 已存在的同名方法
@interface BLNPoint(Drawing)
-(void)draw;
-(void)setWeight:(NSInteger)weight;
-(NSInteger)weight;
@end
- 命名規(guī)范
- 文件名:類名+擴(kuò)展方法,如 NSString+Drawing.h/.m
使用場(chǎng)景
- 適合在沒有源代碼的情況下,向已經(jīng)封裝的類中添加方法。
@interface NSString(Drawing) - 為一個(gè)類在某些特殊場(chǎng)景下增加功能
@interface BLNPoint(Drawing)
-(void)draw;
-(void)setWeight:(NSInteger)weight;
-(NSInteger)weight;
@end
- 對(duì)于復(fù)雜的大型文件分割實(shí)現(xiàn)。
- 添加類別
- 自己創(chuàng)建的類
- 系統(tǒng)的類
- 第三方庫(kù)
擴(kuò)展extension
- 擴(kuò)展支持在編譯時(shí),有類的源代碼的前提下,向類添加功能??梢詫U(kuò)展看做匿名的類別。
- 接口定義在.m文件中@implementation前聲明,實(shí)現(xiàn)代碼仍然在@implementation內(nèi)實(shí)現(xiàn)。
@interface Circle ()
{
NSString * _name;
}
@property (readwrite )NSInteger radius;//修改讀寫屬性
@property NSInteger center;//添加屬性
-(float)getDiameter;//實(shí)例方法
+(void)process:(Circle*) circle;//類方法
@end
- 擴(kuò)展支持添加以下成員:
- 添加屬性。
- 添加實(shí)例成員。
- 添加類方法。
- 添加實(shí)例方法。
- 改寫屬性的讀寫屬性。
使用擴(kuò)展
- 擴(kuò)展實(shí)現(xiàn)的成員都只能在.m實(shí)現(xiàn)文件內(nèi)部訪問,在類外不可以直接訪問。
- 擴(kuò)展的主要用途在于信息隱藏,隱藏一些外部無(wú)需訪問、而內(nèi)部實(shí)現(xiàn)又需要使用的屬性、方法:
- 類的主接口主要用于“對(duì)類外公開”的接口。
- 類的擴(kuò)展接口用于“對(duì)類內(nèi)可見”的接口。
OC泛型
泛型是程序設(shè)計(jì)語(yǔ)言的一種特性,他主要是為了限制類型的,比如OC中的數(shù)組,你可以限制他里面裝的是NSString類型。
-
泛型的基本格式
- 泛型聲明格式:在聲明類的時(shí)候,在類型后面<泛型名稱>
- 泛型定義格式:放在限制的類型后面<類型>
-
泛型的好處
- 提高程序員開發(fā)規(guī)范,讓程序員一眼就可以看出該使用什么類型
- 限制類型,不允許裝入其它的類型
- 可以使用點(diǎn)語(yǔ)法