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弊端總結如下:

  1. 如果都在.h中import, 假如A拷貝了B, B拷貝了C , 如果C被修改了, 那麼B和A都需要重新拷貝. 因爲C修改了那麼B就會重新拷貝, 而B重新拷貝之後相當於B也被修改了, 那麼A也需要重新拷貝. 也就是說如果都在.h中拷貝, 只要有間接關係都會重新拷貝

  2. 如果在.h中用@class, 在.m中用import, 那麼如果一個文件發生了變化, 只有和這個文件有直接關係的那個文件纔會重新拷貝

  3. 所以在.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
  1. required :如果協議中的方法是@required的, 而遵守協議的類又沒有實現該方法, 那麼會報一個警告
  2. optional:如果協議中的方法是@optional的, 而遵守協議的類又沒有實現該方法, 那麼不會報警告
  3. 如果沒有使用任何關鍵字修飾協議中的方法, 那麼該方法默認就是required的
  4. OC中的協議又可以遵守其它協議, 只要一個協議遵守了其它協議, 那麼這個協議中就會自動包含其它協議的聲明
  5. 在OC中一個類可以遵守1個或多個協議(多個協議使用,逗號隔開)
  6. 父類遵守了某個協議, 那麼子類也會自動遵守這個協議
    注意:@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);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章