说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

盘点一些iOS开发技巧:Swift和Objective-C

HTML文档下载 WORD文档下载 PDF文档下载
对苹果开发者来讲,2014年是令人难以置信的一年。在这短短的一年中发生了如此多的变化:在充满吸引力的Swift面前,我们几乎忘了之前是如何痴迷OC;以及充满想象力的iOS8和WatchKit,难以想象还有什么API能与之相比。

回顾过去一年发生在我们身边的事情时,有一点不得不提:对苹果开发者来讲,2014年是令人难以置信的一年。在这短短的一年中(有关APP的开发)发生了如此多的变化:在充满吸引力的Swift面前,我们几乎忘了之前是如何痴迷于Objective-C;以及充满想象力的iOS 8和WatchKit,难以想象还有什么API能与之相比。


NSHipster的惯例:请可爱的童鞋们,在新年的第一天,为大家展示你们(在开发中)常使用的技巧和方法。如今,随着来自Cupertino(苹果总部,位于旧金山)和众多开源社区的一系列API的涌现,妈妈再也不用担心我们找不到有趣的东西来分享啦!

在此,感谢以下童鞋们所做的贡献:

Colin Rofls、Cédric Luthi、Florent Pillet、Heath Borders、Joe Zobkiw、Jon Friskics、Justin Miller、Marcin Matczuk、Mikael Konradsson、Nolan O'Brien、Robert Widmann、Sachin Palewar、Samuel Defago、Sebastian Wittenkamp、Vadim Shpakovski、Zak。

成员函数的使用技巧(来自Robert Widmann)

在用静态方式调用Swift类和结构中的成员函数时,通常使用以下格式:

Object->(参数)->Things

比如,你可以用以下两种方式调用reverse():

[1,2,3,4].reverse( )Array.reverse([1,2,3,4])

用@()来封装C字符串(来自Samuel Defago)

事实上文字大部分时候是数字和字母的集合,使用C字符串,尤其当我在使用运行时编码的时候,我常常会忘记用UTF8编码、以NULL结束:Objective-C字符串封装:

NSString *propertyAttributesString =    @(property_getAttributes(class_getProperty([NSObject class], "description")));// T@"NSString",R,C

AmIBeingDebugged

Nolan O'Brien在这篇Q&A技术文档中让我们注意到了AmIBeingDebugged函数方法:

#include <assert.h>#include <stdbool.h>#include <sys/types.h>#include <unistd.h>#include <sys/sysctl.h>static Bool AmIBeingDebugged(void) {    int mib[4];    struct kinfo_proc info;    size_t size = sizeof(info);    info.kp_proc.p_flag = 0;    mib[0] = CTL_KERN;    mib[1] = KERN_PROC;    mib[2] = KERN_PROC_PID;    mib[3] = getpid();    sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);    return (info.kp_proc.p_flag & P_TRACED) != 0;}

使用延迟存储属性(来自Colin Rofls)

在开发过程中,应该避免使用Optionals类型,更不应该使用隐式解包optionals类型。你想声明一个var变量却不想给一个初始值?使用“lazy”吧,唯一要注意的就是:在你的属性被赋值之前不要调用getter方法即可(童叟无欺!)

lazy var someModelStructure = ExpensiveClass()

假如你仅仅对这var变量调用set方法,而没有调用getter方法的话,这个被lazy修饰的var变量不会被赋值。例如,用lazy修饰那些直到viewDidLoad时才需要初始化的views变量就会非常合适。

获取Storyboard视图容器里的子视图控制器(来自Vadim Shpakovski)

有一个比较方便的方法来获取故事板视图容器里的子视图控制器:

// 1. A property has the same name as a segue identifier in XIB@property (nonatomic) ChildViewController1 *childController1;@property (nonatomic) ChildViewController2 *childController2;// #pragma mark - UIViewController- (void)prepareForSegue:(UIStoryboardSegue *)segue                 sender:(id)sender{    [super prepareForSegue:segue sender:sender];     // 2. All known destination controllers assigned to properties    if ([self respondsToSelector:NSSelectorFromString(segue.identifier)]) {        [self setValue:segue.destinationViewController forKey:segue.identifier];    }}- (void)viewDidLoad {    [super viewDidLoad];    // 3. Controllers already available bc viewDidLoad is called after prepareForSegue    self.childController1.view.backgroundColor = [UIColor redColor];    self.childController2.view.backgroundColor = [UIColor blueColor];}

重复运行项目,不重复构建项目(来自Heath Borders)

假如你一直在不停地调试同一个问题,你可以在不重复构建的情况下运行你的APP,这样:“Product>Perform Action>Run without Building” 

快速获取Playground资源(来自Jon Friskics)

Swift里的所有Playground共享相同的数据目录:/Users/HOME/Documents/Shared Playground Data

如果你喜欢使用很多Playgrounds,你将需要在上述共享目录下为每个Playground新建对应的子目录,来存储每个Playground用到的数据;但是那之后你需要告诉每个Playground在哪儿可以获取其对应的数据。下面是我常用的一个辅助解决方法:

func pathToFileInSharedSubfolder(file: String) -> String {    return XCPSharedDataDirectoryPath + "/" + NSProcessInfo.processInfo().processName + "/" + file}

processName属性是Playground文件的名字,因此只要你已经在Playground数据共享文件目录下以相同的名字新建了一个子目录,那么你可以很容易访问这些数据,和读取本地JSON数据一样:

var jsonReadError:NSError?let jsonData = NSFileManager.defaultManager().contentsAtPath(pathToFileInSharedSubfolder("data.json"))!let jsonArray = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &jsonReadError) as [AnyObject]

....或者访问本地图片

let imageView = UIImageView()imageView.image = UIImage(contentsOfFile: pathToFileInSharedSubfolder("image.png"))

Please attention!本篇文章剩余的部分来自Cédric Luthi大神的贡献,他分享了一些比较有用的开发技巧和技术,这些内容足够自成一篇,值得细细品读。这里再次感谢Cédric!

CocoaPods大揭秘

这儿有一个快速的方法来检查APP里用到的所有pods:

$ class-dump -C Pods_ /Applications/Squire.app | grep -o "Pods_\w+"

CREATE_INFOPLIST_SECTION_IN_BINARY

注意Xcode中为命令模式APP(command-line apps)设置的CREATE_INFOLIST_SECTION_IN_BINARY属性。这比使用-sectcreate__TEXT__info_plist链接标志位更加容易,前者还把已经编译好的Info.plist文件嵌入在二进制编码中。

关于如何向苹果提需求,它也给我们上了一课,这个特性需求早在2006年的 rdar://4722772 被提出,但直到7年后才被满足。

(译者注:言外之意是它是反面教材,应该更有技巧的提需求)

禁用dylib钩子(来自Sam Marshall)

Sam Marshall这个技巧可谓是走自己的路,让黑客无路可走。

在你的“Other Linker Flags”里加上下面这行:

-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null

NSBundle -preferredLocalizations

某些时候,你需要知道APP当前使用的是什么语言。通常,大家会使用NSLocal+preferredLanguages. 可惜的是这个方法不会告诉你APP实际呈现的文字语种。你仅仅会得到iOS系统里“Settings->General->Language&Region->Preferred Language”列表中的选项,或者OSX系统里“System Preferences->Language & Region->Preferred Languages”列表中的选项。想象一下:优先语言列表中只有{英语,法语},但你的APP仅使用德语;调用[[NSLocal preferredLanguages] firstObject]返回给你的是英语,而不是德语。

正确的方法是用[[NSBundle mainBundle] preferredLocalizations]方法。

苹果的开发文档是这样说的:

一个包含了在bundle中本地化的语言ID的NSString对象的数组,里面的字符串排序是根据用户的语言偏好设置和可使用的地理位置而来的。

NSBundle.h里的备注:

一个bundle中本地化的子集,重新排序到当前执行坏境的优先序列里,main bundle的语言顺序中最前面的是用户希望在UI界面上看到的语种。

当然你也许需要调用这个方法:

NSLocal+canonicalLanguageIdentifierFromString:

来确保你使用的文字语种是规范的语种。

保护SDK头文件

如果你用dmg安装Xcode,那么看看这篇Joar Wingfors的文章,它讲述了如何通过保留所有权来避免SDK头文件被意外修改:

$ sudo ditto /Volumes/Xcode/Xcode.app /Applications/Xcode.app

任意类型的实例变量检测

为了达到逆向处理的目的,查询对象的实例变量是一个常见可靠的途径。通常调用对象valueForKey:方法就能达到这一目的,除了少数重写了类方法+accessInstanceVariablesDirectly的类屏蔽了该操作。

下面是一个例子:当实例变量有一个为任意类型的属性时,上述提到的操作无效

这是iOS6.1 SDK中MediaPlayer 框架的一段引用:

@interface MPMoviePlayerController : NSObject {    void *_internal;    // 4 = 0x4    BOOL _readyForDisplay;  // 8 = 0x8}

因为 id internal=[moviePlayerController valueForKey:@”internal”] 无效,下面有一个笨办法来取得这个变量:

id internal = *((const id*)(void*)((uintptr_t)moviePlayerController + sizeof(Class)));

注意!不要随意调用这段代码,因为ivar的布局可能改变(指针偏移量计算可能出错)。仅在逆向工程中使用!

NSDateFormatter +dateFormatFromTemplate:options:locale:

友情提示:假如你调用[NSDateFormatter setDateFormat],而没有调用[NSDateFormatter dateFormatFromTemplate:options:local:],n那么很可能出错。

苹果文档:

+ (NSString *)dateFormatFromTemplate:(NSString *)template                             options:(NSUInteger)opts                              locale:(NSLocale *)locale

不同地区有不同的日期格式。使用这个方法的目的:得到指定地区指定日期字段的一个合适的格式(通常你可以通过currentLocal查看当前所属地区)

下面这个例子给我们表现了英式英语和美式英语不同的日期格式:

NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];NSLocale *gbLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"]; NSString *dateFormat;NSString *dateComponents = @"yMMMMd"; dateFormat = [NSDateFormatter dateFormatFromTemplate:dateComponents options:0 locale:usLocale];NSLog(@"Date format for %@: %@",    [usLocale displayNameForKey:NSLocaleIdentifier value:[usLocale localeIdentifier]], dateFormat); dateFormat = [NSDateFormatter dateFormatFromTemplate:dateComponents options:0 locale:gbLocale];NSLog(@"Date format for %@: %@",    [gbLocale displayNameForKey:NSLocaleIdentifier value:[gbLocale localeIdentifier]], dateFormat); // Output:// Date format for English (United States): MMMM d, y// Date format for English (United Kingdom): d MMMM y

通过调试获取内部常量

近期,Matthias Tretter在Twitter上问到:

有人知道在iOS8里modal viewController presentation的默认动画时间和跳转方式吗?

我们在UIKit的类库中发现了这样一个函数:[UITransitionView defaultDurationForTransition:],并在这个方法的位置加一个断点:

(lldb) br set -n "+[UITransitionView defaultDurationForTransition:]"
模态显示一个viewController,就会停在这个断点,输入finish执行该方法:

(lldb)finish
在defaultDurationForTransition:被执行时,你就能读到结果(在xmm0寄存器里)

(lldb) register read xmm0 --format float64    xmm0 = {0.4 0}
回复:默认动画时间0.4s

DIY 弱关联对象

不幸的是,关联对象OBJC_ASSOCIATION_ASSIGN策略不支持引用计数为0的弱引用。幸运的是,你可以很容易实现它,你仅仅需要一个简单的类,并在这个类里弱引用一个对象:

@interface WeakObjectContainter : NSObject@property (nonatomic, readonly, weak) id object;@end@implementation WeakObjectContainter- (instancetype)initWithObject:(id)object {    self = [super init];    if (!self) {        return nil;    }    self.object = object;    return self;}@end
然后,通过OBJC_ASSOCIATION_RETAIN(_NONATOMIC)关联WeakObjectContainter:

objc_setAssociatedObject(self, &MyKey, [[WeakObjectContainter alloc] initWithObject:object], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
用object属性指向这个所需的引用计数为0的弱引用对象。

id object = [objc_getAssociatedObject(self, &MyKey) object];

英文文章来源:NSHipster,译文出自:CocoaChina

(责编/刘璐璐)

开源移动统计:Cobub Razor近期版本大升级 无人机应用,为何屡遭苹果拒绝 2013年Java继续火的五大理由 Rails所有版本都有SQL注入漏洞?其实没那么严重 如何设置Windows Server 2012 NTFS权限 智能手机大局已定 HTC难扭转乾坤? 比谷歌手表更酷!基于大数据分析的睡衣 众投资金:改变了移动游戏开发的一切一切 这些科技产品和革新或在今年“横空出世”?! 现代Objective-C七宗罪 Google工程总监Ray Kurzweil意欲打造“虚拟朋友” 惠普开源JavaScript框架Enyo更新:支持桌面和移动平台 分析:三星或将成为科技行业第五巨头 是真的 诺基亚真有可能推Android手机 如何打造IE10的指尖触碰式用户体验 SUSE全球OEM联盟总监:为何SAP HANA只选择SUSE? 推荐2013年最佳PHP开发框架 Patrick Wyatt:代码没问题 程序却有bug? NoSQL的可靠性及扩展操作 最新Skype加密技术:“无声”通话能躲过FBI监听 谷歌锁死SDK,能阻止Android碎片化吗? KitCam团队专访:为应用做加法也能雄踞榜首 谷歌哭了:Replicant 4.0 SDK发布搅乱大局 忍者神龟与禅宗启示:如何突破移动广告困境 Linux会是更好的游戏平台?暴雪是这么认为的! 新型恶意软件瞄准Java服务器 AWS被纳为“战略物资”市值或可达到300亿美元? 十张图带你入门Map/Reduce 低端Android野心,Intel发布Atom Z2420处理器 淘宝网的技术发展史(一)——个人网站时代 看Pinterest如何通过架构变化将EC2成本降低了62% 我的MATRIX观----生命的究极存在形式 关闭窗口的问题 因为昨天晚上的积极表现。 我的真情告白·!#¥%…… 遇到了“Destination host unreachable.”,谁能简单的帮我分析一下出错的可能性。 关于安装windoew 2003的初级问题.解决立刻给分. 如何在LISTVIEW里输出打印? 现在你应该睡了~ 困了,睡觉去~~~~~~~~~ 有没有可能在outlook express中加入自已的按钮? 有没有可能在outlook express中加入自已的按钮? 一个sql表达式的问题 JBUILDER9中用代码改变程序的外观, 难?易?,如何写,见贴内,谢谢! 我的电脑里的g盘分区损坏(磁盘坏道)请问有没有补救的方法? 谁有培训教材,单位培训的?? 印章问题?? 如何实现文件上传?在线急等!!! 如何查询出数据库中相同的字段值??? 可以动态改变水晶报表的文本的内容吗? ASP.net提示无法调试 我下载了Fastreport 2.47的中文版,可是不知道怎么用! 请问我在VB.NET里面控制,把SQL里面的数据输出到Excel,但是有一列是000开头的,到Excel后怎么000就不见了呢? 哪位老大有asp.net和.net平台的电子书?可否共享一下? 请问JDK1.4里面主要包括哪些类包 一个初学者的问题? 计算机间发送消息的问题。 请教各位前辈KEIL C51调试的问题 DataGrid控件中如何用selectindexchang方法改变选中的行的颜色》 SOS!今天我的PB7.0里面的Library 和 DB Profile不能用了.(100分) Application 怎样接收参数,并传给窗体?谢谢! vb中执行access里面的查询 请高手详细指点,我的服务器win2000---server,现在想安装WIN2003--SERVER(在同一台服务器),把AD从2000server导出来,在到2003server 为什么要使用内存dc? 高手请告诉我wrox出版的《jsp编程指南》中的例子怎么用 (vital) JTable的两个问题??? 好久不来了,不过一有问题就想到这了,有劳各位了(分不够再加) 请问学J2EE如何学,工具及书籍如何选? ###救命啊:PB+EAServer 实现WEB的问题:这是我的PB不行吗? 上海日記:撞車 [***分享***]DBGRIDEH 组件在Borland开发工具中应用全攻略 上海日記:撞車解決了 如何去掉信使服务? Win98的开始菜单中的“运行”不见了,请问如何恢复? 各位大哥帮忙,这个公司要我的一段设计文档什么的 难题!DCOM中能不能固定某个端口,或某段端口 ████在水晶报表8.5里面如何控制打印尺寸████ 我要关机!!! 哪个大侠有活动下拉菜单的源代码(----急啊 關於i18n和taglib的問題 linux 下的lilo 源代码 我尝试用gcc -O3 lili.c 结果出错 对日软件外包公司大调查!!!!! classical series是什么意思 series-products是什么意思 watch-series是什么意思 汽车进入隧道有异响声音汽车在每次进入隧道的时候,我都能清晰的听到就像是路面有很多小碎石子打击在我轮子上面挡泥板的声音,滋滋滋那种,在隧道里面就一直有声音,出了隧道就没有了, 青岛隧道车最晚几点 小车进入一般的隧道前准备什么工作 二元二次函数求极值的方法函数f(x)=x+y-4x+4,判定其是有最大值还是有最小值,并求出极值. 仿照我喜欢的作文动物篇加天空森林海洋 这是什么线子 已知圆O是四边形ABCD的内切圆求证:AB+CD=AD+BC 任意四边形的中点四边形是什么形状?为什么? 日本自卫队下月将出动逾3万人 演练登杭州有小区物业费每月每平方米涨了两分澳洲林火因澳部队实弹演习引发 强风致奶粉进药店多问题待解 本周开始安装售宁波海曙区已有五个社区无主车“清零”美耶鲁大学19岁大二学生欲徒步闯南极墨西哥一家美国公司糖果厂爆炸20人失美国海军基地再发枪击案 2人受伤枪手美国义诊团感受中国医疗现状 吁加强健环球小姐决赛即将举行 佳丽泳装展示傲世界最高大的狗在美国去世 存活年龄为Ottimo致悦“新锐新势力”武汉站下一篇需要法律威慑新果拍出天价4S店插足二手车弱连接珠江人寿保险电商平台上线主力资金动向(5月13日)104岁阿婆彩票公益金关爱贫困母亲奥迪推出激光大灯
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘