iOS Tips(持續(xù)更新)

1、網(wǎng)絡(luò)請(qǐng)求封裝采用類方法還是單例模式?
2、extern字符串常量,宏定義字符串常量怎么選?
const常量有數(shù)據(jù)類型,而宏常量沒(méi)有數(shù)據(jù)類型。編譯器可以對(duì)前者進(jìn)行類型安全檢查,而對(duì)后者只進(jìn)行字符替換,沒(méi)有類型安全檢查,并且在字符替換時(shí)可能會(huì)產(chǎn)生意料不到的錯(cuò)誤(邊際效應(yīng))。StackOverflow鏈接

// Constants.h
FOUNDATION_EXPORT NSString *const MyFirstConstant;
FOUNDATION_EXPORT NSString *const MySecondConstant;
//etc.
(you can use extern instead of FOUNDATION_EXPORT if your code will not be used in mixed C/C++ environments or on other platforms)

You can include this file in each file that uses the constants or in the pre-compiled header for the project.

You define these constants in a .m file like
// Constants.m
NSString *const MyFirstConstant = @"FirstConstant";
NSString *const MySecondConstant = @"SecondConstant";
Constants.m should be added to your application/framework's target so that it is linked in to the final product.

The advantage of using string constants instead of #define'd constants is that you can test for equality using pointer comparison (stringInstance == MyFirstConstant) which is much faster than string comparison ([stringInstance isEqualToString:MyFirstConstant]) (and easier to read, IMO).

3、文本添加超鏈接

NSAttributedString *linkStr = [[NSAttributedString alloc] initWithString:tagName attributes:@{NSLinkAttributeName: urlStr}];
[attributeString replaceCharactersInRange:range withAttributedString:linkStr];
[attributeString addAttribute:NSLinkAttributeName value:urlStr range:NSMakeRange(0, linkStr.length)];

4、YYModel使用
+ (NSDictionary *)modelCustomPropertyMapper {
return @{@"messageId":@"i",
@"content":@"c",
@"time":@"t"};
}
- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic {
uint64_t timestamp = [dic unsignedLongLongValueForKey:@"t" default:0];
self.time = [NSDate dateWithTimeIntervalSince1970:timestamp / 1000.0];
return YES;
}
5、Copy與MutableCopy

對(duì)于非集合對(duì)象
copy:因?yàn)閏opy默認(rèn)返回的是不可變的,所以當(dāng)我們對(duì)一個(gè)不可變的字符串進(jìn)行copy的時(shí)候,我們只是拷貝了它的指針(淺拷貝)。當(dāng)我們對(duì)一個(gè)可變的字符串進(jìn)行拷貝的時(shí)候,因?yàn)轭愋娃D(zhuǎn)變了,我們需對(duì)其進(jìn)行深拷貝。
mutableCopy:默認(rèn)返回的是一個(gè)可變的對(duì)象,適用于可變的對(duì)象,例如NSMutableString,NSMutableArray,NSMutableDictionary、etc。  無(wú)論對(duì)于可變的字符串還是不可變的字符串進(jìn)行mutableCopy,系統(tǒng)都默認(rèn)進(jìn)行深拷貝,那么為什么對(duì)于相同類型的進(jìn)行mutableCopy返回的仍然是新的對(duì)象呢,因?yàn)樵谶@里系統(tǒng)要保證,舊的對(duì)象和新的對(duì)象都是可變的,且他們之前不會(huì)相互影響。

對(duì)于集合對(duì)象
對(duì)于不可變的集合對(duì)象,copy 是淺拷貝,mutableCopy 是單層深拷貝。
對(duì)于可變的集合對(duì)象,無(wú)論 copy 或者 mutableCopy 都是單層深拷貝。

6、通過(guò)圖片Data數(shù)據(jù)第一個(gè)字節(jié) 來(lái)獲取圖片擴(kuò)展名

- (NSString *)contentTypeForImageData:(NSData *)data {
    uint8_t c;
    [data getBytes:&c length:1];
    switch (c)
    {
        case 0xFF:
            return @"jpeg";
 
        case 0x89:
            return @"png";
 
        case 0x47:
            return @"gif";
 
        case 0x49:
        case 0x4D:
            return @"tiff";
 
        case 0x52:
        if ([data length] < 12) {
            return nil;
        }
 
        NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
        if ([testString hasPrefix:@"RIFF"]
            && [testString hasSuffix:@"WEBP"])
        {
            return @"webp";
        }
 
        return nil;
    }
 
    return nil;
}

7、GET、POST請(qǐng)求

GET
在請(qǐng)求URL后面以?的形式跟上發(fā)給服務(wù)器的參數(shù),多個(gè)參數(shù)之間用&隔開(kāi),比如http://ww.test.com/login?username=123&pwd=234&type=JSON
注意:由于瀏覽器和服務(wù)器對(duì)URL長(zhǎng)度有限制,因此在URL后面附帶的參數(shù)是有限制的,通常不能超過(guò)1KB

POST
發(fā)給服務(wù)器的參數(shù)全部放在請(qǐng)求體中
理論上,POST傳遞的數(shù)據(jù)量沒(méi)有限制(具體還得看服務(wù)器的處理能力)

選擇GET和POST的建議
(1)如果要傳遞大量數(shù)據(jù),比如文件上傳,只能用POST請(qǐng)求
(2)GET的安全性比POST要差些,如果包含機(jī)密\敏感信息,建議用POST
(3)如果僅僅是索取數(shù)據(jù)(數(shù)據(jù)查詢),建議使用GET
(4)如果是增加、修改、刪除數(shù)據(jù),建議使用POST

8、圖片的縮放

原圖為200*100,放在100*100的imageView上
// 改變內(nèi)容的高寬比例,縮放內(nèi)容,UIView中完整顯示內(nèi)容,填滿UIView 
   case scaleToFill
// 保持內(nèi)容的高寬比,縮放內(nèi)容,完整顯示內(nèi)容,最大化填充UIview,沒(méi)填充上的區(qū)域透明
   case scaleAspectFit 
// 保持內(nèi)容高寬比,縮放內(nèi)容,超出視圖的部分內(nèi)容會(huì)被裁減,填充UIView
    case scaleAspectFill

9、防止離屏渲染,為image添加圓角

// image分類
- (UIImage *)circleImage
{
  // NO代表透明
  UIGraphicsBeginImageContextWithOptions(self.size, NO, 1);
  // 獲得上下文
  CGContextRef ctx = UIGraphicsGetCurrentContext();
  // 添加一個(gè)圓
  CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
  // 方形變圓形
  CGContextAddEllipseInRect(ctx, rect);
  // 裁剪
  CGContextClip(ctx);
  // 將圖片畫上去
  [self drawInRect:rect];
  UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  return image;
}

10、鍵盤上方增加工作欄

UIToolbar *keyboardDoneButtonView = [[UIToolbar alloc] init];
[keyboardDoneButtonView sizeToFit];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done"
                                                                   style:UIBarButtonItemStyleBordered target:self
                                                                  action:@selector(doneClicked:)];
[keyboardDoneButtonView setItems:[NSArray arrayWithObjects:doneButton, nil]];
txtField.inputAccessoryView = keyboardDoneButtonView;

11、將一個(gè)View保存成PDF
- (void)createPDFfromUIView:(UIView)aView saveToDocumentsWithFileName:(NSString)aFilename
{
NSMutableData *pdfData = [NSMutableData data];
UIGraphicsBeginPDFContextToData(pdfData, aView.bounds, nil);
UIGraphicsBeginPDFPage();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
[aView.layer renderInContext:pdfContext];
UIGraphicsEndPDFContext();

    NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
    NSString* documentDirectory = [documentDirectories objectAtIndex:0];
    NSString* documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent:aFilename];
    [pdfData writeToFile:documentDirectoryFilename atomically:YES];
    NSLog(@"documentDirectoryFileName: %@",documentDirectoryFilename);
}

12、weak關(guān)鍵詞的使用
weak 的用處用一句話可歸納為:弱引用,在對(duì)象釋放后置為 nil,避免錯(cuò)誤的內(nèi)存訪問(wèn)。用更通俗的話來(lái)表述是:weak 可以在不增加對(duì)象的引用計(jì)數(shù)的同時(shí),又使得指針的訪問(wèn)是安全的。
13、 @IBOutlet 的 didSet
如果我們由于某種原因,確實(shí)需要在代碼中設(shè)置一些 view 的屬性,在連接 @IBOutlet 后,不少開(kāi)發(fā)者會(huì)選擇在 viewDidLoad 中進(jìn)行設(shè)置。其實(shí)個(gè)人認(rèn)為一個(gè)更合適的地方是在該 @IBoutlet 的 didSet 中進(jìn)行。@IBoutlet 所修飾的也是一個(gè)屬性,這個(gè)關(guān)鍵詞所做的僅只是將屬性暴露給 IB,所以它的各種屬性觀察方法 (willSet,didSet 等) 也會(huì)被正常調(diào)用。比如,下面我們實(shí)際項(xiàng)目中的一段代碼:

@IBOutlet var myTextField: UITextField! {
    didSet {
        // Workaround for https://openradar.appspot.com/28751703
        myTextField.layer.borderWidth = 1.0
        myTextField.layer.borderColor = UIColor.lineGreen.cgColor
    }
}

14、Swift進(jìn)階

1、Swift風(fēng)格指南

對(duì)于命名,在使用時(shí)能清晰表意是最重要。因?yàn)?API 被使用的次數(shù)要遠(yuǎn)遠(yuǎn)多于被聲明的次數(shù),所以我們應(yīng)當(dāng)從使用者的角度來(lái)考慮它們的名字。盡快熟悉 Swift API 設(shè)計(jì)準(zhǔn)則,并且在你自己的代碼中堅(jiān)持使用這些準(zhǔn)則。

簡(jiǎn)潔經(jīng)常有助于代碼清晰,但是簡(jiǎn)潔本身不應(yīng)該獨(dú)自成為我們編碼的目標(biāo)。

務(wù)必為函數(shù)添加文檔注釋 — 特別是泛型函數(shù)。

類型使用大寫字母開(kāi)頭,函數(shù)、變量和枚舉成員使用小寫字母開(kāi)頭,兩者都使用駝峰式命名法。

使用類型推斷。省略掉顯而易見(jiàn)的類型會(huì)有助于提高可讀性。

如果存在歧義或者在進(jìn)行定義的時(shí)候不要使用類型推斷。(比如 func 就需要顯式地指定返回類型)

優(yōu)先選擇結(jié)構(gòu)體,只在確實(shí)需要使用到類特有的特性或者是引用語(yǔ)義時(shí)才使用類。

除非你的設(shè)計(jì)就是希望某個(gè)類被繼承使用,否則都應(yīng)該將它們標(biāo)記為 final。

除非一個(gè)閉包后面立即跟隨有左括號(hào),否則都應(yīng)該使用尾隨閉包 (trailing closure) 的語(yǔ)法。

使用 guard 來(lái)提早退出方法。

避免對(duì)可選值進(jìn)行強(qiáng)制解包和隱式強(qiáng)制解包。它們偶爾有用,但是經(jīng)常需要使用它們的話往往意味著有其他不妥的地方。

不要寫重復(fù)的代碼。如果你發(fā)現(xiàn)你寫了好幾次類似的代碼片段的話,試著將它們提取到一個(gè)函數(shù)里,并且考慮將這個(gè)函數(shù)轉(zhuǎn)化為協(xié)議擴(kuò)展的可能性。

試著去使用 map 和 reduce,但這不是強(qiáng)制的。當(dāng)合適的時(shí)候,使用 for 循環(huán)也無(wú)可厚非。高階函數(shù)的意義是讓代碼可讀性更高。但是如果使用 reduce 的場(chǎng)景難以理解的話,強(qiáng)行使用往往事與愿違,這種時(shí)候簡(jiǎn)單的 for 循環(huán)可能會(huì)更清晰。

試著去使用不可變值:除非你需要改變某個(gè)值,否則都應(yīng)該使用 let 來(lái)聲明變量。不過(guò)如果能讓代碼更加清晰高效的話,也可以選擇使用可變的版本。用函數(shù)將可變的部分封裝起來(lái),可以把它帶來(lái)的副作用進(jìn)行隔離。

Swift 的泛型可能會(huì)導(dǎo)致非常長(zhǎng)的函數(shù)簽名。壞消息是我們現(xiàn)在除了將函數(shù)聲明強(qiáng)制寫成幾行以外,對(duì)此并沒(méi)有什么好辦法。我們會(huì)在示例代碼中在這點(diǎn)上保持一貫性,這樣你能看到我們是如何處理這個(gè)問(wèn)題的。

除非你確實(shí)需要,否則不要使用 self.。在閉包表達(dá)式中,使用 self 是一個(gè)清晰的信號(hào),表明閉包將會(huì)捕獲 self。

盡可能地對(duì)現(xiàn)有的類型和協(xié)議進(jìn)行擴(kuò)展,而不是寫一些全局函數(shù)。這有助于提高可讀性,讓別人更容易發(fā)現(xiàn)你的代碼。

2、數(shù)組

想要迭代數(shù)組? for x in array

想要迭代除了第一個(gè)元素以外的數(shù)組其余部分? for x in array.dropFirst()

想要迭代除了最后 5 個(gè)元素以外的數(shù)組? for x in array.dropLast(5)

想要列舉數(shù)組中的元素和對(duì)應(yīng)的下標(biāo)? for (num, element) in collection.enumerated()

想要尋找一個(gè)指定元素的位置? if let idx = array.index { someMatchingLogic($0) }

想要對(duì)數(shù)組中的所有元素進(jìn)行變形? array.map { someTransformation($0) }

想要篩選出符合某個(gè)標(biāo)準(zhǔn)的元素? array.filter { someCriteria($0) }

函數(shù)的使用
map 和 flatMap — 如何對(duì)元素進(jìn)行變換

filter — 元素是否應(yīng)該被包含在結(jié)果中

reduce — 如何將元素合并到一個(gè)總和的值中

sequence — 序列中下一個(gè)元素應(yīng)該是什么?

forEach — 對(duì)于一個(gè)元素,應(yīng)該執(zhí)行怎樣的操作

sort,lexicographicCompare 和 partition — 兩個(gè)元素應(yīng)該以怎樣的順序進(jìn)行排列

index,first 和 contains — 元素是否符合某個(gè)條件

min 和 max — 兩個(gè)元素中的最小/最大值是哪個(gè)

elementsEqual 和 starts — 兩個(gè)元素是否相等

split — 這個(gè)元素是否是一個(gè)分割符

Range
只有半開(kāi)范圍能夠表達(dá)空區(qū)間的概念 (當(dāng)范圍的上下邊界相等時(shí),比如 5..<5)。

只有閉合范圍能夠包含它的元素類型所能表達(dá)的最大值 (比如 0...Int.max)。半開(kāi)范圍總是最少會(huì)有一個(gè)值比范圍所表達(dá)的只要大。

函數(shù):
函數(shù)可以像 Int 或者 String 那樣被賦值給變量,也可以作為另一個(gè)函數(shù)的輸入?yún)?shù),或者另一個(gè)函數(shù)的返回值來(lái)使用。

函數(shù)能夠捕獲存在于其局部作用域之外的變量。

有兩種方法可以創(chuàng)建函數(shù),一種是使用 func 關(guān)鍵字,另一種是 { }。在 Swift 中,后一種被稱為閉包表達(dá)式。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,716評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 178,746評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 63,991評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,706評(píng)論 6 413
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 56,036評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 43,203評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,725評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,451評(píng)論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,677評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,857評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 35,266評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 36,606評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,407評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,643評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容