Reader Submissions -New Year's 2013

为了庆祝即将到来的 year++,我觉得编译一个_你们_最喜爱的tips和tricks的列表一定很好玩——给你们所有人一个机会展示你的NSHipster能力。

感谢Cédric LuthiJason KozemczakJeff KelleyJoel ParsonsMaximilian TagherRob MayoffVadim Shpakovski,同时感谢@alextudanswering the call的_完美_提交。

在Category中关联对象

第一条tip简直太棒了,被你们提到了两次,分别是 Jason KozemczakJeff Kelley提名的。

Category是Objective-C非常著名的特性,通过它你可以给已存在的类添加新方法。但是鲜为人知的是,你可以通过一些objc运行时的hack给已存在类添加新_属性_,赞!

NSObject+IndieBandName.h

@interface NSObject (IndieBandName)
@property (nonatomic, strong) NSString *indieBandName;
@end

NSObject+IndieBandName.m

#import "NSObject+Extension.h"
#import <objc/runtime.h>

static const void *IndieBandNameKey = &IndieBandNameKey;

@implementation NSObject (IndieBandName)
@dynamic indieBandName;

- (NSString *)indieBandName {
    return objc_getAssociatedObject(self, IndieBandNameKey);
}

- (void)setIndieBandName:(NSString *)indieBandName {
    objc_setAssociatedObject(self, IndieBandNameKey, indieBandName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

通过这种方法,你所有的乐团对象都可以用他们乐队的名字来存储和访问。哦对了,表演在本周三晚上开始,一定要来哦。

这确实是一个很酷的trick,但只应该作为最后选择。当你想这么干的时候,问问你自己这个特别的属性是否能从已有的属性导出、是否能被其他的类管理。

对象关联的一个很好的例子就是AFNetworking在它的UIImageView category中对一个图片请求的operation添加一个属性。

LLDB View Hierarchy Dump

Rob Mayoff用了一个非常隐晦而强大的咒语让debugging view变得如此方便。在你的home目录下建立一个 .lldbinit,如果它之前不存在的话,添加下面的命令:

~/.lldbinit

command regex rd 's/^[[:space:]]*$/po [[[UIApplication sharedApplication] keyWindow] recursiveDescription]/' 's/^(.+)$/po [%1 recursiveDescription]/'

现在你可以用LLDB debugger获取你的应用中任何页面任何view的递归层次了。你可以自己试试,在一个view controller里面设一个断点,然后输入 rd self.view。你会被一些内建UI控制器面纱下面的秘密惊到哦!

用 LLDB 打印 CGPathRef 的内容

当我们还在看关于LLDB的东西时,Rob Mayoff发来了一个很有用的咒语,可以在调试器中打印出 CGPathRef 的内容:

p (void)CGPathPrint(pathRef, 0)

如果你正在做一些复杂的 Core Graphics 绘制,请一定要牢记这个。

+initialize,不用 +load

Vadim Shpakovski给了一些关于类加载和初始化的建议。Objective-C有两个神奇的方法:+load+initialize,这两个方法在类被使用时会自动调用。但是两个方法的不同点会导致应用层面上性能的显著差异。

关于这一点Mike Ash一篇文章解释的非常好:

如果你实现了 +load 方法,那么当类被加载时它会自动被调用。这个调用非常早。如果你实现了一个应用或框架的 +load,并且你的应用链接到这个框架上了,那么 +load 会在 main() 函数之前被调用。如果你在一个可加载的bundle中实现了 +load,那么它会在bundle加载的过程中被调用。

+initialize 方法的调用看起来会更合理,通常在它里面写代码比在 +load 里写更好。+initialize 很有趣,因为它是懒调用的,也有可能完全不被调用。类第一次被加载时,+initialize 不会被调用。类接收消息时,运行时会先检查 +initialize 有没有被调用过。如果没有,会在消息被处理前调用。

那篇文章太长了根本读不下去?那就直接记住,实现 +initialize,不要实现 +load,你更需要这种智能调用行为。

Xcode Snippets

Maximilian Tagher 大声疾呼Xcode Snippets的好处。

优秀的开发者都以充分了解和最大利用开发工具为荣。无论是好是坏,这都说明了解Xcode就要像了解我们的手背那样熟悉。Objective-C冗长无比,但”少说多干”才是生产力的代表,Xcode Snippets是帮你走上这条路的最佳方法之一。

如果你不知道从哪开始,下载并且fork这些Xcode Snippets

记录完成时间的宏定义

这儿有一个很有用的宏定义,可以非常方便地记录某一块代码的运行时间。本段代码由@alextud提供:

NS_INLINE void MVComputeTimeWithNameAndBlock(const char *caller, void (^block)()) {
    CFTimeInterval startTimeInterval = CACurrentMediaTime();
    block();
    CFTimeInterval nowTimeInterval = CACurrentMediaTime();
    NSLog(@"%s - Time Running is: %f", caller, nowTimeInterval - startTimeInterval);
}

#define MVComputeTime(...) MVComputeTimeWithNameAndBlock(__PRETTY_FUNCTION__, (__VA_ARGS__))

用block写迭代方法

Joel Parsons提交了一个很有用的建议:用 -enumerateObjectsWithOptions:usingBlock: 方法对 NSArray 和其他集合类型进行迭代操作。传一个 NSEnumerationConcurrent 参数,你就可以享受带 NSFastEnumeration 协议的 for..in 那样高效率的并行block迭代了。

但是你要注意,不是所有的迭代都自动是并行执行的,所以千万不要把你所有的 for...in 都不分青红皂白地换成了这种方式,否则你的应用就该不知道在什么地方崩溃啦。

NSString 判断相等方法的逆向工程实现

Cédric Luthi通过NSString 判断相等方法的逆向工程实现展示了他独有的智慧和对Cocoa内部机制的无比了解。很赞!

NSLayoutConstraint.constant 动画

所有Cocoa Auto Layout的粉丝都应该来看看这个,来自Vadim Shpakovski

viewConstraint.constant = <#Constant Value From#>;
[view layoutIfNeeded];

viewConstraint.constant = <#Constant Value To#>;
[view setNeedsUpdateConstraints];

[UIView animateWithDuration:ConstantAnimationDuration animations:^{
     [view layoutIfNeeded];
}];

细心的读者可能已经做好本条的笔记了,顺便说一句,上面这些代码也可以写成一个优秀的Xcode Snippet哦。

打印 NSCache Usage

看完了这么一堆小技巧,我们再次用Cédric Luthi提供的一个小窍门来结尾,这次我们发掘私有方法 cache_print 来窥探NSCache的内部结构:

extern void cache_print(void *cache);

- (void) printCache:(NSCache *)cache {
    cache_print(*((void **)(__bridge void *)cache + 3));
}

这段代码样例只能用在iOS上,并且只能用作debug(提交到Apple Store之前要移除这些代码!)。


最后再次感谢这段时间提交建议的每个人。类似的活动肯定还会有的,所以请随时发给我你们最喜爱的和Objective-C之间的琐事、各种框架的奥秘、Xcode的隐藏功能之类的你认为对于一个@NSHipster来说很酷的东西!

最后,感谢各位读者,因为有你们的支持NSHipster才能走过本年度如此完美的最后几个月。我们在2013年有很多特别赞的想法,并且非常想分享给你。

作者 Mattt
Mattt

Mattt (@mattt) is a writer and developer in Portland, Oregon. He is the founder of NSHipster and Flight School, and the creator of several open source libraries, including AFNetworking and Alamofire.

翻译者
Croath Liu

云游四海的工程师

下一篇文章

理解“不存在”的概念不仅仅是一个哲学的问题,也是一个实际的问题。我们是 有形 宇宙的居民,而原因在于逻辑宇宙的存在不确定性。作为一个逻辑系统的物理体现,电脑面临一个棘手的问题,就是如何用 存在 表达 不存在 .