iOS開發200個tips總結(二)

工作了兩年多,一直有個“壞習慣”,就是將工作中遇到的一些問題、技巧或心得記在印象筆記里面,按理來說,作為一個開發者,要擁抱開源精神,將這些美好的東西分享給大家,或許能夠幫助別人解決問題或是引起少許的共鳴。

簡書給我的第一印象是:風格清新,易用,同時也*是一個不錯的交流技術,*交流心得的好平臺,趁最近在找工作的空檔,抽些時間將印象筆記里面的tips、輪子或技術解決方案移到這里來。

翻了一下印象筆記的筆記本,咋一看嚇一跳,將近一千條筆記!!! 根據80 20 法則,怎么也有200條對一部分人是有參考意義的。這里抽取200條比較有價值的筆記分享出來,希望看完博客的看官能夠有所收獲。

PS:因為有些tips是在一個swift項目中收集下來的,所以下面放出的tip既有Objective-C 也有 Swift。由于有些筆記記錄的是iOS 6.0時代的一些問題,因此可能存在一些錯誤的地方,歡迎指正。

tip 74 : UITextField leftView & rightView占位

UITextField *testField = [[UITextField? alloc] initWithFrame:CGRectMake(20, 100, 180, 30)];? ? testField.borderStyle = UITextBorderStyleRoundedRect;

//開啟左邊視圖出現模式? ? testField.leftViewMode = UITextFieldViewModeAlways;

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 40, 30)];? ? UIImage *image = [UIImage imageNamed:@"userName.png"];? ? imageView.image = image;

//設置TextField左邊視圖? ? testField.leftView = imageView;? ?

[self.view addSubview:testField];

rightView同理


tip 75 : Xcode 中輸出你想要打印的信息的命令

在Xcode 打斷點debug時控制臺中輸出面板中:

輸入:

po NSHomeDirectory() ?// 演示輸出目錄,您也可以試一試: po @“大家好”

輸出:

/Users/qianfeng/Library/Application Support/iPhone Simulator/7.0/Applications/8E889658-4D95-4499-9708-AA76D056623A


tip 76 : label設置字距

UILabel*label = [[UILabel alloc] initWithFrame:CGRectMake(0,250,750,50)];

label.backgroundColor= [UIColor greenColor];

label.font= [UIFontfontWithName:@"AppleSDGothicNeo-UltraLight"size:50];

NSAttributedString*attributedString =[[NSAttributedString alloc] initWithString:@"中國xx11"attributes:@{NSForegroundColorAttributeName: [UIColorwhiteColor] ,NSKernAttributeName:@(-8.0f)}];

[label setAttributedText:attributedString];

[self.view addSubview:label];


tip 77 : 發布上傳 Error ITMS-90046


解決辦法:

1.前往https://developer.apple.com/account/ios/identifiers/bundle/bundleList.action

2.將Associated Moains 取消 ?

以下是測試應用的設置頁面

3.重新制作證書,更新Xcode里面的證書配置

4.重新打包上傳


tip 78 : layer的繪圖是怎么執行的?

每個UIView內部都有一個Layer的屬性

要具體使用CALayer,需要引入

CALayer中使用CGColorRef和CGImageRef的數據類型,而不用UIColor和UIImage

所有的非Root Layer都存在著隱式動畫

創建一個CALayer的子類,然后覆蓋drawInContext:方法,可以使用Quartz2D API在其中進行繪圖

在實現核心動畫時,本質上是將CALayer中的內容轉換成位圖,從而便于圖形硬件的操縱


tip 79 :編譯報錯: CodeSign error: no provisioning profile at path '/Users/hz/Library/MobileDevice/Provisioning Pro

解決步驟:

1.找到文件包(先關閉項目)

2.右鍵顯示包內容

3.復制provisioning碼

4.用文本編輯器打開project.pbxproj

5.搜索碼(有兩個)

6.刪除搜到的兩個碼

7.重新打開工程編譯


tip 80 : Swift 引入的組件名稱帶 “+”?

如:組件名有+號: UITableView+FDTemplateLayoutCell

引入時:import UITableView_FDTemplateLayoutCell

將“+”好改為“_” 即可


tip 81 : Swift操作加鎖

let str ="a"

func operation(a:String){

? ? ?objc_sync_enter(a) ? // 沒有objc_asyn_xxxx

? ? print("做一些操作,在這個操作的過程中,a保持不被修改")

? ? objc_sync_exit(a)

}

// 封裝

Lock.swift

func lock(object:AnyObject, callBack:()->()){

? ? print("開始執行,加鎖!")

? ? objc_sync_enter(object)

? ? print("執行中...")

? ? callBack()

? ?objc_sync_exit(object)

? ?print("執行完畢,解鎖")

}

//實例:

// let object = "aaa"

// lock(object) { () -> () in

// ??? print("鎖住\(object)")

// }


tip 82 : Swift defer 函數完全退出時執行(常用于銷毀數據)

func resizeImage(url:NSURL) ->UIImage?{

let dataSize:Int=1234

//分配內存

let desData =UnsafeMutablePointer.alloc(dataSize)

//釋放內存程序執行完

? ? defer{ ?// 函數執行完畢才會調用

? ? ? ? ?desData.dealloc(dataSize)

? ? }

? ? returnnil

}



tip 83 :? Swift 必須是可選值的情況&不能是可選值的情況

可選:

weak修飾的是可選值

值綁定一定是可選值

聚合運算一定是可選值

不可選:

unowned修飾的不能是可選值


tip 84 :? Swift 集合類型方法 map、 flatMap、filter

map: 得到一個由閉包里面返回值組成的新序列

flatMap:與map類似,但會過濾掉返回值里面為nil值

filter:得到一個閉包返回值為true的值組成的新序列

var arr = [1,2,3,4,5]

//用法:返回序列里面對遍歷的每一個元素操作的結果序列

//結果: [2, 4, 6, 8, 10]

let result = arr.map{ $0 *2}

print(result)

//用法:在工程目錄下添加兩種圖片命名為1.png/3.png

//結果:將獲取到的nil的值過濾掉,返回[xxx/1.png, yyy/3.png]

let result1 = arr.flatMap{NSBundle.mainBundle().pathForResource("\($0)", ofType:"png")}

print(result1)

//用法:對序列里面的每個元素進行判斷返回滿足bool值的元素

//結果: [3, 4, 5]

let result2 = arr.filter({ $0 >2})

print(result2)


tip 85 :? Swift Any & AnyObject

Any : class、struct、enum

AnyObject: class ,因為所有的類都實現了AnyObject的協議方法,Object-C中的id = AnyObject?


tip 86 : swift static & class 怎么選?

static, class 可以用來修飾計算屬性和方法

適用static : enum, struct

適用class: Class, protocol


tip 87 : swift條件編譯

let btn =UIButton(type:.Custom)

btn.frame=CGRect(x:100, y:100, width:100, height:100)

self.view.addSubview(btn)

//真機x86_64、arm64

//模擬器arm、i386

#if arch(arm64)// os(OSX或iOS)

btn.backgroundColor=UIColor.greenColor()

#elseif arch(i386)

btn.backgroundColor = UIColor.redColor()

#endif


tip 88 : Swift mark 方式

// MARK:非必須?

?// TODO:必須?

?// FIXME:必須


tip 89 : Swift 類名實例化一個對象

if let Class = NSClassFromString("AYIModel").self{

? ? ? ?if let BaseModel = Class as? NSObject.Type{

? ? ? ? ? ? ?let model = BaseModel.init()

? ? ? ? ? ? ?print(model)

? ? ? ?}

}


tip 90 : 怎么個相等法?

swift == 與 === 的區別

== : 值相等

=== : 完全相等


tip 91 : ?NS 與 CF互轉

OC :

NSURL*fileURL?=?[NSURL URLWithString:@"SomeURL"];

SystemSoundID?theSoundID;

//OSStatus?AudioServicesCreateSystemSoundID(CFURLRef?inFileURL,

//? ? ? ? ? ? ? ? ? ? ? ? ? ? ?SystemSoundID?*outSystemSoundID);

OSStatus?error?=?AudioServicesCreateSystemSoundID(

(__bridgeCFURLRef)fileURL,

&theSoundID);

swift:

import AudioToolboxletfileURL = NSURL(string:"SomeURL")

var theSoundID: SystemSoundID =0

//AudioServicesCreateSystemSoundID(inFileURL:?CFURL,

//? ? ? ? _?outSystemSoundID:?UnsafeMutablePointer)?->?OSStatus

AudioServicesCreateSystemSoundID(fileURL!,?&theSoundID)


tip 92 :? pod install 還是 pod update ? (轉)

一個哥們的文章:

詳情請看:http://www.lxweimin.com/p/a977c0a03bf4


tip 93 : 播放本地 m3u8流媒體

請移步CSDN : ?http://blog.csdn.net/u010309384/article/details/49763419


tip 94 : ?Masonry 三個Block函數理解

三種Block函數

// ?(1).對view ( tag == 100)第一次約束使用該方法

-?(NSArray?*)mas_makeConstraints:(void(^)(MASConstraintMaker?*make))block;

//(2).第二次對view(tag == 100)進行約束的時候不能再用方法一,否則會報錯,要對之前添加的約束更,改的時候使用下面的方法。

特別注意,這個update是修改約束條件的值,不能修改約束對象。比如之前左邊是與view1有一個約束,現在將左邊修改為與view2約束,這樣會報錯。

-?(NSArray?*)mas_updateConstraints:(void(^)(MASConstraintMaker?*make))block;

//(3).如果想重新對view(tag == 100)約束,但是又不想用方法二,可以用下面的方法

-?(NSArray?*)mas_remakeConstraints:(void(^)(MASConstraintMaker?*make))block;


tip 95 : 破解Reveal 親測可用

Reveal一個UI審查工具,配合SB 非常好用

破解教程:

http://www.lxweimin.com/p/0cc7089143a3

reveal 一篇不錯的介紹博客:

http://blog.sina.com.cn/s/blog_adb19b690102vk8m.html


tip 96 : 源碼安裝 使用makefile

下載 linux 工具源碼放到指定目錄

第一步: cd 到源碼當前目錄

第二步: $ configure

第三步: $ make

第四步: $ sudo make install

完畢!


tip 97 : iOS 監聽電話狀態

#import <CoreTelephony/CTCallCenter.h>

#import <CoreTelephony/CTCall.h>

@interfaceAppDelegate()

@property(strong,nonatomic)CTCallCenter*callCenter;

@end

@implementationAppDelegate

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {

// Override point for customization after application launch.

_callCenter= [[CTCallCenteralloc]init];

_callCenter.callEventHandler=^(CTCall* call)

{

? ? ? ? ? ? ? ?if(call.callState==CTCallStateDisconnected)

? ? ? ? ? ? ?{

? ? ? ? ? ? ? ? ?NSLog(@"Call has been disconnected");//已經掛斷

? ? ? ? ? ?}

? ? ? ? ? ? ?else if(call.callState==CTCallStateConnected)

? ? ? ? ? {

? ? ? ? ? ? ? ?NSLog(@"Call has just been connected");//已經接通

? ? ? ? ?}

? ? ? ? else if(call.callState==CTCallStateIncoming)//有電話接入

? ? ? ?{

? ? ? ? ? ? NSLog(@"Call is incoming”);

? ? ? ? ? //self.viewController.signalStatus=NO;

? ? ? ? }

? ? ? ? else if (call.callState==CTCallStateDialing)

? ? ? {

? ? ? ? ? ? NSLog(@"call is dialing");//正在呼叫

? ? ? }

? ? ? else

? ? ? {

? ? ? ? ? ? ?NSLog(@"Nothing is done");//中斷?

? ? ? }

? ? };

return YES;

}


tip 98 : ?使用線程能夠解決什么問題 & 多線程應該注意什么

學習多線程之前需要理清的幾個問題

1. 線程同步、異步

2.隊列串行、并行

3.GCD保護資源

4.延后執行(時間可能更久)

5.鎖死問題

6.線程任務優先級

7.為線程存、取數據

8.GCD中是否需要__weak

1.GCD中線程同步、異步

創建同步線程?# 也就是阻塞代碼,等待執行完block后再繼續往下走

1-1.void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);1-2.void dispatch_sync_f(dispatch_queue_t queue, void *context, dispatch_function_t work)

創建異步線程# 方法調用之后,block“下面”的代碼繼續執行。期間,block“里面”的任務會添加到queue中等待執行,執行完任務自動退出

1-1.void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

1-2.void dispatch_async_f(dispatch_queue_t queue, void *context, dispatch_function_t work);

2.GCD串行隊列、并行隊列、主隊列

創建串行隊列的方式 # DISPATCH_QUEUE_SERIAL:串行 ,加入到GCD 串行隊列 里面的任務就會一個任務接著一個任務執行

# 串行隊列可以是sync同步也可以是異步async

dispatch_queue_t queue = dispatch_queue_create("com.liancheng.serial_queue",DISPATCH_QUEUE_SERIAL);

dispatch_queue_t queue = dispatch_queue_create("com.liancheng.serial_queue",NULL);

創建并行隊列的方式 # 自己創建 + 全局隊列

dispatch_queue_t queue = dispatch_queue_create("com.liancheng.serial_queue",DISPATCH_QUEUE_CONCURRENT);

dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags);

#identifier 可以是qos_class(系統資源服務級別)枚舉也可以是dispatch_queue_priority_t(優先級)枚舉

#創建一個默認級別的全局隊列dispatch_get_global_queue(NULL, NULL)

獲取主隊列的方式 ?#

dispatch_queue_t dispatch_get_main_queue(void)

3.GCD保護資源?dispatch_barrier

// 異步,而且隊列里面的任務,也就是blcok里面的代碼會被資源訪問的時候會被保護,其他線程不可以訪問這個資源

void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block); void dispatch_barrier_async_f(dispatch_queue_t queue, void *context, dispatch_function_t work);

// 異步,而且隊列里面的任務,也就是blcok里面的代碼會被資源訪問的時候會被保護,其他線程不可以訪問這個資源void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);void dispatch_barrier_sync_f(dispatch_queue_t queue, void *context, dispatch_function_t work);

例子:

- (void)setObject:(id)anObject forKey:(id

)aKey{? ? dispatch_barrier_async(self.concurrentQueue, ^{

// 寫操作:開始保護,等執行完任務,其他線程才可以訪問self.mutableDictionary? ? ? ? [self.mutableDictionary setObject:anObject forKey:aKey];? ? });}- (id)objectForKey:(id)aKey{? ? __block id object = nil;? ? dispatch_sync(self.concurrentQueue, ^{

// 讀操作:可以被隨時訪問,這里被同步而已? ? ? ? object = [self.mutableDictionary objectForKey:aKey];? ? });? ? return? object;}

4.延后執行

dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);

void dispatch_after_f(dispatch_time_t when, dispatch_queue_t queue, void *context, dispatch_function_t work);

dispatch_time_t =》 秒 :int64(3*NSEC_PRESEC) 即為3秒

dispatch_time_t t= DISPATCH_TIME_NOW *int64(3*NSEC_PRE_SEC) // 從現在可是計時,4秒后執行

dispatch_time_t t= DISPATCH_TIME_NOW? // 表示等同于dispatch_async,注意不能等于DISPATCH_TIME_FOREVER否則永遠死鎖線程

5.鎖死問題:造成程序出錯

# 在串行隊列中,同步執行任務,在同步任務中嵌套同步任務就會發生死鎖

dispatch_queue_t queue = dispatch_queue_create("com.liancheng.serial_queue",DISPATCH_QUEUE_SERIAL);dispatch_async(queue, ^{? ? // 到達串行隊列? ? dispatch_sync(queue, ^{? ? //發生死鎖? ? });});

6.線程任務優先級

dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags);

#identifier 可以是qos_class(系統資源服務級別)枚舉也可以是dispatch_queue_priority_t(優先級)枚舉

#創建一個默認級別的全局隊列dispatch_get_global_queue(NULL, NULL)

7.為線程存、取數據

存:

void dispatch_queue_set_specific(dispatch_queue_t queue, const void *key, void *context, dispatch_function_t destructor);

queue:需要關聯的queue,不允許傳入NULL

key:唯一的關鍵字

context:要關聯的內容,可以為NULL

destructor:釋放context的函數,當新的context被設置時,destructor會被調用

取:

void *dispatch_queue_get_specific(dispatch_queue_t queue, const void *key);void *dispatch_get_specific(const void *key);

dispatch_queue_get_specific: 根據queue和key取出context,queue參數不能傳入全局隊列

dispatch_get_specific: 根據唯一的key取出當前queue的context。如果當前queue沒有key對應的context,則去queue的target queue取,取不著返回NULL,如果對全局隊列取,也會返回NULL

8.GCD中是否需要__weak

不需要使用__weak , 因為GCD中的block屬于系統的,而我們當前的類不會持有系統的屬性,因此不會產生循環引用問題


tip 99 : MVVM的一些理解

1. MVVM 解釋:

M: ?model

V: view,viewController

VM: ViewModel

2. MVVM的理解:關系鏈

view controller : 持有 view

view : 持有 ViewModel

viewModel: 持有Model ,負責 view的邏輯實現

例子:網絡請求,刷新tableView, 點擊cell做跳轉

理解:ViewController.tableView ? ? ? ?// ViewController持有view

tableView.viewModel? ? ?? ? ? // view 持有 viewModel

tableView.viewModel.target = self ?// ViewModel 也持有 View

viewModel.models ???? ???? ???? ???? ????? ? // viewModel 持有數據 model

viewModel.requestManage ? ? ? ? // ViewModel 持有操作 model

在viewController里面添加tableView并顯示

在viewController里面viewDidLoad里面_tableView.viewModel.requestManager.requestData()

在tableView初始化方法指定代理對象

self.delegate = viewModel, self.dataSource = viewModel

self.viewModel = self

在viewModel里面實現tableView的delegate和dataSource

在viewModel里面實現網絡請求的回調,填充models,并讓tableView刷新數據

特別注意:此例子中兩個循環引用的問題

第一個:controller持有view, view持有controller

第二個:view持有viewMode, viewModel持有view

解決辦法:將 View 的 target 設置為 __weak ViewController

將 ViewModel 的 target 設置為 __weak?View


tip 100 : SB 添加約束&刪除約束的三種方式

添加約束三種方法:

1.藍色線+suggest constriant

2.右下角第二個布局按鈕

3.control+拖拽(選中自己->父視圖;選中自己->相鄰視圖;選中自己->自己?)

注意:多個控件同時分享水平空間時,注意擠壓優先級+抗擠壓優先級

刪除約束三種方法:

1.在outlayout 大綱頁面刪除

2.點擊約束線刪除

3.在右邊尺寸觀察器下面的constraint選項刪除

在autoLayout中,出現具體的數字是一個很糟糕的約束


tip 101 : 是使用png 還是 pdf 圖片資源文件呢? (轉)

http://www.zcool.com.cn/article/ZMzc3NjA4.html

http://www.th7.cn/Program/IOS/201507/500873.shtml

http://blog.csdn.net/jspandasp/article/details/49339403


先更新到 101 個tips , 以后有時間繼續更新!?

PS : 有錯的地方歡迎指正!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 背景 擔心了兩周的我終于輪到去醫院做胃鏡檢查了!去的時候我都想好了最壞的可能(胃癌),之前在網上查的癥狀都很相似。...
    Dely閱讀 9,266評論 21 42
  • 在這篇文章中,我將為你整理一下 iOS 開發中幾種多線程方案,以及其使用方法和注意事項。當然也會給出幾種多線程的案...
    張戰威ican閱讀 614評論 0 0
  • 學習多線程,轉載兩篇大神的帖子,留著以后回顧!第一篇:關于iOS多線程,你看我就夠了 第二篇:GCD使用經驗與技巧...
    John_LS閱讀 635評論 0 3
  • GCD (Grand Central Dispatch) :iOS4 開始引入,使用更加方便,程序員只需要將任務添...
    池鵬程閱讀 1,356評論 0 2
  • NSThread 第一種:通過NSThread的對象方法 NSThread *thread = [[NSThrea...
    攻城獅GG閱讀 843評論 0 3