Objective-C零碎知識點

weixin_34194087發表於2016-01-13

OC總結

[TOC]

零碎百科

1.類的命名應當使用匈牙利標識(Hungarian Notation),每個字母開頭大寫。
2.方法的命名應當使用駝峰標識(Camel Notation),首個單詞小寫,後面的單詞首字母大寫其他小寫,在oc初始化方法中如果不使用駝峰標識可能報錯,預設是不是初始化方法。
3.C語言字串(字元陣列)在OC中的賦值不能使用= 要使用字串拷貝函式(在oc中使用char用strcpy)
4.減少程式碼中的硬程式碼(hord code),硬程式碼很難維護,並且減少硬程式碼程式可讀性更強,靜態常量使用:static const 型別 全大寫用下滑線連線下一個單詞,計算公式之類的可以使用巨集定義。
5.API - Application Programming Interface (應用程式程式設計介面)
6.自動釋放池(在自動釋放池中建立的物件由自動釋放池託管 離開自動釋放池自動釋放),如果一個物件沒有指標指向它就成了垃圾物件會被系統自動清理,程式設計師只管分配記憶體不管釋放記憶體(ARC - 自動引用計數).
7.for-in迴圈需要對每個元素進行遍歷(除非用break終止迴圈),只讀迴圈,在迴圈過程中不能夠修改陣列中的元素.
8.不要在標頭檔案中包含自定義類的標頭檔案 因為可能導致迴圈包含標頭檔案的問題,如果類的宣告部分使用了其他自定義型別 可以做一個向前引用宣告.
9.方法宣告前面如果是- 說明該方法是物件方法 需要建立物件來呼叫.
10.方法宣告前面如果是+ 說明該方法是類方法 用類名直接呼叫.
11.三目運算子,貓王運算子:?
12.oc中的*即使指標也是引用。
13.求a,b,c三條邊三角形的面積,使用海倫公式

duoble p = (a + b + c) / 2;
duobel area = sqrt(p * (p - a) * (p - b) * (p - c));

14.當不知道起什麼名字的時候: foo - fuck up bar - beyond all recognization
15.RTTI 執行時型別識別 RunTime Type Identification)
16.神語錄: 在計算機的世界裡時間和空間是不可調和的矛盾,如果想贏得時間就要犧牲空間,如果想節省空間就會浪費時間

  1. ASCII 1位元組 - 字母、數字、符號、控制字元
    Unicode 2-4位元組不等 萬國碼
    GB2312 - 國標碼
    GBK - 國標擴
    GB18030
    18.為什麼複製了還要返回當前物件的指標? 級聯程式設計(開火車式程式設計)
    19.plist檔案,是XML(eXtensible Markup Language 可擴充套件標記語言)格式儲存資料
    20.NSDate物件的timeIntervalSinceDate:可以計算出兩個日期之間相差多少秒
    21.記憶體管理原則:能不用MRC就不用

誰建立誰釋放 +1 操作和 -1 操作必須成對出現
如果使用手動記憶體管理(MRC)需要了解四個方法
1.retain 物件引用計數+ 1
2.release 物件引用計數 - 1
3.retainCount 檢視物件引用計數值
4.autorelease 當使用了自動釋放池可以由自動釋放池自動釋放記憶體而不用再呼叫release方法

22.// @synthesize a = _a;
// 屬性合成:產生和屬性對應的成員變數、修改器和訪問器,系統預設會對屬性進行自動合成

協議(Protocol)

  • 協議委託和Block的使用

協議表能力,表約定,表角色

@protocol 協議名 <NSObject>

// 只有宣告沒有實現
// 相關方法的集合

@end

Objective-C的響應機制 不看指標只看物件

  • Objective-C採用了動態繼承編譯機制。動態編譯機制就是說在編譯時不能確定類之間的繼承關係。只有在執行時才確立類之間的繼承關係。正因如此,也不能在編譯時確定類的大小,自然也就不能將類的物件建立在棧中。

類、物件、訊息

  • 類:類是對一組具有共同屬性和行為的物件的抽象,它是物件的藍圖和模板

定義一個類要做兩件事情:
資料抽象 --- 屬性(名詞)
行為抽象 --- 方法(動詞)

  • 類和類之間的關係簡單的說有三種:
    IS-A 繼承
    HAS-A 關聯
    USE-A 依賴

屬性修飾符

  • 多執行緒特性:nonatomic和atomic

  • 讀寫特性:readwrite和readonly

  • 記憶體管理器:strong(普通物件指標,retain的代替平)、weak(插座變數,不需要管理生命週期的物件,可能導致迴圈引用的指標,代理物件的指標)、copy(NSString和block)、assign(基本資料型別)、retain、unsafe_unretain

  • 修改器和訪問器:setter 和getter

  • 物件:物件是獨一無二的,都有屬性和行為,物件屬於某個類,是一個具體的接受訊息的單元

比方說我們建一個學生類(抽象),那麼具體某個學生就是物件(具體)

  • 訊息:物件與物件之間的聯絡通過訊息來傳遞,程式中的一切操作就是依靠給物件傳送訊息來實現,物件接收到訊息就會呼叫有關物件的行為來完成相應的操作。

物件導向的三大支柱

1.封裝:我們定義一個類相當於封裝了資料結構和運算元據的過程,讓它們形成一個邏輯上的整體。
2.繼承:從一個已經有的類建立新類的過程就叫做繼承。提供繼承資訊的類成為父類(超類、基類);得到繼承資訊的類成為子類(派生類、衍生類)。通過繼承我們可以讓子類複用父類的程式碼(不在需要每個子類書寫和父類相同的重複程式碼),與此同時我們可以建立子類對系統的功能提供了增強(子類是對父類的擴充套件和增強)
3.多型:子類繼承父類的方法後,可以給父類的方法給出新的實現版本,這一過程稱為方法的重寫(也稱為方法覆蓋或方法置換)。由於不同的子類對父類的方法進行重寫是可以給出各自的實現版本,同樣的物件指標,接收到同樣的訊息,但是做了不同的事情,這就是多型。

如何實現多型(polymorphism)

  1. 方法重寫: 在繼承的過程中子類重寫(override)父類方法 不同的子類給出不同的實現版本
  2. 物件造型: 用父型別的指標指向子類物件

訪問物件屬性及修飾符

  • @private:私有的,對外界來說是不可見的
  • @protected:受保護的,對子類相當於公開,對其他類相當於私有。(預設)
  • @public:公開,對外界來說是可見的

常用的基礎類

字串

NSString

1.length:字串長度。
2.characterAtIndex:擷取哪個位置的單個字串,%C連線。
3.stringWithFormat:連線字串。
4.substringFromIdex:擷取從哪個位置開始的一個子串。
5.isEqualToString:比較兩個字串是否相同
6.stringWithString:返回相同的字串(把不可變的字串程式設計可變的字串)

NSString是不變的字串任何對字元的修改操作都會建立新的字串物件,而不是在原來的字串物件上修改。

跑馬燈示例

// 下面的程式碼實現了跑馬燈效果
    NSString *str = @"歡迎來到vistaWorld學習.....";
//
    while (1) {
//         字串的stringWithFormat:方法可以通過指定的格式串來建立並初始化一個字串物件
        // 字串的substringFromIndex:方法是從指定位置取子串
        // 字串的characterAtIndex:方法是取指定位置的字元
        str = [NSString stringWithFormat:@"%@%C", [str substringFromIndex:1], [str characterAtIndex:0]];
  //      NSLog(@"1%@1",[str substringFromIndex:1]);
  //      NSLog(@"0%C0",[str characterAtIndex:2]);
//         字串的UTF8String方法將Objective-C的字串(NSString *)變成C的字串(char *)
        printf("%s\n", [str UTF8String]);
        usleep(100000);
    }

NSMutableString

  • NNString的子類,相容它的所有方法

陣列

  • OC的陣列是物件 在記憶體中的堆(heap)上
  • 陣列和字典都是物件的持有者,可以用來儲存其他物件的地址,陣列是按相鄰關係的組織資料的,而字典是通過鍵值對對映來組織資料的。

NSArray

  • 建立的時候直接賦值分配了記憶體
  • NSArray和C陣列的區別:NSArray中只能存放物件的指標,不能存放基本資料的元素值。可以用NSNumber包裝基本資料型別或使用C語言的陣列來存放基本資料型別的元素。(通知方向傳一個基本資料的時候)
    1.firstObject:第一個元素指標
    2.lastObeject:最後一個元素物件的指標
    3.objectAtIndes:去指定索引的物件
    4.arrayByAddingObject:/arrayByAddingObjectsFromArray:將元素或陣列新增到陣列中並返回新的陣列
    5.count:陣列的個數
    6.componentsSeparatedByString:用指定的字元拆開字串返回一個陣列
       NSString *str10 = @"You go your way, I will go mine!";
        // 下面的方法用指定的字符集對字串進行拆分得到一個陣列
        // 應用場景: 將句子拆分成單詞
        NSArray *words = [str10 componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@", !"]];
        for (NSString *tempStr in words) {
            NSLog(@"%@", tempStr);
        }
        
        // 處理字串最重要的工具是正規表示式
        
        NSArray *unharmoniousContents = @[@"操", @"Fuck", @"fuck", @"FUCK"];
        NSString *str11 = @"操你大爺。Fuck you!";
        for (NSString *tempStr in unharmoniousContents) {
            // 將字串中指定內容替換成另外的內容
            // 應用場景: 構建和諧社會遮蔽不良內容
            str11 = [str11 stringByReplacingOccurrencesOfString:tempStr withString:@"*"];
        }

NSMutableArray

  • 需要alloc來分配記憶體
  • NSArray的子類,相容它
    1.addObject:新增物件
    2.insertObject atIndex/ insertObjects atIndexes:在那個物件的位置插入物件
    3.removeObject:/removeAllObjects/removeLastObject/removeObjectAtIndex:/removeObjectsIn Range:移除物件
    4.arrayWithArray:?
    5.replaceObjectAtIndex:withObject:/setObject:atIndexedSubscript:/setArray: 替換陣列中的元素
    5.直接copy轉換成不可變陣列

NSRange

1.rangOfString:方法在字串中查詢有沒有某個子串
2.NSRange是一個結構體 它包括了location(位置)和length(長度)兩個成員
3.如果location的值是NSNotFound就表示沒有找到指定的子串
4.應用場景: 搜尋和替換
5.substringWithRange:方法擷取字串指定範圍的子串

NSDictionary

1.字典是存放鍵值對組合的容器 也就是說字典容器中的每個條目都是由一個鍵和一個字構成的 鍵在前值在後中間是冒號 條目之間用逗號分隔
2.setObeject forKey:新增元素
3.allkeys:所有的鍵
4.removeObejectForKey:從字典中刪除元素

檔案的操作

資料持久化

資料的持久化就是將資料從記憶體中轉移到持久儲存介質(通常是硬碟)中,使用檔案系統儲存資料是最常見的持久化方案
在Objective-C開發中,我們將對資料結構轉換成NSData類物件的過程成為歸檔,也成為資料的序列化;相反的過程稱之為解歸檔,也稱為資料的反序列化。如果一個類的物件需要歸檔和解歸檔,那麼該類必須要遵循NSCoding協議,我們使用的NSString,NSArray,NSDuctionary遵循這個協議,因此可以進行歸檔和解歸檔。
如果物件中關聯了其他物件 如果在歸檔時要對關聯的物件進行歸檔, 那麼關聯的物件也必須遵循NSCoding協議才能進行歸檔,否則程式會崩潰

NSCoding協議有兩個方法:
1.一個用於物件屬性的編碼:- (void)encodeWithCoder:(NSCoder *)aCoder

  • (void) encodeWithCoder:(NSCoder *)aCoder {
    if (aCoder) {
    [aCoder encodeObject:_name forKey:@"name"];
    }
    }
    2.一個用於物件屬性的解碼:- (id)initWithCoder:(NSCoder *)aDecoder;
    所以只有遵循了該協議的物件才能進行歸檔和解歸檔
  • (instancetype) initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
    if (aDecoder) {
    _name = [aDecoder decodeObjectForKey:
    @"name"];
    }
    }
    return self;
    }

歸檔器(NSKeyedArchiver)和解歸檔器(NSKeyedUnarchiver)

示例:

#if 0
        CDStudent *stu1 = [[CDStudent alloc] init];
        stu1.name = @"王大錘";
        stu1.age = 24;
        stu1.car = [[CDVehicle alloc] initWithBrand:@"BMW" autoTransmission:YES maxSpeed:320];
        
        CDStudent *stu2 = [[CDStudent alloc] init];
        stu2.name = @"張大成";
        stu2.age = 19;
        stu2.car = [[CDVehicle alloc] initWithBrand:@"三蹦子" autoTransmission:NO maxSpeed:15];
        
        NSArray *array = @[stu1, stu2];
        // 將學生物件的狀態寫入儲存裝置的過程叫歸檔
        // 從儲存裝置中將學生物件的狀態讀取出來的過程叫解歸檔
        // 歸檔和解歸檔在有的地方稱為序列化和反序列化
        
        // NSMutableData物件相當於一個資料中轉站
        NSMutableData *mData = [NSMutableData data];
        // 建立歸檔器
        NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mData];
        // 將學生物件進行歸檔編碼並指定對應的鍵
        [archiver encodeObject:array forKey:@"array"];
        // 結束歸檔編碼(學生物件的資料已經編碼到mData物件中)
        [archiver finishEncoding];
        // 將歸檔資料寫入檔案中完成持久化
        [mData writeToFile:@"/Users/Hao/Desktop/data" atomically:YES];
#endif
#if 1
        // 將歸檔檔案的資料載入到記憶體中
        NSData *data = [NSData dataWithContentsOfFile:@"/Users/Hao/Desktop/data"];
        // 建立解歸檔器
        NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
        // 通過指定的鍵將物件解歸檔出來
        NSArray *array = [unarchiver decodeObjectForKey:@"array"];
        for (CDStudent *stu in array) {
            NSLog(@"姓名: %@", stu.name);
            NSLog(@"年齡: %ld", stu.age);
            [stu study];
            [stu drive];
        }
#endif
    }
    return 0;
}

NSFileManager

  • 檔案的操作
/ 獲得預設的檔案管理器物件
        NSFileManager *manager = [NSFileManager defaultManager];
        // 刪除檔案
        NSLog(@"%@", [manager removeItemAtPath:@"/Users/Hao/Desktop/abc.txt" error:nil]? @"刪除成功": @"刪除失敗");
        
        // NSData代表一組二進位制資料的物件
        // 提示: 下面的程式碼是聯網獲得資料如果網路不給力可能得到nil後者程式碼會在此處卡一段時間
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://10.0.8.8/sns/attachment/201505/12/123669_1431421013Nw4a.jpg"]];
        // 用指定的二進位制資料建立檔案物件
        // 如果第二個引數是nil則建立一個空檔案
        NSLog(@"%@", [manager createFileAtPath:@"/Users/Hao/Desktop/你好" contents:data attributes:nil]? @"建立成功":@"建立失敗");
        // 建立資料夾
        // 如果第二個引數是YES則會在上級資料夾不存在時依次建立出上級資料夾再建立當前指定的資料夾
        NSLog(@"%@", [manager createDirectoryAtPath:@"/Users/Hao/Desktop/abc/def/小狗屎" withIntermediateDirectories:YES attributes:nil error:nil]? @"建立資料夾成功": @"建立資料夾失敗");
        
        // 移動(剪下)資料夾
        [manager moveItemAtPath:@"/Users/Hao/Desktop/abc/def/小狗屎" toPath:@"/Users/Hao/Desktop/x/shit" error:nil];
     
        // 刪除資料夾
        [manager removeItemAtPath:@"/Users/Hao/Desktop/b" error:nil];
    }
    return 0;

NSFileHandle:控制程式碼

  • 檔案內容的操作
    • NSFileHandle:控制程式碼(指標)fileHandleForUpdatingAtPath更新檔案
NSArray *myarray = @[@"hello", @"good", @"simple", @"shit"];
        
        myarray = [myarray sortedArrayUsingSelector:@selector(compare:)];
        
        NSLog(@"%@", myarray);
        
        // handle - 控制程式碼(指標)
        NSFileHandle *handler = [NSFileHandle fileHandleForUpdatingAtPath:@"/Users/Hao/Desktop/hello.txt"];
        
        // NSLog(@"檔案有: %ld位元組", handler.availableData.length);
        
        // 讀取6個位元組
//        NSData *data = [handler readDataOfLength:6];
//        NSLog(@"%@", data);
//        NSLog(@"檔案有: %ld位元組", handler.availableData.length);
//        NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        
        NSMutableData *mData = [NSMutableData data];
        [mData appendData:[@"面朝電腦\n" dataUsingEncoding:NSUTF8StringEncoding]];
        [mData appendData:handler.availableData];
        
        // 將檔案指標移到檔案開頭的位置
        [handler seekToFileOffset:0];
        
        [handler writeData:mData];
        #if 0
        NSString *str = @"good good girls";
        NSData *newData = [str dataUsingEncoding:NSUTF8StringEncoding];
        [handler writeData:newData];
        // 將檔案指標移到檔案的末尾
        [handler seekToEndOfFile];
        // fopen/fclose/fseek/fread/fwrite/ftell
        
        NSData *zhData = [@"我愛你們" dataUsingEncoding:NSUTF8StringEncoding];
        // 將資料寫入檔案
       [handler writeData:zhData];
       #endif
       }
    return 0;
    }

JSON及其資料解析

JSON全稱JavaScript Object Notation(JavaScript物件表示式),是目前最多的儲存和交換文字資訊的語法,比XML更小更快更易解析,是一種輕量級的文字資料交換格式
  JSON的語法規則

  • 資料在名/值對中
  • 資料由逗號分隔
  • 花括號儲存物件
  • 方括號儲存陣列
  • JSONObjectWithData:option:error:
  • NSDictionary / NSArray

KVC

  • setValue:forKey:
    setValuesForKeysWithDictionary:

通常需要重寫setValue:forUndefinedKey:方法

 .h實體類(模型類 - 資料模型 只有屬性沒有業務邏輯方法
 @property (nonatomic, assign) NSUInteger wid;
 
 .m- (void) setValue:(id)value forKey:(NSString *)key {
// 對於屬性和JSON資料型別不匹配的情況需要手動轉換
if ([key isEqualToString:@"wid"]) {
    self.wid = [value integerValue];
}
 else {
    // 對於不需要型別轉換的鍵值對組合直接使用KVC賦值
    [super setValue:value forKey:key];
    // 不能寫下面的程式碼否則會因為遞迴呼叫不收斂導致棧溢位
    // [self setValue:value forKey:key];
}

// 提示: 使用KVC大招時一定重寫此方法
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
// 在使用KVC時通常都需要重寫此方法來處理不能識別的key
// 如果JSON資料中的鍵和類的屬性名不匹配可以通過下面的字典進行轉換
NSDictionary *keyPropDict = @{@"wpic_large": @"largePicUrl", @"update_time": @"updateTime"};
// 如果JSON中的鍵在類中有與之對應的屬性才使用KVC給該屬性賦值
// 如果沒有對應的屬性就什麼都不要做
if (keyPropDict[key]) {
    [self setValue:value forKey:keyPropDict[key]];
}

}

匿名類別

  • 定義:// 匿名類別(Anonymous Category) - 類擴充套件
    @interface 類名()
    // 此處可以放置類私有的東西
    @end

Block

  • Block的用法跟C語言中指向函式的指標用法幾乎一致

  • 定義方法一:

    定義Block型別的屬性(用來儲存一段回撥程式碼)
    屬性修飾符必須寫copy因為要從棧將Block拷貝到堆上
    typedef (返回引數,可為空)(^block名)(資料型別); 
    block名 引數 
    

物件導向的程式設計原則

  1. 單一職責原則(SRP): 設計一個類應該只圍繞一個主題或中心思想服務;設計一個方法應該只做好一件事情。

  2. 開閉原則(OCP): 好的軟體實體只接受擴充套件不接受修改。抽象是關鍵,用繼承結構封裝可變性(隔離程式中不同的可變因素)。

  3. 依賴倒轉原則(DIP): 要面向抽象程式設計不要面向實現程式設計。宣告指標變數的型別、方法的引數型別、方法的返回型別時儘可能使用父型別指標或協議指標(id<協議>),不要使用具體型別(子型別)指標。

愛人,待周愛人而後為愛人--- 《墨子·取周》

蛋 *x = nil;

  • (void) foo:(蛋 *) egg;
  • (蛋 *) bar;
  1. 里氏替換原則(LSP): 任何時候用子類物件替換父型別物件都是可以的,但是反過來通常是不成立的。子類能力比父類能力更多,用能力多的替換能力少的當然可以,反之未必成立。

白馬 馬也 乘白馬 乘馬也
黑馬 馬也 乘黑馬 乘馬也

娣 美人也 愛娣 非愛美人
盜 人也 惡盜 非惡人也 ---《墨子·小取》

  1. 介面隔離原則(ISP): 協議小而專,不能大而全。不能夠將不相關的方法組織到一個協議中,這樣會模糊協議所表示的角色。

  2. 合成聚合複用原則(CARP) : 優先考慮用強關聯關係複用程式碼而不是使用繼承。

IS-A --- 繼承
HAS-A --- 關聯 ---> 聚合 ---> 合成
USE-A --- 依賴

  1. 迪米特法則(LoD): 不要和陌生人講話。除非是必須發生聯絡的物件,否則不要讓物件之間發生聯絡。

邱越 - 莊 - Mr.Song - Mr.Lee - DG - Xi Jinping - 奧巴馬

小國寡民,雞犬相聞,民至老死,不相往來

XML

XML全稱eXtensible Markup Language(可擴充套件標記語言),設計用來傳輸和儲存資料。是異構系統之間交換資料的事實標準,是一種具有自我描述能力的傳輸資料的語言。
  XML文件形成的是一種樹形結構,它必須包含根元素,該元素是所有其他元素的父元素,這棵樹從根部開始,並擴充套件到樹的最低端。
   XML的語法規則

  • 所有的XML芫荽都必須有一個關閉標籤
  • XML標籤對於大小寫敏感
  • XML文件必須有根元素
  • XML屬性值必須加引號
  • XML中的特殊字元要使用實體引用
  • XML中的註釋是

解析XML資料檔案主要有兩種方式:

  1. SAX --- 順序解析 事件驅動(遇到標籤、屬性、內容都會引發相應的事件執行事件回撥來處理XML檔案中的資料)
  2. DOM (Document Object Model) --- 支援XPath查詢,可以動態的增加刪除修改節點,佔用記憶體較多

HTTP協議入門

  • 超文字傳輸協議,基於TCP協議的應用層協議
  • HTML (Hyper-Text Markup Language) 標籤語言
  • HTTP請求和響應
  • 請求格式:請求行 請求頭 訊息體
  • 響應格式:響應行 響應頭 訊息體

回撥方法(callBack)

  • SEL理解是給能夠響應的物件繫結一個方法,返回值為空。
  • 如果知道做什麼但是不知道什麼時候發生都應該用回撥方法,簡潔程式碼,發生響應。
  • oc—>selector/Block/指向函式的指標/協議委託

匿名類別(類擴充套件)

  • 通過匿名類別來宣告私有化的成員變數(也可以宣告在實現部分),前置宣告私有化的成員方法(現在私有化的成員方法可以不前置宣告),宣告私有化的屬性(比較常用)。

類別(category)

1.當我們使用蘋果第三方庫感覺這個類再有一個方法就好了,這個時候我們就可以選擇給類打一個補丁。
2.source->Objective-C File->Category->選擇要打的類別

拼接和拆分URL示例

#import <Foundation/Foundation.h>

@interface NSString (FormatURL)

// 拼接URL引數
+ (NSString *)formatURL:(NSString *) url params:(NSDictionary *) params;

// 拆分URL引數
+ (NSDictionary *)splitURL:(NSString *) url;

@end
#import "NSString+FormatURL.h"

@implementation NSString (FormatURL)

// http://chaosky.me -> http://chaosky.me?xx=xxx&xxx=xx
// http://chaosky.me?xxx=xxx -> http://chaosky.me?xxx=xxx&xxx=xx&xx=x
+ (NSString *)formatURL:(NSString *)url params:(NSDictionary *)params
{
    NSMutableArray * paramArray = [NSMutableArray array];
    // 遍歷字典
    for (NSString * key in params.allKeys) {
        NSString * paramString = [NSString stringWithFormat:@"%@=%@", key, params[key]];
        [paramArray addObject:paramString];
    }
    NSString * paramsStr = [paramArray componentsJoinedByString:@"&"];
    
    // 定義拼接好的URL地址
    NSMutableString * formatURL = [NSMutableString stringWithString:url];
    
    // 判斷當前URL地址是否已存在引數列表
    NSRange range = [url rangeOfString:@"?"];
    if (range.location != NSNotFound) {
        [formatURL appendFormat:@"&%@", paramsStr];
    }
    else {
        [formatURL appendFormat:@"?%@", paramsStr];
    }
    return formatURL;
}

+ (NSDictionary *)splitURL:(NSString *)url
{
    // 找到?位置
    NSRange paramRange = [url rangeOfString:@"?"];
    if (paramRange.location != NSNotFound) {
        // 獲取引數列表
        NSString * paramStr = [url substringFromIndex:paramRange.location + 1];
        // 按字元拆分陣列
        NSArray * paramArray = [paramStr componentsSeparatedByString:@"&"];
        // 將陣列中字串拆分
        NSMutableDictionary * paramDict = [NSMutableDictionary dictionary];
        for (NSString * param in paramArray) {
            // 將字串拆分為陣列
            NSArray * keyValue = [param componentsSeparatedByString:@"="];
            paramDict[keyValue[0]] = keyValue[1];
//            paramDict setValue:<#(nullable id)#> forKey:<#(nonnull NSString *)#>
        }
        return [paramDict copy];
    }
    else {
        return nil;
    }
}

@end

那些覺得好玩的案例

加密解密

#import <Foundation/Foundation.h>

static const int KEY = 100;     // 加密和解密使用的金鑰

int main(int argc, const char * argv[]) {
    @autoreleasepool {
//        NSString *str = @"扵牕伄"; // 加密後的字串
//        NSString *mStr = @"";
//        for (int i = 0; i < [str length]; i++) {
//            unichar ch = [str characterAtIndex:i];
//            ch = ch ^ KEY;
//            mStr = [mStr stringByAppendingFormat:@"%C", ch];
//        }
//        NSLog(@"%@", mStr);
        NSString *str = @"不再見";
        NSString *mStr = @"";
        for (int i = 0; i < [str length]; i++) {
            unichar ch = [str characterAtIndex:i];
            ch = ch ^ KEY;
            mStr = [mStr stringByAppendingFormat:@"%C",ch];
            NSLog(@"%@",mStr);
        }
        NSLog(@"%@", mStr);
    }
    return 0;
}