RACSignal*deallocSignal = [[RACSignal zip:@[ self.rac_willDeallocSignal, strongObserver.rac_willDeallocSignal ?: [RACSignal never] ]] doCompleted:^{ // Forces deallocation to wait if the object variables are currently // being read on another thread. [objectLock lock]; @onExit { [objectLock unlock]; }; }];
return [[[RACSignal createSignal:^RACDisposable* (id<RACSubscriber> subscriber) { // Hold onto the lock the whole time we're setting up the KVO // observation, because any resurrection that might be caused by our // retaining below must be balanced out by the time -dealloc returns // (if another thread is waiting on the lock above). [objectLock lock]; @onExit { [objectLock unlock]; }; __strong NSObject*observer __attribute__((objc_precise_lifetime)) = weakObserver; __strong NSObject*self __attribute__((objc_precise_lifetime)) = weakSelf; if (self==nil) { [subscriber sendCompleted]; returnnil; } return [self rac_observeKeyPath:keyPath options:options observer:observer block:^(id value, NSDictionary*change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { [subscriber sendNext:RACTuplePack(value, change)]; }]; }] takeUntil:deallocSignal] setNameWithFormat:@"%@ -rac_valueAndChangesForKeyPath: %@ options: %lu observer: %@", self.rac_description, keyPath, (unsigned long)options, strongObserver.rac_description]; }
RACSignal*deallocSignal = [[RACSignal zip:@[ self.rac_willDeallocSignal, strongObserver.rac_willDeallocSignal ?: [RACSignal never] ]] doCompleted:^{ // Forces deallocation to wait if the object variables are currently // being read on another thread. [objectLock lock]; @onExit { [objectLock unlock]; }; }];
sed -i '''s/ProvisioningStyle = Automatic;/ProvisioningStyle = Manual;/g' \ ${WORKSPACE}/${PROJECT_NAME}.xcodeproj/project.pbxproj
sed -i '''s/DEVELOPMENT_TEAM = .*;/DEVELOPMENT_TEAM = "";/g' \ ${WORKSPACE}/${PROJECT_NAME}.xcodeproj/project.pbxproj
#动态生成 Build Version sed -i ''"/<key>CFBundleVersion<\/key>/{N;s/<string>.*<\/string>/<string>${BUILD_VERSION}<\/string>/g;}" \ ${WORKSPACE}/${PROJECT_NAME}/${PROJECT_NAME}-Info.plist
Dynamic dispatch means that program has to determine at run time which method or property is being referred to and then perform an indirect call or indirect access.
我们都知道 Swift 的 class 是可以被继承,function 和 property 是可以被重写的,而这就意味着 Swift 需要 dynamic dispatch 这种机制来完成这些功能。Swift 的 dynamic dispatch 首先会再 method table 查找方法,然后间接调用。很明显这种方式要比直接调用的效率慢,并且用间接调用的方式还会阻止编译器的一些优化无法实现。
那么应该怎么优化呢?
当我们明确的知道 class、function、property 是不需要 overridden,我们可以通过使用 final 和 private(fileprivate) 这些关键字减少动态派发的发生,从而有效的提高效率。
在 Swift 中,如果被 final 或 private(fileprivate) 修饰的 class、function、property 是不能 overridden,并且调用这些 class、function、property 的时候不再通过 dynamic dispatch 去间接调用,而是直接调用。
所以,通过在必要的代码中使用 final 或 private(fileprivate) 这些关键字进行优化的话,将可以有效提高的效率。
Whole Module Optimization
Swift 的 class、function、property 的默认权限都是 internal ,除非我们明确的加上 public 或 private(fileprivate) 关键字才能改变它们的默认权限。
Efficiency is equivalent to that of Array, unless Element is a class or @objc protocol type, in which case using ContiguousArray may be more efficient.
# 1"B.h" # 1"<built-in>"1 # 1"<built-in>"3 # 329"<built-in>"3 # 1"<command line>"1 # 1"<built-in>"2 # 1"B.h"2 # 1"./A.h"1 # 1"./B.h"1 # 1"./A.h"1 # 1"./B.h"1 ... ... # 1"./A.h"1 # 1"./B.h"1 In file included from ./B.h:1: In file included from ./A.h:1: In file included from ./B.h:1: In file included from ./A.h:1: ... ... In file included from ./B.h:1: In file included from ./A.h:1: ./A.h:1:10: error: #include nested too deeply #include"B.h" ^
接下来还需要递归的把每个头文件的内容展开,最后的结果就是一行代码变成超过11000行代码。如果有多个文件都包含来 UIKit 的头文件,这样就会让每个文件的体积都会变得很大,编译过程也会变得越来越慢。这种递归的方式会让项目的编译时间变成:M source files + N headers => M x N compile time。