字符串處理NSString
認(rèn)識字符串NSString
- NSString是一個Unicode編碼治力、16位字符的字符序列
- NSString被定義為類价捧,引用類型,拷貝時具有引用語義。
- 初始化方法:字面初始化、初始化器逃贝、工廠方法
- NSSring擁有恒定性谣辞,所有的操作無法更改字符串本身,如果有更改沐扳,都是返回新值的形式泥从。
- NSString擁有共享機制,引用計數(shù)管理對其有特殊的管理規(guī)則
oc的NSString和c語言的區(qū)別
- NSString是一個oc對象,OC字符串是一個字符串對象,字符串常量需要用@""包含沪摄。
- C語言字符串是一個數(shù)據(jù)類型躯嫉,用""包含
- OC中的字符串以Unicode編碼,C語言的字符串以字符的ASCII碼形式杨拐。
- 打印OC字符串用%@,打印C語言字符串用%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];
//工廠方法,是一個類方法哄陶,通過類方法內(nèi)部返回一個對象
NSString *str4= @"Hello World!";
上面運行結(jié)果str1
和str4
的存放地址是一樣的(共享機制)帆阳。只要用字面常量創(chuàng)立的字符串才會共享。
- 判斷相等
isEqualToString
值是否相等 -
str1 == str2
比較指針(引用)是否相等
NSMutableString
- NSMutableString具有可變性,NSString具有恒定性
- NSMutableString不具有共享機制,NSString具有共享機制
- NSMutableString不是在原有內(nèi)存上直接增長,而是重新分配一個更大或更小的緩存容量存放字符
- NSMutableString是NSString的子類
NSMutableString *mustr1 = [NSMutableString stringWithString: @"Hello,World!"];
//工場方法停止初始化
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的改動奕筐,使他的父類NSString發(fā)作了改動
存在的固有問題:通過mustr1
的改動,使的父類NSString發(fā)生了改變(而上面提到NSString具有不變性)
緩存容量與增長
- 字符串初始化后,會分配一個緩存容量capacity,其長度一般大于實際的字符串?dāng)?shù)量,當(dāng)然也可以自己給它一個緩存容量
- 當(dāng)字符串增長時,如果實際需求大于capacity,其capacity會以兩倍的方式指數(shù)增長,代價是:
- 分配新的堆內(nèi)存2*capacity
- 將原來堆內(nèi)存的內(nèi)容拷貝到新內(nèi)存,
- 釋放原來堆內(nèi)存
- 最佳實踐:估計好capacity,預(yù)先分配好一定容量,避免以后capacity的增長
常見操作
- NSString常見操作
- 訪問字符串:獲取字符串变骡、字符串長度离赫、字面量、大小寫轉(zhuǎn)換
- 查詢字符串:定位子串塌碌、獲取子串渊胸、是否包含子串、查詢字符集
- 其他操作:比較字符串台妆、替換字符串翎猛、分解字符串
- NSMutableString:
- 添加字符串
[mustr3 appendString:@"Hello Objective"];
- 刪除字符串
- 修改字符串
- 添加字符串
集合類型
數(shù)組
- 數(shù)組是一個有序的元素序列,支持隨機存取接剩。索引從0開始切厘,索引訪問越界會拋出運行時異常。注意與C語言數(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ù)組中元素的個數(shù)疫稿,返回一個NSInteger
.NSArray被定義為class,引用類型鹃两,拷貝時具有引用語義遗座。
-
NSArray的元素必須是對象,即NSObject的子類俊扳。
- 如果為基本數(shù)值類型途蒋,須要用NSNumber 封裝為對象類型后,才能放入數(shù)組中馋记。
NSInteger number=100; NSNumber *numberObject1= [NSNumber numberWithInteger:number ];
- 如果為C語言結(jié)構(gòu)類型号坡,須要用NSValue 封裝為對象類型后懊烤,才能放入數(shù)組中。
NSValue *pointObject = [NSValue value:&point withObjCType:@encode(Point)];
- 數(shù)組元素可以是不同對象類型筋帖,可能會有類型不安全奸晴。
NSArray具有常量性:長度和元素指針都不能更改。但指針指向的對象內(nèi)部可以更改日麸。
NSArray內(nèi)存模型
數(shù)組遍歷
- 最快 for in 直接訪問內(nèi)存寄啼,優(yōu)化索引檢查,比for循環(huán)快5-10倍
- 較慢 NSEnumeration遍歷迭代的方法
NSEnumerator *enumerator = [array5 objectEnumerator];
BLNPoint* item;
while (item = [enumerator nextObject]){
item.x++;
item.y++;
}
- for循環(huán)最慢
數(shù)組查找的方法
-
indexOfObject
查找是否存在“值相等”的對象(類型需要實現(xiàn)isEqual)代箭。NSUInteger index1=[array5 indexOfObject:target];
-
indexOfObjectIdenticalTo
查找是否存在“指針想等”的對象墩划。NSUInteger index2=[array5 indexOfObjectIdenticalTo:p3];
objectAtIndex:
方法訪問數(shù)組中的單個元素,返回給定索引處的單個元素嗡综。lastObject:
方法返回數(shù)組的最后一個元素乙帮。
數(shù)組排序
不改變原數(shù)組(常量性),返回新數(shù)組极景。
NSArray* sortArray1=[array1 sortedArrayUsingSelector:@selector(compare:)];
使用NSMutableArray
- NSMutableArray支持更改數(shù)組長度和元素指針察净,為NSArray的子類。
- capacity與NSMuatbalString一樣
- 估計好capacity預(yù)先分配一定容量盼樟,避免以后增長
- 盡量避免使用
insertObject:atIndex:
和removeObjectAtIndex:
等操作氢卡,因為會改變數(shù)組元素序列,涉及大量內(nèi)存拷貝操作晨缴,代價高译秦。
set
- NSSet 是一個無序的集合,其存儲的對象不能重復(fù)击碗。
- 常量性:長度和元素指針都不能更改筑悴。但指針指向的對象內(nèi)部可以更改。
- 創(chuàng)建NSMutableSet時用initWithCapacity提前設(shè)置capacity稍途。
Dictionary字典類型
NSDictionary是一個存儲key-value的無序集合阁吝,key唯一,value可重復(fù)械拍。
NSDictionary被定義為class求摇,引用類型,拷貝時具有引用意義殊者。
常量集合 NSDictionary,可變集合: NSMutableDictionary:
常量性:長度和元素指針都不能更改与境。但指針指向的對象內(nèi)部可以更改。
創(chuàng)建NSMutableDictionary 時用initWithCapacity 提前設(shè)置capacity
支持Fast Enumeration和NSEnumerator遍歷猖吴,前者較快摔刁。
-
排序方法
- sortedArrayUsingSortDescriptors:
- sortedArrayUsingFunction:context:
- sortedArrayUsingSelector:
其他類型
- NSMumber類是用來封裝基本數(shù)據(jù)類型。
- 裝箱(boxing)是一個基本類型的數(shù)據(jù)封裝成對象的過程
- 開箱(unboxing)從對象中提取基本類型的數(shù)據(jù)
+(NSNumber *) numberWithChar:(char) value;
+(NSNumber *) numberWithInt:(int) value;
+(NSNumber *) numberWithFloat:(float) value;
+(NSNumber *) numberWithBool:(BOOL) value;
//可以通過下面的實例方法重新獲得基本類型數(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;
自動引用計數(shù)ARC
ARC
- 自動引用計數(shù)(Automatic Reference Counting)是Objective-C默認(rèn)的內(nèi)存管理機制绑谣,其針對堆上的對象,由編譯器自動生成操作引用計數(shù)的指令(retain或release)拗引,來管理對象的創(chuàng)建與釋放借宵。
- 哪些對象受ARC管理:
- OC對象指針
- Block指針
- 使用attribute((NSObject))定義的typedef
- 哪些對象不受ARC管理:
- 值類型(簡單值類型,C語言struct)
- 使用其他方式分配的堆對象(如使用malloc分配)
- 非內(nèi)存資源
引用計數(shù)管理
- 新創(chuàng)建(使用alloc矾削,new壤玫,copy等)一個引用類型對象,引用計數(shù)為1
BLNPoint *p1 = [[BLNPoint alloc]init];
BLNRectangle *rect = [[BLNRectangle alloc]init]; - 對象引用計數(shù)增1——retain操作:
- 將對象引用賦值給其他變量或常量哼凯。
BLNPoint *p2 = p1;
- 將對象引用賦值給其他屬性或?qū)嵗兞俊?br>
rect.center = p1;
- 將對象傳遞給函數(shù)參數(shù)欲间,或者返回值。
draw(p1);
- 將對象加入集合中断部。
array=[[NSMutableArray alloc]initWithCapacity:10];
[array addObject:p1];
- 將對象引用賦值給其他變量或常量哼凯。
- 對象引用計數(shù)減1——release操作:
- 將局部變量或全局變量賦值為nil或其他值猎贴。
p1 = nil;
p2 = nil;
- 將屬性賦值為nil或其他值。
rect.center = nil;
- 實例屬性所在的對象被釋放蝴光。
- 參數(shù)或局部變量離開函數(shù)她渴。
- 將對象從集合中刪除。
[array removeObjectAtIndex:0];
- 將局部變量或全局變量賦值為nil或其他值猎贴。
- 引用計數(shù)變?yōu)?時蔑祟,內(nèi)存自動被釋放
自動釋放池(Autorelease Pool)
release會導(dǎo)致對象立即釋放趁耗。如果頻繁對對象進行release,可能會造成瑣碎的內(nèi)存管理負(fù)擔(dān)做瞪。autorelease可以將release的調(diào)用延遲到自動釋放池被釋放時对粪。
推薦使用自動釋放池(AutoreleasePool)Block右冻,當(dāng)其結(jié)束時装蓬,所有接受autorelease消息的對象將會被立即釋放(即發(fā)送release消息)。
AppKit和UIKit框架在處理每一次事件循環(huán)迭代時纱扭,都會將其放入一個Autorelease Pool中牍帚。大多數(shù)情況,無需程序員干預(yù)乳蛾。
-
什么時候需要手工管理Autorelease Pool
- 編寫的程序不基于UI框架暗赶,如命令行程序。
- 在循環(huán)中創(chuàng)建大量臨時對象肃叶,需要更早地釋放蹂随,避免臨時對象聚集導(dǎo)致內(nèi)存峰值過大。
- 在主線程之外創(chuàng)建新的線程因惭,在新線程開始執(zhí)行處岳锁,需要創(chuàng)建自己的Autorelease Pool.
- 可以嵌套使用Autorelease Pool.
類型合同:協(xié)議
認(rèn)識協(xié)議 Protocol
- 協(xié)議:類型的合同約定,只描述外部接口蹦魔,不提供具體實現(xiàn)激率。
- 協(xié)議可以包含以下成員:
- 屬性
- 實例方法
- 類方法
- 初始化器-不常用
- 析構(gòu)器-不常用
@protocol Drawable
@property NSInteger x;
@property NSInteger y;
-(void)draw;
+(void)createShape;
@optional
-(void)moveToX:(NSInteger)x withY:(NSInteger)y;
@end
- 協(xié)議中無法包含實例變量成員
- 協(xié)議中定義的屬性本質(zhì)上是訪問器方法咳燕,編譯器不會合成實例變量。
協(xié)議關(guān)鍵字
-
@required:
表明其后所有的方法是實現(xiàn)該協(xié)議的必須方法乒躺。協(xié)議的默認(rèn)行為招盲,如果沒有指定@required ,協(xié)議中聲明的所有方法都默認(rèn)是必須實現(xiàn)的嘉冒。 -
@optional:
表明實現(xiàn)類時可以選擇性實現(xiàn)該方法曹货。實現(xiàn)了該協(xié)議的類可以選擇不實現(xiàn)任何在@optional后所有聲明的方法。
使用協(xié)議
- 一個類遵守協(xié)議健爬,需要實現(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é)議中的屬性須在實現(xiàn)類的.h文件中聲明(編譯器合成實例變量需要)控乾。
@property NSInteger x;
@property NSInteger y;
- 注意編譯警告?:
- 遵守協(xié)議后卻沒有實現(xiàn)必選協(xié)議方法時,會出現(xiàn)警告提示娜遵。
- 協(xié)議類型變量被賦值非協(xié)議類型對象時蜕衡,會出現(xiàn)警告提示。
- 協(xié)議本質(zhì)上是一種類型设拟,可以作為聲明類型慨仿,但不能創(chuàng)建實例。
- 檢查協(xié)議類型
-->使用conformsToProtocol:檢查對象是否實現(xiàn)了協(xié)議纳胧。
void process2(id obj){
if ([obj conformsToProtocol:@protocol(AProtocol) ]) {
[obj methodA];
}
}
更多協(xié)議形式
- 協(xié)議繼承
- 一個協(xié)議可以繼承一個或多個協(xié)議
- 實現(xiàn)子協(xié)議的類型镰吆,也必須實現(xiàn)父協(xié)議中約定的成員
- 協(xié)議組合
- 可以使用protocol<A,B,...>來組合多個協(xié)議
- 實現(xiàn)組合協(xié)議的類型,必須實現(xiàn)組合協(xié)議中的每一個協(xié)議
- 可選協(xié)議
- 協(xié)議的 某些成員可以定義為optional跑慕,不必實現(xiàn)
- 常用協(xié)議
- NSObject:包含對象的常用操作万皿,想等、字符串表示核行、哈希
- NSCopying:支持復(fù)制的類型必須遵守該協(xié)議
- NSFastEnumeration:實現(xiàn)快速枚舉 for-in的類型采用
- NSCoding協(xié)議:支持將對象圖進行編碼/解碼以支持對象序列化
類別與擴展
類別Category
- 類別支持在沒有源代碼的情況下牢硅,基于某些特定的場合,為一個類增加功能芝雪。
- 可以添加
- 類方法
- 實例方法
- 重寫基類方法
- 不能添加
- 屬性
- 實例變量
- 已存在的同名方法
@interface BLNPoint(Drawing)
-(void)draw;
-(void)setWeight:(NSInteger)weight;
-(NSInteger)weight;
@end
- 命名規(guī)范
- 文件名:類名+擴展方法减余,如 NSString+Drawing.h/.m
使用場景
- 適合在沒有源代碼的情況下,向已經(jīng)封裝的類中添加方法惩系。
@interface NSString(Drawing)
- 為一個類在某些特殊場景下增加功能
@interface BLNPoint(Drawing)
-(void)draw;
-(void)setWeight:(NSInteger)weight;
-(NSInteger)weight;
@end
- 對于復(fù)雜的大型文件分割實現(xiàn)位岔。
- 添加類別
- 自己創(chuàng)建的類
- 系統(tǒng)的類
- 第三方庫
擴展extension
- 擴展支持在編譯時,有類的源代碼的前提下堡牡,向類添加功能抒抬。可以將擴展看做匿名的類別晤柄。
- 接口定義在.m文件中@implementation前聲明擦剑,實現(xiàn)代碼仍然在@implementation內(nèi)實現(xiàn)。
@interface Circle ()
{
NSString * _name;
}
@property (readwrite )NSInteger radius;//修改讀寫屬性
@property NSInteger center;//添加屬性
-(float)getDiameter;//實例方法
+(void)process:(Circle*) circle;//類方法
@end
- 擴展支持添加以下成員:
- 添加屬性。
- 添加實例成員抓于。
- 添加類方法做粤。
- 添加實例方法。
- 改寫屬性的讀寫屬性捉撮。
使用擴展
- 擴展實現(xiàn)的成員都只能在.m實現(xiàn)文件內(nèi)部訪問怕品,在類外不可以直接訪問。
- 擴展的主要用途在于信息隱藏巾遭,隱藏一些外部無需訪問肉康、而內(nèi)部實現(xiàn)又需要使用的屬性、方法:
- 類的主接口主要用于“對類外公開”的接口灼舍。
- 類的擴展接口用于“對類內(nèi)可見”的接口吼和。
OC泛型
泛型是程序設(shè)計語言的一種特性,他主要是為了限制類型的骑素,比如OC中的數(shù)組炫乓,你可以限制他里面裝的是NSString類型。
-
泛型的基本格式
- 泛型聲明格式:在聲明類的時候,在類型后面<泛型名稱>
- 泛型定義格式:放在限制的類型后面<類型>
-
泛型的好處
- 提高程序員開發(fā)規(guī)范献丑,讓程序員一眼就可以看出該使用什么類型
- 限制類型末捣,不允許裝入其它的類型
- 可以使用點語法