工作了兩年多,一直有個“壞習慣”,就是將工作中遇到的一些問題、技巧或心得記在印象筆記里面,按理來說,作為一個開發者,要擁抱開源精神,將這些美好的東西分享給大家,或許能夠幫助別人解決問題或是引起少許的共鳴。
簡書給我的第一印象是:風格清新,易用,同時也*是一個不錯的交流技術,*交流心得的好平臺,趁最近在找工作的空檔,抽些時間將印象筆記里面的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 ? (轉)
一個哥們的文章:
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 一篇不錯的介紹博客:
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 : 有錯的地方歡迎指正!