工作了两年多,一直有个“坏习惯”,就是将工作中遇到的一些问题、技巧或心得记在印象笔记里面,按理来说,作为一个开发者,要拥抱开源精神,将这些美好的东西分享给大家,或许能够帮助别人解决问题或是引起少许的共鸣。
简书给我的第一印象是:风格清新,易用,同时也*是一个不错的交流技术,*交流心得的好平台,趁最近在找工作的空档,抽些时间将印象笔记里面的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.jianshu.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 : 有错的地方欢迎指正!