延续上一篇iOS |知识点整理(10)
mqtt ios client facebook的通讯库
项目通用库:
1.照片多选,选择多张,删除,添加,从摄像头添加
2.日期选择,日期限制
3.图片单张选择上传[ OK ]
4.下方弹出模块.[ OK ]
5.autolayout宏.[ OK ]
6.UINavigationController下拉菜单.
7.UITableViewCell自适应大小的总结.
8.用户帐户信息管理通用,如:登陆,加载,退出
9.fmdb通用信息管理.
10.先抽象出公共组件.
11.表格无数据时的弹出显示[ OK ].
12.扩展点击区域通用
13.xib容器通用.[ OK ]
14.数字tint通用.[ OK ]
15.健康资讯页面.
16.单页面视图UITextView高度自适应,键盘自适应.
17.单张照片查看视图,放大,缩小.
15.iBeacon、Socket、ffmpeg
16.工种添加其它target.
17.ios与html页面的混合编程
18.键盘加dismiss附加view.[OK]
19.饼状图
20.使用coretext实现相关的点击式链接等富文本
21.AVFoundation的用法
22.Loading页面[ OK ]
23.自适应textview[ OK ]
24.Xib模板,特别是针对于UITableviewcell的
25.UINavigationController的顶部下拉菜单
26.关于CAShapeLayer与UIBezierPath的坐标系统.
27.当推送到来之后,需要弹出一个页面,那么,如果当前有alertview,或者是其它弹出的窗口,那该怎么办??
28.IOS8中的autolayout的margin以及autolayout name的用法.
29.指纹支付,3Dtouch
30.对于多lable cell自适应的能用库
31.core location prgramming guide
32.core text/UITextKit
33.条型码以及二维码扫描[OK]
34.instruments的使用
35.UINotification在多线程中的使用.
36.新版objectiveC的用法.
37.graphicZ的应用.[ OK ]
38.CorePlot的使用
39.cell大小的自适应计算.sunny的能用库
40.IOS7中的后台任务
41.在任意时间点,强制退出登陆时,如果遇到alert窗口怎么办?
42.相机特效
43.ffmpeg
44.KVO中的一对多demo的编写
45.常用的通用库,提高效率
46.将那几篇关于动画的英文博客给保存下来. [ OK ]
47.蓝牙的descriptor
48.healthKit
49.时间日期函数
50.小米手环的下拉菜单效果
51.分享页面,如果不能分享,则其图标是灰色的,是app
52.小米手环的地图mask效果 [ OK ]
53.GCDTimer的用法.
54.圆块自动分配百分比 [ OK ]
55.仿写一下https://github.com/Wzxhaha/WZXTextfieldAnimation [ OK ]
56.Pop动画库效果
57.UIView addKeyframeWithRelativeStartTime用法
58.ios7程序后台运行
59.spotlight
60.写图片缓存类,缓存策略之类的
61.CoreGraphics中的蒙版的用法
62.仿建行旋转菜单
63.算法加强. hashTable,二叉树,双向链表等.
64.离屏渲染是怎样缓存结果的,怎么样才能把这个缓存的结果重复利用起来.
65.IOS CI方面,以及xcode自动打包上传等等.
66.故事板以及子故事板的用法
67.UICollectionView动画
68.ComponentKit的用法
69.gif图片的显示
70.Carthage
71.日历中添加一个可自定义标记的功能.比如显示哪天可以预约.
72.CATransaction
73.UINavigationController的几个关键属性.
74.IOS版本及机器型号相关的宏
75.唐巧的那个NSUserDefault替代
76.二维码生成及扫描.
78.支付宝生活圈的动画效果.
79.PJSIP 和 webRTC 实时视频通话.
80.AFNetWork低版本的源代码
81.size class
82.UINavgigationController
83.Binary search tree
84.摇一摇
1.总结一下常用的代码库
2.封装一下常用的代码,比如封闭一下UITableView,那几个常用的功能.
3.封装一下常用约束的宏.以及分类. 可以参考一下:
https://github.com/smileyborg/PureLayout
4.对于不显示的可滚动区域,要闪动一下scrollbar;
5.如果在小屏幕的机器上,可能会挡住一些按钮什么的,最好,判断一下,滚动.
6.封装一下欢迎页.
7.自定义timingfunction
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
8.一米鲜的拉动放大效果.
常用框架:
1.Loading及提示框架
2.http请求
3.本地缓存
4.日期uitls 颜色[OK]
5.测试,边写边测试
6.注意,初始化设置,与用属性设置的区别
7.故事板的使用,以及子故事板的使用
8.didmovetoviewcontroller
uibuttonitem
placeholder的处理[OK]
uitextview键盘自适应以及高度自适应.[OK]
uicollectionview的总结
uicollectionview cell中的条目摇动效果
键盘处理.[OK]
xib布局如何提高效率
常用布局的代码书写
声音转换播放库
日历组件用绘图功能重写[OK]
基本缓存功能,存文件.
NSURL *url = [NSURL fileURLWithPath:(NSString *)path];
WhuSliderView 惰性加载vc[OK]
全局数据请求
常用宏
照片添加编辑页面
日期选择,时间选择[OK]
关于一些与项目相关的常量,数组什么的,存放在哪里?
NSattribute string常用属性
墨迹上的时钟摆动小动画
自定义图片浏览器
图片选择器.[OK]
增删改对原列表影响的通知方法.
统一的imageview loading
background fetch
remote notification
一些常用布局的整理.包括相应xib,调用代码.
addChildViewController的用法总结.
蓝牙模块的完善
基类中要包含需求登陆,以及登陆之后的跳转行为,被强制退出了,怎么办?
常用tableviewCell的代码
收集常用的组件及示例代码
完善基类
常用宏,Utils[OK]
上下拉刷新的集成.
地址选择[OK]
用reactiveCocoa重写一下验证码模块[OK]
根据whupopview生成一个向上滑动的view
常用的xib及对应的代码模板
注册,登陆,修改密码,帮助与反馈功能的模板,设置模块
web cache
地理位置能用[OK]
文件缓存类的编写
约束更简便的写法.
流式布局,通用.
二维码扫描[OK]
WHUSliderView支持lazy load,重新发布.[OK]
EventKit实现事件的提醒
UIViewController切换动画
ffmpeg+
App Extension编程
升级一下WHUCalendarView[OK]
程序刚一安装时的功能介绍页面 [OK]
关于coretxt曲线路径时的绘制 [OK]
python中列表,字典的所有方法
添加多个提醒的实现,超过local notification的个数限制
Expand TableCell [OK]
用药提醒 [数量限制不能超过64个]
子故事板及故事板的运用
测试IOS7的background task
HTTP协议的理解
Linux中的管道
自适应高度 uitextview,在UITableview中的自适应高度
searchViewcontroller的用法.
UINavigationBar的颜色管理
bitcode编译的相关知识
在UITableViewCell中使用UITextView相关的高度及键盘自适应. 或者在弹出的键盘中显示编辑界面.
BDMessagesKeyboardController的frame设置使用方法.
xcode的interfaceBuilder中所有的控件的用法,都了解嘛?
找到一个在UITablView内嵌UITextView的内容输入方法. 比如消息输入的方案等
多行文本的地址微调
三行文本的自适应布局
set和array
用AFN3.0下载文件,在下载过程中,kill app,下次进来继续下载,不是接着后面下载,是重0开始,知道怎么弄?
EGOCache YYCache
NSUrlSession
页面使用指引的写法,像钉钉那样的. UINavigationController header的全面控制.
UDID的替代方案
websocket
NSURLSessionDownloadTask 这个下载 我下载一半后,暂停 然后重启APP怎么让他继续下载?
整个app的颜色管理,可以通过宏,或者是一个单独的类来管理
NSURLSession
YYWebImage
NSOperation的用法,包括DownloadManager,AFDownloadRequestOperation,zhihu-Daily,Advanced Operations
预编译头的使用
swift与objective C的差别
webRtc singaling server
由小到大的滑动变化,类似医联云健康中的居民卡
树的先序遍历
阿里支付的编写
VIPER模式
RN中的view默认排版方式,在不指定flex的情况下,它是如何排版的?
Swift中标准库中的结构体,是如何处理效率问题的?
alignmentRectInsets http://www.electricpeelsoftware.com/2013/05/08/custom-views-with-auto-layout.html
UICollectionViewLayoutAttributes *attributes = [self.collectionView.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath]; 是不是只返回可见的cell
AF缓存管理
KeyChain
将自己整理的tip中的代码转换成code snippet
storyboard的全部用法.
SearchViewController的用法
github.com/tiger8888/M… 图片浏览器,放大,缩小等. download.csdn.net/download/l8…
www.code4app.com/ios/Image-C… image crop
UIViewController的持久化,是否能方便的取得到.
应该有个basedata方便传递数据
二进制数据的处理,比如用户的头像
从登陆界面登陆与默认直接登陆接口方面的区别.
如果功能模块需要登陆,那么怎么样以一种更好的方式来处理需要通用的这类登陆功能.
对于loadingView,有的功能需要整个窗口的mask,而有的功能,只需要其功能页面的mask.
开发版应用中获取的deviceToken和发布版中应用中获取的deviceToken是不一样的.
对于医联云健康来说,可以使用charles工具在程序启动时候,获取发布版的deviceToken
APP的整体架构能力.
TODO:
1.demo的分类
2.整理相关概念及codesnippt
IOS https的用法. 开发版的机器deviceToken:
dwarfdump –lookup 0x000d67f0 –arch armv7 armv7s xxx.app.dSYM
"Prior to iOS 7, the device token was the same across all app installations on a given device. Different apps on your phone, whether Tap Tap Revenge or USA Today, would utilize the same address, i.e., device token, to route the push notification to you. The security credentials that you pair with a message would ensure it made it to the right app. On iOS 7, Apple has gone one step further and made sure that device tokens are now different in every single app install. This helps further protect users’ privacy by removing another phone-level identifier."
ref:stackoverflow.com/questions/1…
__block的retain情况
__IPHONE_8_0的用法.
自定义手势roybaby.blog.51cto.com/1508945/157…
AFNetWorking的超时操作.
手势解锁.
动态背景.
本地数据库是不是应该放在登陆之前建立还是在登陆之后建立.
使用cocopods来管理自己项目的依赖.
json的大小写解析
图片加载,在4s机器上,如果2x没有的话,会加载3x
统一的viewcontroller压栈出栈管理,的
在viewWillAppear的时候,autolayout的大小是不是已经确定
urlencode的问题
NSorderset set
NSValueTransformer
NSAttribueString与Lable的用法.
UIBezierPath.lineWidth和CAShaper的lineWidth的区别
NSOperation的用法
测试一下状态栏随着控制器变色
网络重新连网时的处理.
使用Cycript修改支付宝app运行时
UITableView所有的api
coredata
@interface NSObject (CAAnimationDelegate)
/* Called when the animation begins its active duration. */
- (void)animationDidStart:(CAAnimation *)anim;
/* Called when the animation either completes its active duration or
* is removed from the object it is attached to (i.e. the layer). 'flag'
* is true if the animation reached the end of its active duration
* without being removed. */
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
@end
百度地图的总结
[[NSRunLoop currentRunLoop] run] 和那个 beforedate方法,一个不在循环中调用,一个在循环中调用.为什么???
swift
viewDidLayoutSubviews
字体管理
使用UUID + keychain 可以变相防止 UUID在app卸载后重新生成 keychain可以脱离app本身 达到系统级存储
推送中苹果手机的设置和自己app设置的关系.
对于加载等待的控制.
当出现询问是否打开推送的时候,那么主线程是暂停住了,还是继续往下执行呢?
openUDID在什么情况下发生改变? kensou.blog.51cto.com/3495587/124…
在消息列表中,那个删除,往左滑动时删除二字显示不全
xcrun的用法. leancodingnow.com/xcode-6-sim…
json结构的可变化性.
约束怎么调试.
code sign identifier
what is the team in Xcode
conclusion of remote push
贝塞尔曲线的用法.
在一个UISCrollView的滚动界面中,怎么做到滚动到最左边的时候,开始调用返回手势动画.
ios7的新特性 backgroundTask
对NSMutableArray做KVO
RACSignal leeway的用法
总结下sampler的用法
静态库的编译
-(CGSize)intrinsicContentSize 与 sizeThatFits
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
和
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]
请问他们有什么区别?
Baseline Alignment
QCSwitch
expandTableView
不使用默认命名
图像资源Images Assets
http://www.cnblogs.com/liufan9/p/3136064.html
uiscrollview bounce
is initially hidden
在viewdidload设置自己的frame,无效
xcode中的那些界面配置
tag是不是可以重复的
rac_sequence的用法
assert的用法 NSAssert
NSAssert(NO, @"子类需要实现此方法");
tableview中的section是从零开始的,还是从1开始的 stackoverflow.com/questions/2…
已安装的机器,模拟新机器第一次安装: 1.先删除app 2.按住HOME+开机键 15秒,强制重启 3.将系统时间往后调1天. 4.按住HOME+开机键 15秒,强制重启 5.重新安装app
UIView catgory
findallview
getviewheight
shake animation
autolay out中的相关方法
-(UIView*)findViewByTag:(UIView*)conv withTag:(NSInteger)t{
for(UIView* v in conv.subviews){
if([v viewWithTag:t]!=nil)
return [v viewWithTag:t];
else{
return [self findViewByTag:v withTag:t];
}
}
return nil;
}
#ifndef DEBUG
#define NSLog(...)
#endif
UIViewController和AppDelegate的生命周期
UITableViewCell中的按钮点击, user interaction enabled -> false
UIButton在addTarget的情况下,才会有highlighted状态,才会有selected状态.
NSArray *newArray = [[NSArray alloc] initWithArray:oldArray copyItems:YES];
[newArray makeObjectsPerformSelector:@selector(doSomethingToObject) withObject:object];//object为BOOL类型无效?
Nib must contain exactly one top level object which must be a UITableViewCell instance
在nib中添加手势action,在UITableViewcell复用的时候,出现了上面的错误.
静态表格的用法 [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:view.superview attribute:NSLayoutAttributeCenterX multiplier:1.f constant:0.f];
file url 和 链接的区别
if([type isEqualToString:@"url"]){
data= [NSData dataWithContentsOfURL:[NSURL URLWithString:songUrl]];
}
else if([type isEqualToString:@"file"]){
data= [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:songUrl]];
}
表格中的图片异步加载,如果用户滚动的话,会出现在错误的地方的处理.
python中的mantle生成器要加上这些:
- (void)setNilValueForKey:(NSString *)key {
[self setValue:@0 forKey:key]; // For NSInteger/CGFloat/BOOL
}
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:path relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil];
request.timeoutInterval =15;
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
UINavigateController全局风格的设定
String *pattern = @"\\[pic:([^\\s:\\]]+):([^\\]]+)\\]";
NSString *str = @"bla bla [pic:brand:123] bla bla";
NSLog(@"Original test: %@",str);
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:pattern
options:NSRegularExpressionCaseInsensitive error:&error];
if(error != nil){
NSLog(@"ERror: %@",error);
} else{
NSString *replaced = [regex stringByReplacingMatchesInString:str
options:0
range:NSMakeRange(0, [str length])
withTemplate:[NSString stringWithFormat:@"/%@/photo/%@.gif",
@"IMAGE_BASE_URL", @"$1/$2"]];
NSLog(@"Replaced test: %@",replaced);
}
produces the output
Original test: bla bla [pic:brand:123] bla bla
Replaced test: bla bla /IMAGE_BASE_URL/photo/brand/123.gif bla bla
stackoverflow.com/questions/5…
Which thread does the block in dispatch_once run in? t runs in the current/calling thread.
This NSLayoutConstraint is being configured with a constant that exceeds internal limits. A smaller value will be substituted, but this problem should be fixed. Break on void _NSLayoutConstraintNumberExceedsLimit() to debug. This will be logged only once. This may break in the future.
解决方法:
(lldb) br s -n _NSLayoutConstraintNumberExceedsLimit
Breakpoint 2: where = Foundation`_NSLayoutConstraintNumberExceedsLimit, address = 0x00007fff9168e6f5
ref: stackoverflow.com/questions/2…
Xcode调试-获取APP中当前页面所对应的controller 可以设置符号断点,viewDidLoad.
cornetStone分支的用法:
1.在你当前svn的父目录上,选定该svn,然后点击branch,然后选择你要创建分支的地址,一般是在服务器上分配的一个专门的存放地址.
IOS静态库常用命令
//合并静态库,做个通用的,支持模拟器和真机
lipo -create -output lib.a lib-armv6.a lib-i386.a
//查看静态库支持什么架构
lipo -info lib.a
//若只要指定架构的库,可以从通用库中加压除指定的
lipo -extract_family armv7 -output lib-armv7.a lib.a
如果我们同时在界面上滚动一个scrollview,那么我们会发现在滚动停止之前,控制台是不会有输出的,就好像scrollView在滚动的时候将timer暂停了一样。通过了解后发现,其实是Cocoa的RunLoop Mode在作怪。
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
NSTimer *timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(myTimerAction:) userInfo:nil repeats:YES];
[runloop addTimer:timer forMode:NSRunLoopCommonModes];
定义:NSRunLoopCommonModes (Cocoa) kCFRunLoopCommonModes (Core Foundation)
描述:这是一个伪模式,其为一组run loop mode的集合,将输入源加入此模式意味着在Common Modes中包含的所有模式下都可以处理。
在Cocoa应用程序中,默认情况下Common Modes包含default modes,modal modes,event Tracking modes.
响应链
大多数事件的分发都是依赖响应链的。响应链是由一系列链接在一起的响应者组成的。一般情况下,一条响应链开始于第一响应者,结束于application对象。如果一个响应者不能处理事件,则会将事件沿着响应链传到下一响应者。
那这里就会有三个问题: 响应链是何时构建的 系统是如何确定第一响应者的 确定第一响应者后,系统又是按照什么样的顺序来传递事件的
ref: southpeak.github.io/blog/2015/0…
####UINavigationController and the iOS 7 Status Bar
如果你的viewController是在UINavigationController里面,且当.plist文件里的 UIViewControllerBasedStatusBarAppearance 设置为YES时,那么UINavigationBar会决定你status bar的外观. 但是当你设置隐藏UINavigationBar时,它就不起作用了. If your app uses a UINavigationController with every view, then, as far as the status bar is concerned, there will be little for you to worry about when developing for or transitioning to iOS 7. When a UINavigationController is present, the UINavigationBar will automatically be placed below the status bar (the standard 20 point offset from the top of the screen that we are accustomed to from previous iOS versions). The background of the status bar will be modified to match the UINavigationBar below it.
The status bar will inherit the color and transparency of the UINavigationBar.Additionally, the color of the text and content in the status bar will be adjusted based on the UIBarStyle (UIBarStyleDefault or UIBarStyleBlack) of the UINavigationBar below it.In this case, the only way to make changes in how the status bar looks is to make changes to the UINavigationBar.
UIViewControllerBasedStatusBarAppearance的实际作用如下:
这个属性只影响如何设置status bar上字体的颜色是黑色还是白色,对status bar的背景色无影响。status bar的背景色在iOS7上永远是透明的。
UIViewControllerBasedStatusBarAppearance = NO时:
UIApplication 的setStatusBarStyle方法生效:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
viewController的preferredStatusBarStyle方法无效:
- (UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
UIViewControllerBasedStatusBarAppearance = YES时:
UIApplication 的setStatusBarStyle无效。
UINavigationviewController的preferredStatusBarStyle方法有效。 准确的说,应该是第一个加载的viewController的preferredStatusBarStyle的方法有效
discovered that if your ViewController is inside a navigationController then the navigationController’s navigationBar.barStyle determines the statusBarStyle.
Setting your navigationBar’s barStyle to UIBarStyleBlackTranslucent will give white status bar text (ie. UIStatusBarStyleLightContent), and UIBarStyleDefault will give black status bar text (ie. UIStatusBarStyleDefault).
Note that this applies even if you totally change the navigationBar’s color via its barTintColor.
修改navigationbar的颜色:
View controller-based status bar appearance =NO 这个设置为:View Controller 不对status Bar 显示进行操作
然后在viewcontroller里面修改navigationbar的颜色
[[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed:65/255.0 green:159/255.0 blue:252/255.0 alpha:0.5]];
官方给出的意思
To customize the appearance of all instances of a class, send the relevant appearance modification messages to the appearance proxy for the class.(自定义的一个类的所有实例的外观,发送相关信息到外观的外观的代理类)For example, to modify the bar tint color for all UINavigationBar instances:
[[UINavigationBar appearance] setBarTintColor:myColor];
evernote:///view/555639/s7/89dac1af-a4c6-4c4f-8a76-3c6c2f1a0af4/89dac1af-a4c6-4c4f-8a76-3c6c2f1a0af4/
stackoverflow.com/questions/1…
//防止UINavigationBar遮挡其下面的view
self.edgesForExtendedLayout = UIRectEdgeNone;
//防止UINavigationBar遮挡下面的UIScrollview
automaticallyAdjustsScrollViewInsets=YES;
extendedLayoutIncludesOpaqueBars
This value is just an addition to the previous ones. If the status bar is opaque, the views won't be extended to include the status bar too, unless this parameter is YES. So, if you extend your view to cover the navigation bar (edgesForExtendedLayout to UIRectEdgeAll) and the parameter is NO (default) it wont covert the status bar if it's opaque.
evernote:///view/555639/s7/0de3b90a-7145-46f5-b4f7-8e24b9276545/0de3b90a-7145-46f5-b4f7-8e24b9276545/
定时器的用法:
- 方式1:
// 定时器执行的方法
- (void)paint:(NSTimer *)paramTimer{
NSLog(@"定时器执行的方法");
}
// 开始定时器
- (void) startPainting{
// 定义一个NSTimer
self.paintingTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(paint:) userInfo:nil
repeats:YES];
}
- 方式2:
// 使用timerWithTimeInterval方法来实例化一个NSTimer,这时候NSTimer是不会启动的
self.paintingTimer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:@selector(paint:)
userInfo:nil
repeats:YES];
// 当需要调用时,可以把计时器添加到事件处理循环中
[[NSRunLoop currentRunLoop] addTimer:self.paintingTimer forMode:NSDefaultRunLoopMode];
- 方式3:
- (void) startPainting{
// 定义将调用的方法
SEL selectorToCall = @selector(paint:);
// 为SEL进行 方法签名
NSMethodSignature *methodSignature =[[self class] instanceMethodSignatureForSelector:selectorToCall];
// 初始化NSInvocation
NSInvocation *invocation =[NSInvocation invocationWithMethodSignature:methodSignature];
[invocation setTarget:self];
[invocation setSelector:selectorToCall];
self.paintingTimer = [NSTimer timerWithTimeInterval:1.0
invocation:invocation
repeats:YES];
// 当需要调用时,可以把计时器添加到事件处理循环中
[[NSRunLoop currentRunLoop] addTimer:self.paintingTimer forMode:NSDefaultRunLoopMode];
}
//NSInvocation是什么?
//是Object-C 中的消息传递着。它可以以“方法签名”的方式来封装一个对象的方法,并且在各个对象中传送!主要可以用在NSTimer中。
UIViewController的生命周期,就是来负责这些问题的处理。
呈现视图的顺序
它内部的顺序是这样的:
- 先走init方法,如果有自定义视图,则走自定义视图。如果没有,则走xib或storyborad,如果这个也没有则走loadView方法,loadView方法系统调用,也可以重载它。当我们重载它时,可以[super loadView] 父类帮助我们创建一个空的view,如果不调用父类,那么就要自己创建一个UIView,并且self.view = UIView。
- 如果在调用loadView时不调用父类,也不创建,如果使用self.view的getter method并且view等于nil,会发生自我循环调用。一般情况下,不要在初始化时做view相当的动作。在viewDiload中调用一些网络访问的动作,可以在初始化方法中做一些关于模型数据的准备工作。
- 如果覆盖了loadView,则必须创建UIViewController的view属性。如果没有覆盖该方法,UIViewController会默认调用initWithNibName方法来初始化并加载view。
ref: lcepy.github.io/2015/02/16/…
关于类簇
I don't know what is in the CDP that Steve referenced but basically the Objective-C Class Cluster is a construct that supports implementing the abstract Factory pattern.
The idea is simple: You want to provide a Factory (Cluster) interface that, with minimal description, manufactures and returns a specific concrete instance of a Factory Object that satisfies the behavior of the cluster family described by the Factory (Cluster) interface.
A simple concrete example: This example provides a Laugh factory that produces concrete classes of specific laughter types (e.g. Guffaw, Giggle). Pay attention to the Laugh initWithLaughter: method.
In Laugh.h:
#define kLaughWithGuffaw 1
#define kLaughWithGiggle 2
@interface Laugh: NSObject {}
- (Laugh *) initWithLaughter:(NSUInteger) laughterType;
- (void) laugh;
@end
In Laugh.m:
@interface Guffaws:Laugh {}
- (void) laugh;
@end
@interface Giggles:Laugh {}
- (void) laugh;
@end
@implementation Laugh
- (Laugh *) initWithLaughter:(NSUInteger) laugherType {
id instanceReturn=nil;
; // Removed for ARC [self release]
if ( laughterType == kLaughWithGuffaw )
instanceReturn = [[Guffaws alloc]init];
else if( laughterType == kLaughWithGiggle )
instanceReturn = [[Giggles alloc]init];
else
; // deal with this
return instanceReturn;
}
- (void) laugh {
NSLog(@"Humbug");
}
@end
@implementation Guffaws
- (void) laugh {
NSLog(@"OH HA HA HOWAH HA HA HA");
}
@end
@implementation Giggles
- (void) laugh {
NSLog(@"Tee hee");
}
@end
From programming in objective c by Stephen Kochan on page 498 in the glossary, cluster: An abstract class that groups a set of private concrete subclasses, providing a simplified interface to the user through the abstract class.
ref: stackoverflow.com/questions/1…
关于使用分类来覆盖原有的方法:
Overriding methods using categories in Objective-C
-
Although the Objective-C language currently allows you to use a category to override methods the class inherits, or even methods declared in the class interface, you are strongly discouraged from doing so. A category is not a substitute for a subclass. There are several significant shortcomings to using a category to override methods:
-
When a category overrides an inherited method, the method in the category can, as usual, invoke the inherited implementation via a message to super. However,
if a category overrides a method that exists in the category's class, there is no way to invoke the original implementation.
A category cannot reliably override methods declared in another category of the same class.
- This issue is of particular significance because many of the Cocoa classes are implemented using categories. A framework-defined method you try to override may itself have been implemented in a category, and so which implementation takes precedence is not defined.
The very presence of some category methods may cause behavior changes across all frameworks. For example, if you override the windowWillClose: delegate method in a category on NSObject, all window delegates in your program then respond using the category method; the behavior of all your instances of NSWindow may change. Categories you add on a framework class may cause mysterious changes in behavior and lead to crashes.
You can do this by adapting Class Cluster approach, or using methods swizzling technique. Otherwise, the behavior of two or more categorized methods is undefined
ref: stackoverflow.com/questions/5…
CGRectDivide构造一个网格布局:
void (^addGrid)(CGRect) = ^(CGRect frame) {
UIView *grid = [[UIView alloc] initWithFrame:frame];
grid.backgroundColor = [UIColor colorWithHue:drand48()
saturation:1.0
brightness:1.0
alpha:1.0];
grid.layer.borderColor = [[UIColor grayColor] CGColor];
grid.layer.borderWidth = 0.5;
[self.view addSubview:grid];
};
CGFloat gridWidth = 40.0, gridHeight = 30.0;
NSInteger numberOfRow = 10, numberOfColumn = 8;
CGRect slice, rowRemainder, columnRemainder;
rowRemainder = self.view.bounds;
for (NSInteger i = 0; i < numberOfRow; i++) { // 行
CGRectDivide(rowRemainder, &slice, &rowRemainder, gridHeight, CGRectMinYEdge);
columnRemainder = slice;
for (NSInteger j = 0; j < numberOfColumn; j++) { // 列
CGRectDivide(columnRemainder, &slice, &columnRemainder, gridWidth, CGRectMinXEdge);
addGrid(slice);
}
}
void CGRectDivide (
CGRect rect,
CGRect *slice,
CGRect *remainder,
CGFloat amount,
CGRectEdge edge
);
这个函数的功能很简单,就是将一个 CGRect 切割成两个 CGRect;其中,
rect 参数是你要切分的对象;
slice 是一个指向切出的 CGRect 的指针;
remainder 是指向切割后剩下的 CGRect 的指针;
amount 是你要切割的大小;
最后一个参数 edge 是一个枚举值,代表 amount 开始计算的方向,假设 amount 为 10.0 那么:
CGRectMinXEdge 代表在 rect 从左往右数 10 个单位开始切割
CGRectMaxXEdge 代表在 rect 从右往左数 10 个单位开始切割
CGRectMinYEdge 代表在 rect 从上往下数 10 个单位开始切割
CGRectMaxYEdge 代表在 rect 从下往上数 10 个单位开始切割
ref:lldong.github.io/2014/06/12/…
iOS项目中group和folder的区别
Group:
如果xcode中使用的是group,那么Xcode自动帮你存储group里面的每一个单独的文件的一个引用,这些引用存储在project.pbxproj文件里面(用命令行打开这个文件就可以清楚的看出来了),也就是相当与有一个指针指向了这个图片。
缺点:group只是一个虚拟的文件夹,硬盘上不一定存在对应的文件夹。这就会导致给人疑惑或者给项目的维护带来不便。优点:build app的时候,xcode将所有group文件夹层级都展开放在最高层级的bundle下,也就是说所有group里的文件都是同一个层级的,所以你代码里面引用某个文件就不需要写整个文件的路径,只需要写文件名就好了。 例如将: [UIImage imageNamed:@"Resource/image/logo"]; 替代为: [UIImage imageNamed:@"logo"]; 但这也意味着你需要处理文件命名冲突的问题。
Folder
folder相对比较容易理解,你可以很容易在xcode的项目中找到他们,黄色的文件夹是group,而蓝色的是folder。
优点:
1、project.pbxproj仅仅是对folder这个文件夹做了引用,文件夹里面的文件或者子文件夹,都是自动引入到xcode项目里面的,并没有引用。也就是说project.pbxproj文件变得更小更简单。 2、如果删除,重命名硬盘项目上某个folder里面的文件,那么xcode会自动帮你更新改变的文件,文件管理变得更容易。 3、xcode上的folder文件夹层级跟硬盘上的文件夹层级是一致的,所以就没有跟group一样的疑惑。 4、不需要担心命名冲突,因为不同folder里面可以有同一个名字相同的文件。
缺点:代码里引用文件的时候需要文件的路径,只是写文件名是引用不到文件的,这一点跟group正好相反。
iOS开发里的Bundle是个啥玩意?!
初学iOS开发的同学,不管是自己写的,还是粘贴的代码,或多或少都写过下面的代码
[[NSBundle mainBundle] pathForResource:@"someFileName" ofType:@"yourFileExtension"];
[YourViewController initWithNibName:"YourViewController" bundle:nil];
可是你知道这里的bundle到底是个啥玩意呢?!
Bundle简单地讲,就是一个内部结构按照标准规则组织的特殊目录
iOS的应用都是通过bundle进行封装的,对应的bundle类型是Application类型,平时我们通过XCode编译出来的Target(即我们开发的应用),其实就是一个Application类型bundle,即一个文件夹!但是Finder会把这个bundle当做一个文件显示给我们,其实是因为这个bundle自身也是一个package,而Mac系统会把所有的package当做一个文件来对待,显示给用户,从而防止用户误操作导致程序文件损坏或丢失。至于bundle和package有什么区别,就不在这里展开说明了,本文后面所说的bundle都会被Mac系统视为package。
疑问6:声明为IBOutlet属性的,在MRC中应该retain还是assign?在ARC中应该是strong还是weak?
在MRC中,应该是retain的,因为IBOutlet本身就是retain的
任何一个被声明为IBOutlet并且在Interface Builder里被连接到一个UI组件的成员变量,会被额外retain一次。 常见的情形如
IBOutlet UILabel *label; 这个label在Interface Builder里被连接到一个UILabel。此时,这个label的retainCount为2。 所以,只要使用了IBOutlet变量,一定需要在dealloc或者viewDidUnload里release这个变量。
在ARC中,property,我们将其申明为weak(事实上,如果没有特别意外,除了最顶层的IBOutlet意外,自己写的outlet都应该是weak)。通过加载xib得到的用户界面,在其从xib文件加载时,就已经是view hierarchy的一部分了,而view hierarchy中的指向都是strong的。因此outlet所指向的UI对象不应当再被hold一次了。将这些outlet写为weak的最显而易见的好处是你就不用再viewDidUnload方法中再将这些outlet设为nil了(否则就算view被摧毁了,但是由于这些UI对象还在被outlet指针指向而无法释放)。
dequeueReusableCellWithIdentifier vs dequeueReusableCellWithIdentifier : forIndexPath
The most important difference is that the forIndexPath: version asserts (crashes) if you didn't register a class or nib for the identifier. The older (non-forIndexPath:) version returns nil in that case.
You register a class for an identifier by sending registerClass:forCellReuseIdentifier: to the table view. You register a nib for an identifier by sending registerNib:forCellReuseIdentifier: to the table view.
If you create your table view and your cell prototypes in a storyboard, the storyboard loader takes care of registering the cell prototypes that you defined in the storyboard.
Session 200 - What's New in Cocoa Touch from WWDC 2012 discusses the (then-new) forIndexPath: version starting around 8m30s. It says that “you will always get an initialized cell” (without mentioning that it will crash if you didn't register a class or nib).
The video also says that “it will be the right size for that index path”. Presumably this means that it will set the cell's size before returning it, by looking at the table view's own width and calling your delegate's tableView:heightForRowAtIndexPath: method (if defined). This is why it needs the index path.
ref:stackoverflow.com/questions/2…
transient property
@interface Card : NSManagedObject
@property (nonatomic, retain) NSString * imagePath;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSNumber * order;
@property (nonatomic, retain) NSString * displayName;
@property (nonatomic, retain) UIImage *displayImage; //transient property
@end
Here we change the class of the transient property to the actual class type
e.g. displayImage type here is UIImage.
In the implementation file (or an extension class) you implement the getter/setter for your transient property:
也就是相当于swift中的计算属性.
-(UIImage*)displayImage{
//Get Value
[self willAccessValueForKey:@"displayImage"];
UIImage *img = (UIImage*)[self primitiveValueForKey:@"displayImage"];
[self didAccessValueForKey:@"displayImage"];
if (img == nil) {
if ([self imagePath]) { //That is a non-transient property on the object
img = [UIImage imageWithContentsOfFile:self.imagePath];
//Set Value
[self setPrimitiveValue:img forKey:@"displayImage"];
}
}
return img;
}
Hope that helps you.
ref: stackoverflow.com/questions/1…
关于推送证书:
当你为一个appid生成推送证书的时候,那么需要你重新生成一下provisioning file.
If you are getting this message:
no valid 'aps-environment' entitlement string found for applicationin the NSError that is passed to-[UIApplication application:didFailToRegisterForRemoteNotificationsWithError:], you may need to check that you're using the correct provisioning profile, and that it is the one that is Push Notification-enabled.
同一个UITableView可不可以注册两个不同的nib
答案是可以的:
[_tableview registerNib:[UINib nibWithNibName:@"AppointTimeHeadCell" bundle:nil] forCellReuseIdentifier:@"headcell"];
[_tableview registerNib:[UINib nibWithNibName:@"AppointTimeDetailCell" bundle:nil] forCellReuseIdentifier:@"detailcell"];
那么在使用的时候,我可以根据不同的需要,分别dequeue了:
AppointTimeHeadCell* cell=[tableView dequeueReusableCellWithIdentifier:@"headcell"];
OR:
AppointTimeHeadCell* cell=[tableView dequeueReusableCellWithIdentifier:@"detailcell"];
关于字典到model的映射
[model setValuesForKeysWithDictionary:dic] 如果dic中的key在model中没有对应的属性,会导致运行时崩溃,那么这时在model对应的类中需要实现实现一个方法setValue:forUndefinedKey:,来处理没有的key 或非法的key,如名字为"id"的key.
单例模式中如何隐藏init
Throw an exception in init
- (instancetype)init {
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (instancetype)initPrivate {
self = [super init];
if (self) {
}
return self;
}
+ (instancetype)sharedInstance {
static MySingleton *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] initPrivate];
});
return sharedInstance;
}
Have init return your singleton
- (instancetype)init {
return [[self class] sharedInstance];
}
- (instancetype)initPrivate {
self = [super init];
if (self) {
}
return self;
}
+ (instancetype)sharedInstance {
static MySingleton2 *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] initPrivate];
});
return sharedInstance;
}
What property should I use for a Dispatch Queue after ARC?
Updated answer: In current OS X and iOS, Dispatch objects are now treated as Obj-C objects by ARC. They will be memory-managed the same way that Obj-C objects will, and you should use strong for your property.
This is controlled by the OS_OBJECT_HAVE_OBJC_SUPPORT macro, defined in <os/object.h>. It's set to 1 by default when your deployment target is OS X 10.8 or higher, or iOS 6.0 or higher. If you're deploying to an older OS, then this is left at 0 and you should see my original answer below.
Original answer:
Dispatch objects (including queues) are not Obj-C objects, so the only possible choice is assign. The compiler will throw an error if you try to use strong or weak. ARC has no impact on GCD.
关于在调试控制台打印uiview的hidden属性
直接使用expr [myview hidden]是打印不出来的,因为在UIView中,属性hidden的声明如下:
@property(nonatomic,getter=isHidden) BOOL
应该这样在控制台输出:
expr [myview isHidden]
两种获取UIWindow方法的区别:
-
当使用故事板的时候,必须使用这种方法: [[[UIApplication sharedApplication] delegate] window];
-
当用代码来创建UIWindow的时候,要使用这种方法: [[UIApplication sharedApplication] keyWindow];
不过对于,用来代码来创建UIWindow,这两种方式都是一样的.
They are the same in iOS, but on Mac OS they can be different, because in iOS there is only one window, while on Mac OS could be more than one. from the documentation:
- For
[[[UIApplication sharedApplication] delegate] window];
The window to use when presenting a storyboard. This property contains the window used to present the app’s visual content on the device’s main screen. i.e this is the property window you have in your appDelegate.h file
for [[UIApplication sharedApplication] keyWindow];
This property holds the UIWindow object in the windows array that is most recently sent the makeKeyAndVisible message. in iOS you sent makeKeyAndVisible in your appDelegate.m inside
application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptionsto window, which what we have above, so they are the same. (This is done automatically if you are using storyboards)
ref: stackoverflow.com/questions/2…
按下按钮,却在按钮外面松手,不让它触发回调.
TouchUpInside event is fired even if you touch up outside the button While I'm not sure how to modify the way that Apple calculates a button's tappable zone, I can offer you a workaround solution. In your event handler for UIControlEventTouchUpInside, you can check to see if the location of the touchUpInside event is actually within the bounds of the button:
[myButton addTarget:self action:@selector(buttonWasPressed:event:) forControlEvents:UIControlEventTouchUpInside];
//...
- (void)buttonWasPressed:(UIButton *)sender event:(UIEvent *)event
{
CGPoint location = [[[event allTouches] anyObject] locationInView:sender];
if (!CGRectContainsPoint(sender.bounds, location)) {
// Outside of bounds, so ignore:
return;
}
// Inside our bounds, so continue as normal:
}
UIPanGestureReconizer的一些用法.
手指在屏幕上一路拖动,会掠过不少的视图,那么下面的API,可以出在这些视图内移动了多少距离,以及移动的速度. 移动的速度和距离是矢量,为正代码向右移动,为负代表向左移动.
//translationInView是指拖动手势在指定的视图移动了多少距离,
[UIMyPanGesture translationInView:view]
//velocityInView是指拖动手势在指定的视图内移动的速度,单位是 points per second.
[UIMyPanGesture velocityInView:view]
当你设置gestureRecognizer.enabled = NO; ,那么手势的状态会切换到canceled
让UIActionSheet同步执行.
-
CFRunLoopRun()的document: Runs the current thread’s CFRunLoop object in its default mode indefinitely. The current thread’s run loop runs in the default mode (see Default Run Loop Mode) until the run loop is stopped with CFRunLoopStop or all the sources and timers are removed from the default run loop mode. Run loops can be run recursively. You can call CFRunLoopRun from within any run loop callout and create nested run loop activations on the current thread’s call stack.
-
下面的代码中CFRunLoopRun()使得当前线程的run loop在它的default mode下无限运行,程序的执行流程在这里就不会继续往下走了. 那当前线程事件分发,都会经由这个run loop.
-
使用CFRunLoopStop(CFRunLoopGetCurrent())终止当前的run loop. 如果当前线程没有在运行的run loop,那么该语句没有作用.
- (NSInteger)showInView:(UIView *)view {
_actionSheet = [[UIActionSheet alloc] init];
for (NSString * title in _titles) {
[_actionSheet addButtonWithTitle:title];
}
if (_destructiveButtonIndex != -1) {
_actionSheet.destructiveButtonIndex = _destructiveButtonIndex;
}
if (_cancelButtonIndex != -1) {
_actionSheet.cancelButtonIndex = _cancelButtonIndex;
}
[_actionSheet showInView:view];
CFRunLoopRun();
return _selectedIndex;
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
_selectedIndex = buttonIndex;
_actionSheet = nil;
CFRunLoopStop(CFRunLoopGetCurrent());
}
ref: blog.devtang.com/blog/2012/0… stackoverflow.com/questions/1…
等待异步操作完成.
- 使用CFRunLoopRun()
// run work asynchronously
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0UL);
dispatch_async(queue,^{
NSLog(@"==================");
sleep(1); // replace this with your task
dispatch_async(dispatch_get_main_queue(), ^{
CFRunLoopStop(CFRunLoopGetCurrent());
});
finished = YES;
});
CFRunLoopRun();
NSLog(@"=======end=========");
- 又一种的等待方式
__block BOOL finished = NO;
NSLog(@"starting.......");
// run work asynchronously
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0UL);
dispatch_async(queue,^{
sleep(7); // replace this with your task
NSLog(@"======work done======");
finished = YES;
});
int i=0;
// wait two seconds
NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:7];
while (!finished ) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]];
NSLog(@"=====已经等待%d秒======",++i);
}
NSLog(@"=========end=========");
输出:
2015-07-15 22:18:31.942 TESTGcd[52057:2600890] starting.......
2015-07-15 22:18:32.957 TESTGcd[52057:2600890] =====已经等待1秒======
2015-07-15 22:18:33.959 TESTGcd[52057:2600890] =====已经等待2秒======
2015-07-15 22:18:34.961 TESTGcd[52057:2600890] =====已经等待3秒======
2015-07-15 22:18:35.965 TESTGcd[52057:2600890] =====已经等待4秒======
2015-07-15 22:18:36.969 TESTGcd[52057:2600890] =====已经等待5秒======
2015-07-15 22:18:37.970 TESTGcd[52057:2600890] =====已经等待6秒======
2015-07-15 22:18:38.975 TESTGcd[52057:2600890] =====已经等待7秒======
2015-07-15 22:18:39.030 TESTGcd[52057:2600985] ======work done======
2015-07-15 22:18:39.979 TESTGcd[52057:2600890] =====已经等待8秒======
2015-07-15 22:18:39.979 TESTGcd[52057:2600890] =========end=========
让NSTimer在新的线程中运行
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//创建一个新的线程,其中object:nil部分可以作为selector的参数传递,在这里没有参数,设为nil
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(playerThread: ) object:nil];
//开启线程,如果是利用NSOperation,只需要加入到NSOperationQueue里面去就好了,queue自己会在合适的时机执行线程,而不需要程序员自己去控制。
[thread start];
}
- (void) playerThread:(id)unused
{
_currentLoop = CFRunLoopGetCurrent();//子线程的runloop引用
//run loop
[self initPlayer];
//CFRunLoopRun,Runs the current thread’s CFRunLoop object in its default mode indefinitely.
CFRunLoopRun();
//run loop,这里就会停住了。
}
// 实现一个timer,用于检查子线程的工作状态,并在合适的时候做任务切换。或者是合适的时候停掉
// 自己的run loop
-(void) initPlayer
{
// 在这里你可以初始化一个工作类,比如声音或者视频播放
NSTimer *stateChange = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self
selector:@selector(checkState:) userInfo:nil repeats:YES];
}
-(void) checkState:(NSTimer*) timer
{
NSLog(@"isMainThread:%d,%ld",[NSThread isMainThread],i++);
if(i==5){
CFRunLoopStop(_currentLoop);
}
}
output:
2015-07-21 09:30:12.621 testRunLoop1[81241:2396465] isMainThread:0,0
2015-07-21 09:30:13.118 testRunLoop1[81241:2396465] isMainThread:0,1
2015-07-21 09:30:13.620 testRunLoop1[81241:2396465] isMainThread:0,2
2015-07-21 09:30:14.117 testRunLoop1[81241:2396465] isMainThread:0,3
2015-07-21 09:30:14.620 testRunLoop1[81241:2396465] isMainThread:0,4
等待dispatch_after的完成:
__block BOOL finished = NO;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0UL);
dispatch_async(queue,^{
sleep(1); // replace this with your task
finished = YES;
});
dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, 2LL * NSEC_xER_SEC;
dispatch_after(timeout, dispatch_get_main_queue(), ^(void){
STAssertTrue(finished, @"Should have finished by now");
});
// wait two seconds
NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:2];
while (!finished && [timeout timeIntervalSinceNow]>0) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1]];
使用dispatch_queue_t来实现timer
__block int timeout=300; //倒计时时间
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //没秒执行
dispatch_source_set_event_handler(_timer, ^{
if(timeout<=0){ //倒计时结束,关闭
dispatch_source_cancel(_timer);
dispatch_release(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
//设置界面的按钮显示 根据自己需求设置
。。。。。。。。
});
}else{
int minutes = timeout / 60;
int seconds = timeout % 60;
NSString *strTime = [NSString stringWithFormat:@"%d分%.2d秒后重新获取验证码",minutes, seconds];
dispatch_async(dispatch_get_main_queue(), ^{
//设置界面的按钮显示 根据自己需求设置
。。。。。。。。
});
timeout--;
}
});
dispatch_resume(_timer);
异步操作的顺序保证
-
According to the documentation, multiple dispatch_async calls on same queue will have order maintained, and multiple performSelectorOnMainThread: calls from same thread will maintain order as well.
-
综上所述,下面两个调用,就不能保证其先后顺序.
According to Apple's "Concurrency Programming Guide", the main queue will interleave queued tasks with other events from the app's run loop. Thus, if there are other events to be processed in the event queue, the queued blocks in the dispatch queue may be run first, even though they were submitted later.
[self performSelectorOnMainThread:@selector(doA) withObject:nil waitUntilDone:NO];
dispatch_async(dispatch_get_main_queue(), ^{ [self doB]; });
ref:blackpixel.com/writing/201…
performSelectorOnMainThread和dispatch_get_main_queue()的区别
By default, -performSelectorOnMainThread:withObject:waitUntilDone: only schedules the selector to run in the default run loop mode. If the run loop is in another mode (e.g. the tracking mode), it won't run until the run loop switches back to the default mode. You can get around this with the variant -performSelectorOnMainThread:withObject:waitUntilDone:modes: (by passing all the modes you want it to run in).
On the other hand, dispatch_async(dispatch_get_main_queue(), ^{ ... }) will run the block as soon as the main run loop returns control flow back to the event loop. It doesn't care about modes. So if you don't want to care about modes either, dispatch_async() may be the better way to go.
ref:stackoverflow.com/questions/9…
unichar的用法.
unichar special=0x2006;
NSString* specialStr=[NSString stringWithCharacters:&special length:1];
str=[str stringByReplacingOccurrencesOfString:specialStr withString:@""];
UIScrollView中contentView高度的确定.
在UIScrollView的contentView中内嵌多个可变高度的view的布局中,如果要确定最终contentView的高度,那么可以根据多个可变高度的view中最后一个view的位置,加上他的高度,来计算出,最终的contentView的高度.
关于viewDidLoad中self.view的大小问题.
在xib中view的大小是320480,现在view要在iphone6(320568)中显示,那么此时在viewDidLoad中self.view的大小依然为320480 ,而在viewWillAppear中self.view的大小为320568.
关于UIView的层次问题.
view通过父视图的addSubview方法被添加到父视图中,那么这些子视图的z-order,分别为,最先添加的子视图,其z-order最小,后来添加的子视图依次变大.其具体的z-order顺序,和superiew.subViews中对应视图的index相似.
相关的API:
将一个UIView显示在最前面只需要调用其父视图的 bringSubviewToFront()方法。
将一个UIView层推送到背后只需要调用其父视图的 sendSubviewToBack()方法。
判断一个类是否实现了某个协议
[MyClass conformsToProtocol:@protocol(MyProtocol)];
- Indicator的隐藏显示: ActivityIndicator的隐藏用stopAnimating,不要用hidden = YES。
2.autolayout和Aspect Fit不冲突,因此,UIImageVIew需要增加完全的约束,而Aspect Fit会根据计算的大小进行Aspect Fit。
viewDidLayoutSubviews 与 layoutSubviews 调用顺序
(lldb) po [[self view] recursiveDescription]
<MyCustomView: 0x8d8f070; frame = (0 0; 320 480); autoresize = W+H; layer = <CALayer: 0x8d8f490>>
| <ZQCustomView: 0x8c61130; frame = (0 0; 0 0); layer = <CALayer: 0x8c61220>>
| | <UIButton: 0x8f55530; frame = (100 100; 50 50); opaque = NO; layer = <CALayer: 0x8f59320>>
| | | <UIButtonLabel: 0x8f594e0; frame = (9 16; 32 18); text = ' GO '; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8f595d0>>
也即是:self.view 上添加个自定义的customView
打印调用的顺序:
TestFunctionCall[49445:60b] ---> -[ZQRootViewController viewDidLoad]
TestFunctionCall[49445:60b] ---> -[MyCustomView layoutSubviews]
TestFunctionCall[49445:60b] ---> -[ZQRootViewController viewWillLayoutSubviews]
TestFunctionCall[49445:60b] ---> -[ZQRootViewController viewDidLayoutSubviews]
TestFunctionCall[49445:60b] ---> -[ZQCustomView layoutSubviews]
TestFunctionCall[49445:60b] ---> -[ZQCustomView layoutSubviews]
TestFunctionCall[49445:60b] ---> -[ZQCustomView drawRect:]
可以看到MyCustomView即控制器的rootview,调用完layoutSubviews,之后,就调用控制器的viewDidLayoutSubviews. 然后,rootview中的子视图,再分别调用自己的layoutSubviews分别完成自己的布局.
viewDidLayoutSubviews的作用,就像其本身的名字一样,仅在完成了当前view的子视图的布局之后调用的.
会调用viewDidLayoutSubviews
- 当你改变以约束之后,可以直接调用layoutIfNeeded
- 在viewWillLayoutSubviews中,可以对视图的frame约束进行调整.
- 当屏幕横竖方向发生了变化之后,会调用viewDidLayoutSubviews
-
setNeedsUpdateConstraints makes sure a future call to updateConstraintsIfNeeded calls updateConstraints. setNeedsLayout makes sure a future call to layoutIfNeeded calls layoutSubviews.
-
I set up my constraints in viewDidLoad/loadView (I'm targeting iOS >= 6). updateViewConstraints is useful for changing values of constraints, e.g. if some constraint is dependent on the orientation of the screen (I know, it's a bad practice) you can change its constant in this method.
-
If you are using auto layout, assign sufficient constraints to each of the views you just created to control the position and size of your views. Otherwise, implement the viewWillLayoutSubviews and viewDidLayoutSubviews methods to adjust the frames of the subviews in the view hierarchy.
-
其他地方适合设置constraint的值,比如viewDidLayoutSubviews或者viewDidAppear等
-(void)viewDidLayoutSubviews{ NSLog(@"view did layout subviews"); widthConstraint.constant=scrollView.frame.size.width; //为了兼容iOS7,http://stackoverflow.com/questions/15490140/auto-layout-error //iOS8下无需这句话 [self.view layoutSubviews]; }
ref: stackoverflow.com/questions/1…
-
不要在运行时删除约束,然后再重新添加约束,这样的成本会较高,改变约束的constant会是一个较好的做法.
Apple UIKit engineers recommend. The most important point is to avoid removing constraints once the auto layout engine has done a layout pass -- it's unbelievably expensive to remove a bunch of constraints, re-add some more, and then re-calculate the layout. If you do want to make changes to constraints, adjust the constant property on existing ones because it is very efficient for the auto layout engine to re-solve.
父类的updateViewConstraints和updateConstraints一定放在最后
-
I recommend creating a BOOL and setting them in the -updateConstraints of UIView (or -updateViewConstraints, for UIViewController).
-[UIView updateConstraints]: (apple docs)
Custom views that set up constraints themselves should do so by overriding this method.
Both -updateConstraints and -updateViewConstraints may be called multiple times during a view's lifetime. (Calling setNeedsUpdateConstraints on a view will trigger this to happen, for example.) As a result, you need to make sure to prevent creating and activating duplicate constraints -- either using a BOOL to only perform certain constraint setup only once, or by making sure to deactivate/remove existing constraints before creating & activating new ones.
For example:
- (void)updateConstraints { // for view controllers, use -updateViewConstraints
if (!_hasLoadedConstraints) {
_hasLoadedConstraints = YES;
// create your constraints
}
[super updateConstraints];
}
- If you call super before making changes to some constraints, you may hit a runtime exception (crash). make sure to call super at the very end of your implementation of -updateConstraints or -updateViewConstraints
ref: stackoverflow.com/questions/1…
关于Multitouch Events
1.要启动多点触控,先把view的multipleTouchEnabled property 设置为YES,该选项默认为NO.
The other parameter is an event (UIEvent object) that includes all touch objects for the event. This differs from the set of touches because some of the touch objects in the event may not have changed since the previous event message.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
event.alltouchs返回的是所有的touches,而上面的touches参数,仅是较上次变化了touch.
ref:developer.apple.com/library/pre…
主nib文件
主nib文件是指应用程序一启动就装载的nib文件,它的File’s Owner一定要是个UIApplication(或子类),并且新建一个delegate对象、建立UIApplication和delegate对象的关联
[UIApplication sharedApplication].windows: 在本应用中打开的UIWindow列表,这样就可以接触应用中的任何一个UIView对象
[UIApplication sharedApplication].keyWindow: 用来接收键盘以及非触摸类的消息事件的UIWindow,而且程序中每个时刻只能有一个UIWindow是keyWindow。如果某个UIWindow内部的文本框不能输入文字,可能是因为这个UIWindow不是keyWindow
今天碰到崩溃如下:
1 UIKit 0x33e4193e -[UIGestureRecognizer _delegateShouldReceiveTouch:] + 114
2 UIKit 0x33d6f8b2 -[UITouchesEvent _addGestureRecognizersForView:toTouch:currentTouchMap:newTouchMap:] + 782
3 UIKit 0x33d6f394 -[UITouchesEvent _addTouch:forDelayedDelivery:] + 212
4 UIKit 0x33d6f2ac _AddTouchToEvent + 184
是由于对象已经销毁,但是UIGestureRecognizer的delegate没有置为空造成的.
关于UINavigationController滑动返回相关问题总结:
1.从ViewController1 push 到 ViewController2,这时由ViewController2滑动返回到ViewController1,滑动到一半的时候,再返回到ViewController2. 这时想着方法的调用顺序是:
-[ViewController2 viewWillDisappear:]
-[ViewController1 viewWillAppear:]
-[ViewController1 viewWillDisappear:]
-[ViewController1 viewDidDisappear:]
-[ViewController2 viewWillAppear:]
-[ViewController2 viewDidAppear:]
可以看到,会出现viewWillAppear或者Disappear后面不一定跟着viewDidAppear或者Disappear方法。此时如果代码内依赖这种成对调用的逻辑很可能就会出现Bug,开发者需要多注意。
注意,当开始进行右滑动作时,UINavigationController会立即调用自己的popViewControllerAnimated:方法,参数为YES。但是如果此时再左滑返回,UINavigationController不会再调用pushViewController:animated:方法。
2.滑动的过程中出现了三个小点点,不要在自定义leftBarButton后设置成YES,即可解决.
ref: www.mgenware.com/blog/?p=254…
对UINavigationBar的外观进行统一的设置.
1.统一设置UIBarButtonItem的文字颜色:
[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
2.统一设置title的字体及颜色
[[UINavigationBar appearance] setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys: [UIColor whiteColor], UITextAttributeTextColor, [UIFont boldSystemFontOfSize:20.0], UITextAttributeFont,nil]];
3.To customize the appearances for instances of a class when contained within an instance of a container class, or instances in a hierarchy, you use appearanceWhenContainedIn: to get the appearance proxy for the class:
[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil]
setTintColor:myNavBarColor];
[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], [UIPopoverController class], nil]
setTintColor:myPopoverNavBarColor];
[[UIBarButtonItem appearanceWhenContainedIn:[UIToolbar class], nil]
setTintColor:myToolbarColor];
[[UIBarButtonItem appearanceWhenContainedIn:[UIToolbar class], [UIPopoverController class], nil]
setTintColor:myPopoverToolbarColor];
ref:nshipster.com/uiappearanc…
setTranslation:inView:的用法:
Sets the translation value in the coordinate system of the specified view. Changing the translation value resets the velocity of the pan.
-(void)setTranslation:(CGPoint)translation inView:(UIView *)view; 这个API用于重新设置一下translation的值
- (void)viewDidLoad {
[super viewDidLoad];
UIPanGestureRecognizer* pan=[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
[self.barView addGestureRecognizer:pan];
}
-(void)panAction:(UIPanGestureRecognizer*)sender{
if (sender.state == UIGestureRecognizerStateChanged ||
sender.state == UIGestureRecognizerStateEnded) {
//注意,这里取得的参照坐标系是该对象的上层View的坐标。
CGPoint offset = [sender translationInView:self.view];
NSLog(@"%f",offset.x);
UIView *draggableObj = self.barView;
//通过计算偏移量来设定draggableObj的新坐标
[draggableObj setCenter:CGPointMake(draggableObj.center.x + offset.x, draggableObj.center.y + offset.y)];
//初始化sender中的坐标位置。如果不初始化,移动坐标会一直积累起来。
[sender setTranslation:CGPointMake(0, 0) inView:self.view];
}
}
当UIView上的UIPanGestureRecognizer与touchs等方法共存时的问题.
当手势添加到view上的时候,手势会开始观察view和view上的subviews。
当手势被识别的时候,之前的touch将被取消同时不会再传递,也就是说当手势被识别的时候,view上的touchs系列方法中,touch cancel被触发.
也就是说只要view上手势识别器识别成功,那么手势就不再传递给view,识别失败则传递给view.
当然这个可以通过设置`cancelsTouchesInView`为NO来取消或者开启,
In the simple case, when a touch occurs, the touch object is passed from the UIApplication object to the UIWindow object. Then, the window first sends touches to any gesture recognizers attached the view where the touches occurred (or to that view’s superviews), before it passes the touch to the view object itself.
Gesture Recognizers Get the First Opportunity to Recognize a Touch
A window delays the delivery of touch objects to the view so that the gesture recognizer can analyze the touch first. During the delay, if the gesture recognizer recognizes a touch gesture, then the window never delivers the touch object to the view, and also cancels any touch objects it previously sent to the view that were part of that recognized sequence.
ref: developer.apple.com/library/ios… www.cnblogs.com/peterpan507…
requireGestureRecognizerToFail
- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;
当otherGestureRecognizer的状态为UIGestureRecognizerStateFailed时, receiver会正常切换到它的下一个状态
当otherGestureRecognizer的状态为UIGestureRecognizerStateRecognized or UIGestureRecognizerStateBegan时, receiver切换到UIGestureRecognizerStateFailed.
也可以认为otherGestureRecognizer和receiver是互斥的.
接口文档:
Creates a dependency relationship between the receiver and another gesture recognizer. This method creates a relationship with another gesture recognizer that delays the receiver’s transition out of UIGestureRecognizerStatePossible. The state that the receiver transitions to depends on what happens with otherGestureRecognizer: If otherGestureRecognizer transitions to UIGestureRecognizerStateFailed, the receiver transitions to its normal next state. if otherGestureRecognizer transitions to UIGestureRecognizerStateRecognized or UIGestureRecognizerStateBegan, the receiver transitions to UIGestureRecognizerStateFailed. An example where this method might be called is when you want a single-tap gesture require that a double-tap gesture fail.
ref:www.cnblogs.com/lexingyu/p/…
关于手势的一些基本知识
1.对手势识别器进行属性设定
[doubleTap setNumberOfTapsRequired:2];
[twoFingerTap setNumberOfTouchesRequired:2];
[swipeLeft setNumberOfTouchesRequired:1];
[swipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
[swipeRight setNumberOfTouchesRequired:1];
[swipeRight setDirection:UISwipeGestureRecognizerDirectionRight];
UIScreenEdgePanGestureRecognizer
popRecognizer.edges=UIRectEdgeLeft;
2.区分单击双击、滑动(Swipe)和拖拽(Pan)
在识别单击双击时,逻辑上应该只有判断非双击时,才判定为单击,否则永远都只会判断为单击;在识别滑动和拖拽时也是一样,应该先判断是否是swipe,不是则才是拖拽,否则都只会识别拖拽。实现方式见下面Step4,使用requireGestureRecognizerToFail方法。
3.每个方向的滑动(Swipe)都是一个独立的手势
如果你想接受向多个方向的滑动,对每个方向都要声明一个手势,专门代表这个方向的滑动。向左向右就是两个,加上向上向下就是4个。
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)];
UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)];
然后,你在扑捉到滑动手势之后的处理函数中,去判断UISwipeGestureRecognizer *类型的recognizer.direction属于哪个方向.
4.UIGestureRecognizer的其它方法还有:
// individual UIGestureRecognizer subclasses may provide subclass-specific location information. see individual subclasses for details
- (CGPoint)locationInView:(UIView*)view; //
- (NSUInteger)numberOfTouches; // number of touches involved for which locations can be queried
- (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(UIView*)view; // the location of a particular touch
获取touch的位置
下面tap需要两个手指同时点击,那么可以使用locationOfTouch:inView:来获取两个手指的位置.
-(void)gestureLoad {
UIGestureRecognizer *recognizer;
recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(numTap2:)];
[(UITapGestureRecognizer *)recognizer setNumberOfTouchesRequired:2];
[self.view addGestureRecognizer:recognizer];
}
- (void)numTap2:(UITapGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationOfTouch:0 inView:self.view];
CGPoint location1 = [recognizer locationOfTouch:1 inView:self.view];
NSLog(@"loc:x %f y %f",location.x, location.y);
NSLog(@"loc1:x %f y %f",location1.x, location1.y);
}