IOS開發學習筆記Day2-OC基礎二
內存管理
OC內存管理有兩種方式:手動、自動。
ARC: Automatic(自動) Reference(引用) Counting(計數)
不需要程序員管理內容, 編譯器會在適當的地方自動給我們添加release/retain等代碼
注意點: OC中的ARC和java中的垃圾回收機制不太一樣, java中的垃圾回收是系統幹得, 而OC中的ARC是編譯器幹得
MRC: Manul(手動) Reference(引用) Counting(計數)
所有對象的內容都需要我們手動管理, 需要程序員自己編寫release/retain等代碼
內存管理的原則就是有加就有減,也就是說, 一次alloc對應一次release, 一次retain對應一次relese
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 只要創建一個對象默認引用計數器的值就是1
Person *p = [[Person alloc] init];
NSLog(@"retainCount = %lu", [p retainCount]); // 1
// 只要給對象發送一個retain消息, 對象的引用計數器就會+1
[p retain];
NSLog(@"retainCount = %lu", [p retainCount]); // 2
// 通過指針變量p,給p指向的對象發送一條release消息
// 只要對象接收到release消息, 引用計數器就會-1
// 只要一個對象的引用計數器爲0, 系統就會釋放對象
[p release];
// 需要注意的是: release並不代表銷燬\回收對象, 僅僅是計數器-1
NSLog(@"retainCount = %lu", [p retainCount]); // 1
[p release]; // 0
NSLog(@"--------");
}
return 0;
}
每次內存釋放都會調用dealloc方法,
- (void)dealloc{
NSLog(@"dealloc");
// 注意:super dealloc一定要寫到所有代碼的最後
[super dealloc];
}
多個對象的內存管理
當A對象想使用B對象一定要對B對象進行一次retain, 這樣才能保證A對象存在B對象就存在, 也就是說這樣才能保證無論在什麼時候在A對象中都可以使用B對象
當A對象釋放的時候, 一定要對B對應進行一次release, 這樣才能保證A對象釋放了, B對應也會隨之釋放, 避免內存泄露
總結一句話: 有增就有減
- (void)setRoom:(Room *)room{
// 只有房間不同才需用release和retain
if (_room != room) {// 0ffe1 != 0ffe1
// 將以前的房間釋放掉 -1
[_room release];
/*
// 對房間的引用計數器+1
[room retain];
_room = room;
*/
// retain不僅僅會對引用計數器+1, 而且還會返回當前對象
_room = [room retain];
}
}
- (Room *)room{
return _room;
}
- (void)dealloc{
// 人釋放了, 那麼房間也需要釋放
[_room release];
NSLog(@"%s", __func__);
[super dealloc];
}
在談@property修飾符-內存管理
修飾符可以使用的關鍵字:
屬性可讀性
- readonly: 只會生成getter方法
- readwrite: 既會生成getter也會生成setter, 默認什麼都不寫就是readwrite
屬性方法名
- getter: 可以給生成的getter方法起一個名稱
- setter: 可以給生成的setter方法起一個名稱
內存管理
手動釋放
- retain: 就會自動幫我們生成getter/setter方法內存管理的代碼
- assign: 不會幫我們生成set方法內存管理的代碼, 僅僅只會生成普通的getter/setter方法, 默認什麼都不寫就是assign
自動釋放
- strong 用於OC對象,相當於MRC的retain
- weak 用於OC對象,相當於MRC中的assign
- assign 用於基本數據類型,相當於MRC中的assign
多線程
- atomic :性能低(默認)
- nonatomic :性能高
注
1.相同類型的property修飾符不能同時使用(屬性方法名除外)
2.不同類型的property修飾符可以多個結合在一起使用, 多個之間用,號隔開
@property(nonatomic, retain) Room *room;
@class避免重複拷貝和編譯性能優化
使用**#import** 的弊端
-
由於import是一個預編譯指令, 他會將"“中的文件拷貝到import所在的位置
並且import有一個特點, 只要”"中的文件發生了變化, 那麼import就會重新拷貝一次(更新操作),影響編譯性能 -
如果兩個.h文件相互import,則會陷入死循環。
故使用import弊端總結如下:
-
如果都在.h中import, 假如A拷貝了B, B拷貝了C , 如果C被修改了, 那麼B和A都需要重新拷貝. 因爲C修改了那麼B就會重新拷貝, 而B重新拷貝之後相當於B也被修改了, 那麼A也需要重新拷貝. 也就是說如果都在.h中拷貝, 只要有間接關係都會重新拷貝
-
如果在.h中用@class, 在.m中用import, 那麼如果一個文件發生了變化, 只有和這個文件有直接關係的那個文件纔會重新拷貝
-
所以在.h中用@class可以提升編譯效率
解決方案:將#import換成@class,例如:@class Car;
@class僅僅是告訴編譯器, @class後面的名稱是一個類, 不會做任何拷貝操作
注: 由於@class僅僅是告訴編譯器後面的名稱是一個類, 所以編譯器並不知道這個類中有哪些屬性和方法, 所以在.m中使用這個類時需要import這個類, 才能使用。
強指針弱指針對釋放的影響
ARC的判斷準則: 只要沒有強指針指向對象, 對象就會釋放
默認情況下所有的指針都是強指針
Person *p = [[Person alloc] init];
p = nil;
__strong Person *p = [[Person alloc] init];
// 弱指針
__weak Person *p2 = p;
p = nil;
//在開發中, 千萬不要使用一個弱指針保存一個剛剛創建的對象,否則立即釋放
__weak Person *p = [[Person alloc] init];
類別Category
類別的文件名:ClassName + CategoryName.h\.m例如:Person+NJ.h
也可以使用Xcode工具生成Category類型的文件。
類別的聲明
@interface ClassName (CategoryName)
NewMethod;
@end
// 分類的實現
@implementation ClassName(CategoryName)
NewMethod
... ...
@end
ClassName: 需要給哪個類擴充方法
CategoryName: 分類的名稱
NewMethod: 擴充的方法
注意:不允許在類別中添加變量
匿名類別
當原有類和類別中都有同樣方法時會先調用類別中的方法,忽略原有類的方法。我們可以利用這個特性實現私有方法和私有屬性。
只需要在類別中聲明方法名和屬性名相同則會覆蓋原油方法和屬性。
例如:
@interface Person ()
{
int _age;
}
- (void)say;
@end
@implementation Person
int _age;
-(void)eat{
NSLog(@"%s", __func__);
}
- (void)say{
NSLog(@"age = %i", _age);
}
@end
block的使用
//沒有參數的block
void (^roseBlock) ();
// 如果block沒有參數, 那麼^後面的()可以省略
roseBlock = ^(){
printf("{@}");
};
// 要想執行block保存的代碼, 必須調用block纔會執行
roseBlock();
//一個參數的block
void (^roseBlock) (int);
roseBlock = ^(int num){
NSLog(@"sum = %i", num);
};
roseBlock(2);
//兩個參數帶返回值的block
int (^sumBlock) (int, int);
sumBlock =^(int value1, int value2){
return value1 + value2;
};
//簡寫形式
int (^printBlock)(int)= ^int (int num){
NSLog(@"sum = %i", num);
return 1;
}
printBlock(2);
使用typedef定義block
typedef int (^calculteBlock)(int , int);
calculteBlock sumBlock = ^(int value1, int value2){
return value1 + value2;
};
block應用場景
我們寫代碼時經常會出現上面代碼和下面代碼都相同的情況,這個時候抽取方法,那麼調用方法的代碼就是重複代碼,例如:
void goToWorkInday1() {
goToWorkPrefix();
//不同的代碼塊
goToWorkSubfix();
}
如果我們把不同的代碼塊當作block來傳入並調用,則會簡潔很多代碼。
// 當發現代碼的前面和後面都是一樣的時候, 這個時候就可以使用block
void goToWork(void (^workBlock)()){
NSLog(@"起牀");
// 不一樣
workBlock();
NSLog(@"睡覺");
}
void goToWorkInDay1(){
goToWork(^{
NSLog(@"開始編寫代碼");
});
}
block注意事項
block可以訪問外部變量,但是不能修改外部變量,若要修改,需要加上__block關鍵字,例如:
__block int a = 10;
block是存儲在堆中還是棧中
默認情況下block存儲在棧中, 如果對block進行一個copy操作, block會轉移到堆中
如果block在棧中, block中訪問了外界的對象, 那麼不會對對象進行retain操作
但是如果block在堆中, block中訪問了外界的對象, 那麼會對外界的對象進行一次retain
如果在block中訪問了外界的對象, 一定要給對象加上__block, 只要加上了__block, 哪怕block在堆中, 也不會對外界的對象進行retain
如果是在ARC開發中就需要在前面加上__weak
copy操作例子:Block_copy(myBlock);
OC的協議protocol
OC的協議相當於java中的接口,但有以下注意點:
- 協議只能聲明方法, 不能聲明屬性
- 協議有兩種修飾符。@required、@optional
- required :如果協議中的方法是@required的, 而遵守協議的類又沒有實現該方法, 那麼會報一個警告
- optional:如果協議中的方法是@optional的, 而遵守協議的類又沒有實現該方法, 那麼不會報警告
- 如果沒有使用任何關鍵字修飾協議中的方法, 那麼該方法默認就是required的
- OC中的協議又可以遵守其它協議, 只要一個協議遵守了其它協議, 那麼這個協議中就會自動包含其它協議的聲明
- 在OC中一個類可以遵守1個或多個協議(多個協議使用,逗號隔開)
- 父類遵守了某個協議, 那麼子類也會自動遵守這個協議
注意:@required和@optional僅僅使用程序員之間交流, 並不能嚴格的控制某一個遵守該協議的類必須要實現該方法, 因爲即便不是實現也不會報錯, 只會報一個警告
//聲明協議
@protocol SportProtocol <NSObject>
// 方法聲明列表
- (void)playFootball;
@end
//實現協議
@interface Person : NSObject <SportProtocol>
@end
@implementation Person
- (void)playFootball{
NSLog(@"%s", __func__);
}
- (void)playBasketball{
NSLog(@"%s", __func__);
}
- (void)playBaseball{
NSLog(@"%s", __func__);
}
@end
協議的應用場景:
類型限定:
協議的第一個應用場景, 可以將協議寫在數據類型的右邊, 明確的標註如果想給該變量賦值, 那麼該對象必須遵守某個協議
例如:Wife<WifeCondition> *w = [Wife new];
注意: 雖然在接受某一個對象的時候, 對這個對象進行了類型限定(限定它必須實現某個協議), 但是並不意味着這個對象就真正的實現了該方法. 所以每次在調用對象的協議方法時應該進行一次驗證
if ([self.wife respondsToSelector:@selector(cooking)]) {
[self.wife cooking];
}
if ([self.wife respondsToSelector:@selector(washing)]) {
[self.wife washing];
}
if ([self.wife respondsToSelector:@selector(job)]) {
[self.wife job];
}
字符串
通過不同的方式創建字符串,字符串對象儲存的位置也不一樣
如果是通過字符串常量創建,那麼字符串對象存儲在常量區中
如果是通過alloc initWithFormat/stringWithFormat創建,那麼字符串對象存儲在堆區中
而且需要注意:
不同的平臺存儲的方式也不一樣,如果是Mac平臺系統會自動對字符串對象進行優化,但是如果是iOS平臺就是兩個對象
不同的編譯器存儲的方式也不一樣,如果是Xcode6以下並且是在iOS平臺,那麼每次alloc都會創建一個新的對象,如果是在Xcode6以上那麼alloc多次指向同一塊存儲空間
創建字符串
通過字符串常量創建
注意:如果是通過字符串常量創建對象,並且字符串常量的內容一致,那麼如果創建多個字符串對象,多個對象指向同一塊存儲空間
NSString *str1 = @"lnj";
NSString *str11 = @"lnj";
NSLog(@"str1 = %p, str11 = %p", str1 ,str11);
通過alloc init創建
只要調用alloc就會在堆內存中開闢一塊存儲空間
NSString *str2 = [[NSString alloc]initWithFormat:@"lmj"];
NSString *str22 = [[NSString alloc]initWithFormat:@"lmj"];
NSLog(@"str2 = %p, str22 = %p", str2, str22);
通過類工廠方法創建/ stringWithFormat
內部其實就是封裝了alloc init
NSString *str3 = [NSString stringWithFormat:@"zs"];
NSString *str33= [NSString stringWithFormat:@"zs"];
注意:一般情況下,只要是通過alloc或者類工廠方法創建的對象,每次都會在堆內存中開闢一塊新的存儲空間,但是如果是通過alloc的initWithString方法除外,因爲這個方法是通過copy返回一個字符串對象給我們,而copy又分爲深拷貝和淺拷貝,如果是深拷貝會創建一個新的對象,如果是淺拷貝不會創建一個新的對象,而是直接返回被拷貝的對象的地址給我們
NSString *str4 = [[NSString alloc]initWithString:@"ls"];
NSString *str44 = [[NSString alloc]initWithString:@"ls"];
NSLog(@"str4 = %p, str44 = %p", str4, str44);
從文本文件中讀取字符串
file: 文件路徑,
encoding: 編碼英文 iOS-5988-1 中文 GBK GBK2312 , 一般情況填寫UTF-8
error: 如果讀取錯誤, 會將錯誤信息保存到error中 ,如果讀取正確, 就沒有error = nil
注意: 以後在OC方法中但凡看到XXXofFile的方法, 傳遞的一定是全路徑(絕對路徑)
NSString *path = @"/Users/xiaomage/Desktop/lnj.txt";
NSError *error = nil;
// 從文件中讀取字符串
NSString *str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
if (error == nil) {
NSLog(@"str = %@", str);
}else{
NSLog(@"error = %@", [error localizedDescription]);
}
// 將字符串寫入到文件中
NSString *str = @"HelloWorld";
// atomically 如果傳入YES, 字符串寫入文件的過程中如果沒有寫完, 那麼不會生成文件
// 如果傳入NO, 字符串寫入文件的過程中如果沒有寫完, 會生成文件
NSString *path2 = @"/Users/xiaomage/Desktop/abc.txt";
BOOL flag = [str writeToFile:path2 atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSLog(@"flag = %i", flag);
文件讀取
1.創建URL
協議頭 + 主機地址 + 文件路徑
NSString *path = @"file://192.168.199.199/Users/NJ-Lee/Desktop/lnj.txt";
NSString *path = @"http://www.baidu.com";
//注意:如果加載的資源是本機上的資源,那麼URL中的主機地址可以省略
//雖然主機地址可以省略,但是需要注意,文件路勁中最前面的/不能省略,文件路徑最前面的/代表根路徑
// NSString *path = @"file:///Users/NJ-Lee/Desktop/lnj.txt";
// NSURL *url = [NSURL URLWithString:path];
//注意:如果是通過NSURL的fileURLWithPath:方法創建URL,那麼系統會自動給我們傳入的字符串添加協議頭(file://),所以字符串中不需要再寫file://
// 注意:開發中一 般情況下,如果是訪問本機的資源,創建URL的時候,建議使用fileURLWithPath方法創建
//因爲url不支持中文,如果URL中包含中文,那麼無法訪問;但是如果是通過fileURLWithString方法創建URL,哪怕URL中包含中文也可以進行訪問,系統內部會自動對URL中包含的中文進行處理
// NSURL *url = [NSURL fileURLWithPath:path];
NSString *path = @"file:///Users/NJ-Lee/Desktop/lnj.txt";
//如果URL中包含中文,又非不通過fileURLWithPath創建,也可以破
//如果想破就必須在創建URL之前先對字符串中的中文進行處理,進行百分號編碼
NSLog(@"處理前:%@", path);
path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"處理後:%@", path);
NSURL *url = [NSURL URLWithString:path];
NSLog(@"url = %@", url);
//2.根據URL加載文件中的字符串
NSString *str = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSLog(@"str = %@", str);
*/
//2.文件寫入
NSString *str = @"lnj";
// NSString *path = @"file:///Users/NJ-Lee/Desktop/未命名文件夾/abc.txt";
// path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// NSURL *url = [NSURL URLWithString:path];
NSString *path = @"/Users/NJ-Lee/Desktop/未命名文件夾/abc.txt";
NSURL *url = [NSURL fileURLWithPath:path];
[str writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:nil];
//注意點:如果多次往同一個文件中寫入內容,那麼後一次的會覆蓋前一次的
NSString *str2 = @"xxoo";
[str2 writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:nil];
字符串的比較
NSString *str1 = @"abc";
NSString *str2 = @"ABC";
/*
// 比較兩個字符串的"內容"是否相同
BOOL flag = [str1 isEqualToString:str2];
NSLog(@"flag = %i", flag);
// 下面這個方法, 是比較兩個字符串的"地址"是否相同
flag = (str1 == str2);
NSLog(@"flag = %i", flag);
*/
// 比較字符串的大小
/*
// NSOrderedAscending 前面的小於後面的
// NSOrderedSame, 兩個字符串相等
// NSOrderedDescending 前面的大於後面的
switch ([str1 compare:str2]) {
case NSOrderedAscending:
NSLog(@"str1小於str2");
break;
case NSOrderedSame:
NSLog(@"str1等於str2");
break;
case NSOrderedDescending:
NSLog(@"str1大於str2");
break;
default:
break;
}
*/
/*
// 忽略大小寫進行比較
switch ([str1 caseInsensitiveCompare:str2]) {
case NSOrderedAscending:
NSLog(@"str1小於str2");
break;
case NSOrderedSame:
NSLog(@"str1等於str2");
break;
case NSOrderedDescending:
NSLog(@"str1大於str2");
break;
default:
break;
}
字符串的查找
// NSString *str = @"http://www.520it.com/img/lnj.gif";
// 1.判斷是否以什麼開頭
/*
// 本質就是從字符串的第一個字符開始匹配, 只要不匹配就返回NO
if ([str hasPrefix:@"http://"]) {
NSLog(@"是一個URL");
}else{
NSLog(@"不是一個URL");
}
*/
// 2.判斷是否以什麼結尾
/*
// 本質就是從字符串的最後一個字符開始匹配, 只要不匹配就返回NO
if ([str hasSuffix:@".gif"]) {
NSLog(@"動態圖片");
}else{
NSLog(@"不是動態圖片");
}
*/
// 3.判斷字符串中是否包含520it.com
/*
NSString *str = @"abcd";
// 只要str中包含該字符串, 那麼就會返回該字符串在str中的起始位置以及該字符串的長度
// location從0開始 , length從1開始
// 如果str中沒有需要查找的字符串, 那麼返回的range的length=0, location = NSNotFound
NSRange range = [str rangeOfString:@"lnj"];
// if (range.location == NSNotFound) {
if (range.length == 0){
NSLog(@"str中沒有需要查找的字符串");
}else{
NSLog(@"str中有需要查找的字符串");
NSLog(@"location = %lu, length = %lu", range.location, range.length);
}
*/
字符串的借取
NSString *str = @"<head>小碼哥</head>";
/*
// NSRange : 位置/長度
// NSRange range = {6, 3};
// NSRange range;
// range.location = 6;
// range.length = 3;
// 只要是OC提供的結構體, 一般都可以使用NSMakeXXX來創建
// NSRange range = NSMakeRange(6, 3);
*/
/*
// 1.動態獲取截取的起始位置
NSUInteger location = [str rangeOfString:@">"].location + 1;
// 2.動態獲取截取的長度
// 注意:rangeOfString是從左至右的開始查找, 只要找到就不找了
// NSUInteger length = [str rangeOfString:@"<" options:NSBackwardsSearch].location - location;
NSUInteger length = [str rangeOfString:@"</"].location - location;
NSLog(@"location = %lu, length = %lu", location, length);
NSRange range = NSMakeRange(location, length);
NSString *newStr = [str substringWithRange:range];
NSLog(@"str = %@", str);
NSLog(@"newStr = %@", newStr);
// NSString *temp = @"abcdefa";
// NSRange range =[temp rangeOfString:@"a" options:NSBackwardsSearch];
// NSLog(@"%lu", range.location);
*/
// 從什麼地方開始截取, 一直截取到最後
// NSString *newStr = [str substringFromIndex:6];
// NSLog(@"newStr = %@", newStr);
// 從開頭開始截取, 一直截取到什麼位置
// NSString *newStr = [str substringToIndex:6];
// NSLog(@"newStr = %@", newStr);
/*
<head>小碼哥</head> --> 小碼哥</head> --> 小碼哥
<head>小碼哥</head> --> <head>小碼哥 --> 小碼哥
*/
NSLog(@"str = %@", str);
NSUInteger location = [str rangeOfString:@">"].location + 1;
NSString *newStr = [str substringFromIndex:location];
NSLog(@"newStr = %@", newStr);
location = [newStr rangeOfString:@"</"].location;
// 改變了指針的指向, 並不是修改了原來的字符串
newStr = [newStr substringToIndex:location];
NSLog(@"newStr = %@", newStr);
字符串的替換
/*
// 需求: 將&符號替換爲/
NSString *str = @"http:&&www.520it.com&img&lnj.gif";
// OccurrencesOfString: 要替換誰
// withString: 用誰替換
NSString *newStr = [str stringByReplacingOccurrencesOfString:@"&" withString:@"/"];
NSLog(@"newStr = %@", newStr);
*/
/*
// 1.去除空格 2.將&替換爲/
NSString *str = @" http: &&www. 520it.com &img&lnj.gif ";
// 1.去除空格
NSString *newStr = [str stringByReplacingOccurrencesOfString:@" " withString:@""];
NSLog(@"newStr = |%@|", newStr);
NSString *newStr2 = [newStr stringByReplacingOccurrencesOfString:@"&" withString:@"/"];
NSLog(@"newStr2 = |%@|", newStr2);
*/
// 3.替換首尾
// NSString *str = @" http:&&www.520it.com&img&lnj.gif ";
NSString *str = @"HTTP://www.520it.com/img/LNJ.GIF";
// NSCharacterSet *set = [NSCharacterSet whitespaceCharacterSet];
// NSString *newStr = [str stringByTrimmingCharactersInSet:set];
NSCharacterSet *set = [NSCharacterSet uppercaseLetterCharacterSet];
NSString *newStr = [str stringByTrimmingCharactersInSet:set];
NSLog(@"newStr = |%@|", newStr);
字符串與路徑
NSString *str = @"User/lnj/Desktop/lnj.txt.jpg";
// 1.判斷是否是絕對路徑
/*
// 其實本質就是判斷字符串是否以/開頭
if([str isAbsolutePath])
{
NSLog(@"是絕對路徑");
}else{
NSLog(@"不是絕對路徑");
}
*/
// 2.獲取文件路徑中的最後一個目錄
// 本質就是獲取路徑中最後一個/後面的內容
/*
NSString *newStr = [str lastPathComponent];
NSLog(@"%@", newStr);
*/
// 3.刪除文件路徑中的最後一個目錄
/*
// 本質就是刪除最後一個/後面的內容, 包括/也會被刪除
NSString *newStr = [str stringByDeletingLastPathComponent];
NSLog(@"%@", newStr);
*/
// 4.給文件路徑添加一個目錄
/*
// 本質就是在字符串的末尾加上一個/ 和指定的內容
// 注意: 如果路徑後面已經有了/, 那麼就不會添加了
// 如果路徑後面有多個/, 那麼會自動刪除多餘的/, 只保留一個
NSString *newStr = [str stringByAppendingPathComponent:@"xmg"];
NSLog(@"%@", newStr);
*/
// 5.獲取路徑中文件的擴展名
/*
// 本質就是從字符串的末尾開始查找., 截取第一個.後面的內容
NSString *newStr = [str pathExtension];
NSLog(@"%@", newStr);
*/
// 6.刪除路徑中文件的擴展名
/*
// 本質就是從字符串的末尾開始查找.,刪除第一個.和.後面的內容
NSString *newStr = [str stringByDeletingPathExtension];
NSLog(@"%@", newStr);
*/
// 7.給文件路徑添加一個擴展名
// 本質就是在字符串的末尾加上一個.和指定的內容
NSString *newStr = [str stringByAppendingPathExtension:@"jpg"];
NSLog(@"%@", newStr);
字符串的轉換
// NSString *str = @"abc";
// 1.將字符串轉換爲大寫
/*
NSString *newStr = [str uppercaseString];
NSLog(@"%@", newStr);
*/
// 2.將字符串轉換爲小寫
/*
NSString *newStr2 = [newStr lowercaseString];
NSLog(@"%@", newStr2);
// htpp://www.520it.com/img/lnj.GIF;
*/
// 3.將字符串的首字符轉換爲大寫
/*
NSString *newStr = [str capitalizedString];
NSLog(@"%@", newStr);
*/
// 4.字符串與基本數據類型的轉換
/*
NSString *str1 = @"110";
NSString *str2 = @"120";
// str1 + str2; // 錯誤
int value1 = [str1 intValue];
int value2 = [str2 intValue];
NSLog(@"sum = %i", value1 + value2);
// 注意: 如果不是int,double,float,bool,integer,longlong這些類型就不要亂用
NSString *str3 = @"abc";
int value3 = [str3 intValue];
NSLog(@"value3 = %i", value3);
*/
// 5.C語言字符串和OC字符串之間的轉換
/*
char *cStr = "lnj";
NSString *str = [NSString stringWithUTF8String:cStr];
NSLog(@"str = %@", str);
NSString *newStr = @"lmj";
const char *cStr2 = [newStr UTF8String];
NSLog(@"cStr2 = %s", cStr2);
*/
NSMutableString
/*
NSString *str = @"lnj"; // 一開始str指向@"lnj"對應的內存
str = @"lmj"; // 修改了str指針的指向, 讓它指向@"lmj"對應的內存
NSString *newStr = [str stringByReplacingOccurrencesOfString:@"l" withString:@"X"];
NSLog(@"%@", newStr);
*/
// 創建一個空的字符串
NSMutableString *str = [NSMutableString string];
NSLog(@"修改前: %@", str);
[str appendString:@"lnj"];
NSLog(@"修改後: %@", str);
NSMutableString *strM = [[NSMutableString alloc] init];
// strM = [NSMutableString alloc] initWithFormat:<#(NSString *), ...#>
// strM = [NSMutableString stringWithFormat:<#(NSString *), ...#>]
NSMutableString *strM = [NSMutableString stringWithFormat:@"www.520it.com.520"];
// 1.在字符串後面添加/image
/*
[strM appendString:@"/image"];
// [strM appendFormat:@"/age is %i", 10];
NSLog(@"strM = %@", strM);
*/
// 2.刪除字符串中的520
/*
// 技巧: 在開發中, 我們經常利用rangeOfString和deleteCharactersInRange方法配合起來刪除指定的字符串
// 2.1先查找出520在字符串中的位置
NSRange range = [strM rangeOfString:@"520"];
// 2.2刪除520
[strM deleteCharactersInRange:range];
NSLog(@"strM = %@", strM);
*/
// 3.在520前面插入love這個單詞
/*
// insertString : 需要插入的字符串
// atIndex: 從哪裏開始插入
NSRange range = [strM rangeOfString:@"520"];
[strM insertString:@"love" atIndex:range.location];
NSLog(@"strM = %@", strM);
*/
// 4.要求將字符串中的520替換爲530
// 注意: 如果是調用NSString的字符串替換方法, 不會修改原有字符串, 而是生成一個新的字符串
// NSString *newStr =[strM stringByReplacingOccurrencesOfString:@"520" withString:@"530"];
// 注意: 一般情況下OC方法要求傳入一個參數如果沒有*, 大部分都是枚舉
// 一般情況下如果不想使用枚舉的值, 可以傳入0, 代表按照系統默認的方式處理
// OccurrencesOfString: 需要替換的字符串
// withString: 用什麼替換
// options: 替換時的搜索方式
// range: 搜索的範圍
// 返回值: 代表替換了多少個字符串
NSUInteger count = [strM replaceOccurrencesOfString:@"520" withString:@"530" options:0 range:NSMakeRange(0, strM.length)];
NSLog(@"strM = %@", strM);
NSLog(@"count = %lu", count);
// NSLog(@"newStr = %@", newStr);
/*
需求: 將3個520it拼接在一起, 中間用空格隔開
520it 520it 520it
*/
NSString *subStr = @"520it";
/*
// 520it-
NSString *newStr = [subStr stringByAppendingString:@" "];
// 520it-520it
newStr = [newStr stringByAppendingString:subStr];
// 520it-520it-
newStr = [newStr stringByAppendingString:@" "];
// 520it-520-520it
newStr = [newStr stringByAppendingString:subStr];
*/
/*
// 注意: 在開發中如果需要對字符串進行頻繁的操作, 不要使用不可變的字符串
NSString *newStr = [subStr stringByAppendingString:@" "];;
for (int i = 0; i < 2; ++i) {
newStr = [newStr stringByAppendingString:subStr];
newStr = [newStr stringByAppendingString:@" "];
}
// newStr = [newStr stringByReplacingCharactersInRange:NSMakeRange(newStr.length -1 , 1) withString:@""];
newStr = [newStr stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSLog(@"newStr = |%@|", newStr);
*/
// 創建一個空得字符串
NSMutableString *strM = [NSMutableString string];
for (int i = 0; i < 3; ++i) {
// 1.添加一個520it
[strM appendString:subStr];
// 2.添加一個空格
[strM appendString:@" "];
}
[strM deleteCharactersInRange:NSMakeRange(strM.length - 1, 1)];
NSLog(@"strM = |%@|", strM);