01 Dec 2015
偶然看到的收藏之
网络篇:
为啥要用第三方开源库?因为系统API废话太多,用起来太啰嗦。
HTTP请求看这些:
AFNetWorking: 个人认为是首选,轻量、易用,开发者也在很积极的维护,拥护者也多,新的项目,就直接用它吧! https://github.com/AFNetworking/AFNetworking
MKNetworkKit: 用的人也不少,也是非常轻量级,使用起来比较简单。https://github.com/MugunthKumar/MKNetworkKit
ASIHttpRequest: 一句话,过时了。开发者已经很久没有维护了,而且用起来有点重。
Socket通信看这个:
CocoaAsyncSocket: 如果要使用socket进行通讯,那么肯定就用他了,支持TCP和UDP,支持GCD,支持OC接口,封装的非常不错。 https://github.com/robbiehanson/CocoaAsyncSocket
网络相关工具看这个:
Reachability: 用来判断和监听网络状态和变化,非常好的辅助工具库,必用。 https://github.com/tonymillion/Reachability
JSON解析篇:
如果是支持iOS 5以上的系统,那么就直接使用系统提供的NSJSONSerialization吧,性能好,官方提供,可靠!
如果要用第三方的,那就选择JSONKit吧,性能好,源码就2文件,看着都舒服。
SBJson就千万别再用了,性能差,维护的也不好。
UI框架篇:
提升到框架层面,一般都比较重了,选择的时候需要慎重了,因为这个对于你的APP未必是必须的。
AsyncDisplayKit:强烈推荐一试。 Facebook刚刚开源发布的UI框架,被用于Facebook自家的应用Paper中。这个框架能给你带来的核心收益,是能够提高UI的流畅性,降低UI的响应时间。这是通过对UIKIt的进一步的异步封装来实现的,AsyncDisplayKit的UI元素都是线程安全的,可以在并行异步的进行操作,这样就可以让图像解码等耗时操作移出UI线程,为UI主线程减负。值得一提的是,AsyncDisplayKit的组件封装,与UIKit很类似,可以直接进行替换,接入门槛相对比较低。https://github.com/facebook/AsyncDisplayKit
ReactiveCocoa:如果你对响应式编程模式有兴趣,可以尝试一下这个框架,毕竟一般APP,大部分时间是在等待事件发生,等待用户操作或者网络请求返回,所以这种事件驱动模式,还是很适合的。https://github.com/ReactiveCocoa/ReactiveCocoa
bee Framework:国产mvc框架,将许多核心逻辑注入到了NSObject基类里,同样也是采用了响应式的设计。 https://github.com/gavinkwoe/BeeFramework
nimBus:Three20的作者之一开发的一套轻型框架,很多思路和Three20相似,但是轻量很多,支持命名空间,内部耦合性没那么高,很多人把他作为Three20的替代品。
Three20: 曾经的辉煌,Facebook自己也早已不维护,不要再使用了。
UI控件篇:
存储篇:
喜欢使用 sqlite的,可以试试fmdb,封装的不错,简洁易用。 https://github.com/ccgus/fmdb
如果要用CoreData, 那么用一下MagicalRecord,它降低了使用coredata的门槛。https://github.com/magicalpanda/MagicalRecord
如果要使用keyChain存储敏感数据,那么可以用SFHFKeychainUtils,使用非常简单。 https://github.com/kamiro/SFHFKeychainUtils
动画篇:
pop: Facebook发布的大名鼎鼎的动画库(动画引擎),支持多种常见动画效果,包括弹性和衰减,也可以自定义效果,最关键的是,其接口语法上和Core Animation非常相似,就像是重新实现了系统的Core Animation,所以上手容易。https://github.com/facebook/pop
Canvas :可以认为就是个动画集合,提供了对Core Animation进一步的封装。 https://github.com/CanvasPod/Canvas
工具篇:
日志框架: 用用 CocoaLumberjack吧,支持log分级,支持日志记录方式(控制台、文件、服务器),而且性能不错,可以简单的替换NSLog。 https://github.com/CocoaLumberjack/CocoaLumberjack
数据加密和摘要: CocoaSecurity 提供了常见的AES加解密,sha1、md5系列的摘要算法。 https://github.com/kelp404/CocoaSecurity
zip压缩和解压: ZipArchive,非常好用,打包上传和下载的时候经常需要用到。
文字效果: DTCoreText 是一个功能强大的文字效果库,可以在UITextView上实现包括文字大小、颜色、字体、下划线、链接、间距等效果。 https://github.com/Cocoanetics/DTCoreText
DTFoundation: 这是个强大的工具集合,百宝箱啊,里面有异步文件删除、目录监控、base64编码、日志、版本管理,以及对NSArray、NSDictionary、NSString、NSURL等系统类的一些方便使用扩展,还有对gif动画的支持和HTML解析,以及UIWebView、UIImage、UIView等UIKit的扩展和一些UI增强组件。 https://github.com/Cocoanetics/DTFoundation
MAZeroingWeakRef:非常棒的智能指针工具,可以自动销毁对象分配的内存,防止内存泄漏,方便内存管理。https://github.com/mikeash/MAZeroingWeakRef
TMCache: 一个不错的基于key/value的数据缓存库,支持内存和持久缓存,基于GCD支持多线程操作,挺好用。 https://github.com/tumblr/TMCache
扩展
94个iOS开发资源推荐,帮你加速应用开发
GitHub 上排名前 100 的 Objective-C 项目简介
01 Dec 2015
在UIImageView
中加载一个网络图片有一些需要注意的地方。因为retina屏使iPhone的屏幕的基础坐标系系统有一个像素到点的转换。以 iPhone 5为例,像素是640×1136 而点是320×568。这中间有一个2倍的缩放系数,即[UIScreen mainScreen].scale
。像素和点的关系是pixel = point × scale
。
还是以iPhone 5为例,假如有一张图片占据整个屏幕,并且图片命名有@2x
后缀,那么这张图正好适应这个全屏的UIImageView
并且不需要按照系数缩放。但是,如果这个图片的命名没有@2x
后缀,iOS
会放大这张图片两倍。而在加载网络图片的时候正是这个问题,因为图片名木有@2x
后缀。
下面是解决方法的代码,为了使用的方便,写成了一个category
。
@interface UIImageView (URLImage)
- (void)loadRetinaImage: (NSString*) url;
@end
@implementation UIImageView (URLImage)
- (void)loadRetinaImageWithURL:(NSString*)urlStr {
NSURL *url = [NSURL URLWithString:urlStr];
NSData *data = [NSData dataWithContentsOfURL:url];
if (data == nil) {
NSLog(@"Failed to load data from URL: %@", urlStr);
return;
}
UIImage *image = [UIImage imageWithData:data];
//Resample the image to be for retina
image = [UIImage imageWithCGImage:[image CGImage]
scale:[UIScreen mainScreen].scale
orientation:UIImageOrientationUp];
self.image = image;
}
@end
这个方案的重点是 [UIImage imageWithCGImage]
。 这个方法会设置图片为retina,等价于图片命名有@2x
后缀。
30 Nov 2015
看到这篇blog记录下来
一、UIWindow是一种特殊的UIView,通常在一个程序中只会有一个UIWindow,但可以手动创建多个UIWindow,同时加到程序里面。UIWindow在程序中主要起到三个作用:
作为容器,包含app所要显示的所有视图
传递触摸消息到程序中view和其他对象
与UIViewController协同工作,方便完成设备方向旋转的支持
二、通常我们可以采取两种方法将view添加到UIWindow中:
addSubview
直接将view通过addSubview方式添加到window中,程序负责维护view的生命周期以及刷新,但是并不会为view添加对应的ViewController,因此采用这种方法将view添加到window以后,我们还要保持view对应的ViewController的有效性,不能过早释放。
rootViewController时UIWindow的一个遍历方法,通过设置该属性为要添加view对应的ViewController,UIWindow将会自动将其view添加到当前window中,同时负责ViewController和view的生命周期的维护,防止其过早释放
三、WindowLevel
UIWindow在显示的时候会根据UIWindowLevel进行排序的,即Level高的将排在所有Level比他低的层级的前面。下面我们来看UIWindowLevel的定义:
const UIWindowLevel UIWindowLevelNormal;
const UIWindowLevel UIWindowLevelAlert;
const UIWindowLevel UIWindowLevelStatusBar;
typedef CGFloat UIWindowLevel;
IOS系统中定义了三个window层级,其中每一个层级又可以分好多子层级(从UIWindow的头文件中可以看到成员变量CGFloat _windowSublevel;),不过系统并没有把则个属性开出来。UIWindow的默认级别是UIWindowLevelNormal,我们打印输出这三个level的值分别如下:
2012-03-27 22:46:08.752 UIViewSample[395:f803] Normal window level: 0.000000
2012-03-27 22:46:08.754 UIViewSample[395:f803] Alter window level: 2000.000000
2012-03-27 22:46:08.755 UIViewSample[395:f803] StatusBar window level: 1000.000000
这样印证了他们级别的高低顺序从小到大为Normal < StatusBar < Alert,下面请看小的测试代码:
TestWindowLevel
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.window.backgroundColor = [UIColor yellowColor];
[self.window makeKeyAndVisible];
UIWindow *normalWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
normalWindow.backgroundColor = [UIColor blueColor];
normalWindow.windowLevel = UIWindowLevelNormal;
[normalWindow makeKeyAndVisible];
CGRect windowRect = CGRectMake(50,
50,
[[UIScreen mainScreen] bounds].size.width - 100,
[[UIScreen mainScreen] bounds].size.height - 100);
UIWindow *alertLevelWindow = [[UIWindow alloc] initWithFrame:windowRect];
alertLevelWindow.windowLevel = UIWindowLevelAlert;
alertLevelWindow.backgroundColor = [UIColor redColor];
[alertLevelWindow makeKeyAndVisible];
UIWindow *statusLevelWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 50, 320, 20)];
statusLevelWindow.windowLevel = UIWindowLevelStatusBar;
statusLevelWindow.backgroundColor = [UIColor blackColor];
[statusLevelWindow makeKeyAndVisible];
NSLog(@"Normal window level: %f", UIWindowLevelNormal);
NSLog(@"Normal window level: %f", UIWindowLevelAlert);
NSLog(@"Normal window level: %f", UIWindowLevelStatusBar);
return YES;
}
运行结果如下图:
我们可以注意到两点:
我们生成的normalWindow虽然是在第一个默认的window之后调用makeKeyAndVisible,但是仍然没有显示出来。这说明当Level层级相同的时候,只有第一个设置为KeyWindow的显示出来,后面同级的再设置KeyWindow也不会显示。
statusLevelWindow在alertLevelWindow之后调用makeKeyAndVisible,淡仍然只是显示在alertLevelWindow的下方。这说明UIWindow在显示的时候是不管KeyWindow是谁,都是Level优先的,即Level最高的始终显示在最前面。
30 Nov 2015
最近业务需求要做一个TextField的号码输入格式化,如电话号输入的时候344分组插空格。对UITextField的委托方法又熟悉了一下,每次要用的时候,都要看一遍,对基础掌握不够牢固啊,所以记下来,以后好查找。
UITextFielddelegate委托方法注释:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
//返回一个BOOL值,指定是否循序文本字段开始编辑
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField{
//开始编辑时触发,文本字段将成为first responder
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
//返回BOOL值,指定是否允许文本字段结束编辑,当编辑结束,文本字段会让出first responder
//要想在用户结束编辑时阻止文本字段消失,可以返回NO
//这对一些文本字段必须始终保持活跃状态的程序很有用,比如即时消息
return NO;
}
- (BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
//当用户使用自动更正功能,把输入的文字修改为推荐的文字时,就会调用这个方法。
//这对于想要加入撤销选项的应用程序特别有用
//可以跟踪字段内所做的最后一次修改,也可以对所有编辑做日志记录,用作审计用途。
//要防止文字被改变可以返回NO
//这个方法的参数中有一个NSRange对象,指明了被改变文字的位置,建议修改的文本也在其中
return YES;
}
- (BOOL)textFieldShouldClear:(UITextField *)textField{
//返回一个BOOL值指明是否允许根据用户请求清除内容
//可以设置在特定条件下才允许清除内容
return YES;
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
//返回一个BOOL值,指明是否允许在按下回车键时结束编辑
//如果允许要调用resignFirstResponder 方法,这回导致结束编辑,而键盘会被收起
[textField resignFirstResponder];//查一下resign这个单词的意思就明白这个方法了
return YES;
}
30 Nov 2015
NSURLProtocol的使用讲解
开发iOS的应用一定离不开网络。iOS的常用网络框架主要分为两种:基于NSURLConnection和基于CFNetwork。基于NSURLConnection的有apple原生和AFNetworking等,基于CFNetwork框架有ASIHttpRequest等。而NSURLProtocol能够拦截处理基于NSURLConnection的一切网络请求和UIWebView ,但是对于基于CFNetwork的网络请求没有作用。
什么是NSURLProtocol?
NSURLProtocol is an abstract class which provides the basic structure for performing protocol-specific loading of URL data.
它是一个抽象类,为载入URL的data的一些特定协议提供基础的结构。
NSURLProtocol是URL加载系统中的的协议支持部分,它功能强大却晦涩。它是一个抽象类,在使用的使用必须子类化来实现新的或者定制已经存在的URL加载行为,实现自己业务的需求。
NSURLProtocol的使用举例
拦截图片加载请求,转为从本地文件加载
为了测试对HTTP返回内容进行mock和stub
对发出请求的header进行格式化
对发出的媒体请求进行签名
创建本地代理服务,用于数据变化时对URL请求的更改
故意制造畸形或非法返回数据来测试程序的鲁棒性
过滤请求和返回中的敏感信息
在既有协议基础上完成对 NSURLConnection 的实现且与原逻辑不产生矛盾
NSURLProtocol的核心思想是 通过使用它,不用改变网络调用的其他部分,就可以改变URL加载行为的全部细节。简言之,NSURLProtocol就是一个苹果允许的网络调用的中间人。
NSURLProtocol的使用方法
使用NSURLProtocol必须先子类化,否则不能使用。
注册自定义的子类,代码如下
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//注册protocol
[NSURLProtocol registerClass:[CustomURLProtocol class]];
return YES;
}
子类化时要override以下方法,逻辑顺序如下:
以上方法并不是全部可以overide方法,还有很多其他的方法,可以实现更加强大的功能。
几点注意:
URLProtocol会被以注册顺序的反序访问,所以自己写的protocol比其他内建的protocol拥有更高的优先级。
无论对webView还是native的,只要是基于NSURLConnection的网络请求的,可以根据相关特征进行URL拦截并处理。
扩展阅读
NSURLProtocol
NSURLProtocol与NSURLProtocolClient简介
iOS开发之— NSURLProtocol
使用NSURLProtocol拦截替换http请求
NSURLProtocol Tutorial