重庆迈尖科技有限公司
2018-06-29 82ad101839771e904ebbe6e4b83e01281bc27e77
weex
27个文件已修改
223个文件已添加
30854 ■■■■ 已修改文件
MIduo.xcodeproj/project.pbxproj 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo.xcworkspace/xcuserdata/mj.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/AppDelegate.m 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/PrefixHeader.pch 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/Common.h 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/WeexDomain/Component/WXCutomNewStrategyComponent.h 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/WeexDomain/Component/WXCutomNewStrategyComponent.m 201 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/WeexDomain/Module/WXUserModule.h 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/WeexDomain/Module/WXUserModule.m 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/WeexDomain/Module/WXUtilModule.h 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/数据/WeexDomain/Module/WXUtilModule.m 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/我的/MineViewController.m 358 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/网页视图/WeexNativeController.h 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/网页视图/WeexNativeController.m 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo/界面/网页视图/商品详情/GoodDeTrViewController.m 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Podfile 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Podfile.lock 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Local Podspecs/ReactiveCocoa.podspec.json 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Manifest.lock 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/project.pbxproj 10086 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/Pods-MIduo.xcscheme 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/ReactiveCocoa.xcscheme 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/SDAutoLayout.xcscheme 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/SDCycleScrollView.xcscheme 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/SDWebImage.xcscheme 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/SVProgressHUD.xcscheme 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/UICollectionViewLeftAlignedLayout.xcscheme 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/WeexSDK.xcscheme 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/YYCache.xcscheme 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/YYImage.xcscheme 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/YYKeyboardManager.xcscheme 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/YYModel.xcscheme 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/YYText.xcscheme 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/YYWebImage.xcscheme 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/LICENSE.md 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/README.md 553 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/MKAnnotationView+RACSignalSupport.h 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/MKAnnotationView+RACSignalSupport.m 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSArray+RACSequenceAdditions.h 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSArray+RACSequenceAdditions.m 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSData+RACSupport.h 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSData+RACSupport.m 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSDictionary+RACSequenceAdditions.h 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSDictionary+RACSequenceAdditions.m 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSEnumerator+RACSequenceAdditions.h 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSEnumerator+RACSequenceAdditions.m 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSFileHandle+RACSupport.h 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSFileHandle+RACSupport.m 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSIndexSet+RACSequenceAdditions.h 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSIndexSet+RACSequenceAdditions.m 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSInvocation+RACTypeParsing.h 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSInvocation+RACTypeParsing.m 232 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSNotificationCenter+RACSupport.h 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSNotificationCenter+RACSupport.m 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACDeallocating.h 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACDeallocating.m 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACDescription.h 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACDescription.m 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACKVOWrapper.h 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACKVOWrapper.m 213 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACLifting.h 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACLifting.m 142 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACPropertySubscribing.h 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACPropertySubscribing.m 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACSelectorSignal.h 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACSelectorSignal.m 330 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSOrderedSet+RACSequenceAdditions.h 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSOrderedSet+RACSequenceAdditions.m 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSSet+RACSequenceAdditions.h 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSSet+RACSequenceAdditions.m 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSString+RACKeyPathUtilities.h 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSString+RACKeyPathUtilities.m 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSString+RACSequenceAdditions.h 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSString+RACSequenceAdditions.m 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSString+RACSupport.h 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSString+RACSupport.m 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSURLConnection+RACSupport.h 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSURLConnection+RACSupport.m 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSUserDefaults+RACSupport.h 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/NSUserDefaults+RACSupport.m 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACArraySequence.h 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACArraySequence.m 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACBehaviorSubject.h 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACBehaviorSubject.m 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACBlockTrampoline.h 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACBlockTrampoline.m 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACChannel.h 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACChannel.m 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACCommand.h 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACCommand.m 267 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACCompoundDisposable.h 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACCompoundDisposable.m 239 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACCompoundDisposableProvider.d 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACDelegateProxy.h 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACDelegateProxy.m 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACDisposable.h 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACDisposable.m 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACDynamicSequence.h 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACDynamicSequence.m 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACDynamicSignal.h 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACDynamicSignal.m 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACEagerSequence.h 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACEagerSequence.m 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACEmptySequence.h 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACEmptySequence.m 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACEmptySignal.h 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACEmptySignal.m 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACErrorSignal.h 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACErrorSignal.m 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACEvent.h 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACEvent.m 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACGroupedSignal.h 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACGroupedSignal.m 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACImmediateScheduler.h 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACImmediateScheduler.m 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACIndexSetSequence.h 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACIndexSetSequence.m 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACKVOChannel.h 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACKVOChannel.m 208 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACKVOProxy.h 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACKVOProxy.m 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACKVOTrampoline.h 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACKVOTrampoline.m 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACMulticastConnection+Private.h 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACMulticastConnection.h 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACMulticastConnection.m 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACObjCRuntime.h 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACObjCRuntime.m 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACPassthroughSubscriber.h 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACPassthroughSubscriber.m 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACQueueScheduler+Subclass.h 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACQueueScheduler.h 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACQueueScheduler.m 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACReplaySubject.h 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACReplaySubject.m 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACReturnSignal.h 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACReturnSignal.m 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACScheduler+Private.h 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACScheduler+Subclass.h 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACScheduler.h 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACScheduler.m 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACScopedDisposable.h 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACScopedDisposable.m 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSequence.h 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSequence.m 384 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSerialDisposable.h 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSerialDisposable.m 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSignal+Operations.h 709 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSignal+Operations.m 1482 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSignal.h 219 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSignal.m 450 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSignalProvider.d 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSignalSequence.h 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSignalSequence.m 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACStream+Private.h 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACStream.h 335 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACStream.m 377 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACStringSequence.h 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACStringSequence.m 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSubject.h 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSubject.m 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriber+Private.h 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriber.h 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriber.m 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriptingAssignmentTrampoline.h 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriptingAssignmentTrampoline.m 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriptionScheduler.h 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriptionScheduler.m 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACTargetQueueScheduler.h 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACTargetQueueScheduler.m 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACTestScheduler.h 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACTestScheduler.m 223 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACTuple.h 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACTuple.m 252 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACTupleSequence.h 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACTupleSequence.m 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACUnarySequence.h 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACUnarySequence.m 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACUnit.h 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACUnit.m 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACValueTransformer.h 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/RACValueTransformer.m 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/ReactiveCocoa.h 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIActionSheet+RACSignalSupport.h 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIActionSheet+RACSignalSupport.m 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIAlertView+RACSignalSupport.h 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIAlertView+RACSignalSupport.m 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIBarButtonItem+RACCommandSupport.h 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIBarButtonItem+RACCommandSupport.m 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIButton+RACCommandSupport.h 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIButton+RACCommandSupport.m 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UICollectionReusableView+RACSignalSupport.h 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UICollectionReusableView+RACSignalSupport.m 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIControl+RACSignalSupport.h 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIControl+RACSignalSupport.m 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIControl+RACSignalSupportPrivate.h 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIControl+RACSignalSupportPrivate.m 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIDatePicker+RACSignalSupport.h 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIDatePicker+RACSignalSupport.m 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIGestureRecognizer+RACSignalSupport.h 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIGestureRecognizer+RACSignalSupport.m 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIImagePickerController+RACSignalSupport.h 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIImagePickerController+RACSignalSupport.m 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIRefreshControl+RACCommandSupport.h 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIRefreshControl+RACCommandSupport.m 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UISegmentedControl+RACSignalSupport.h 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UISegmentedControl+RACSignalSupport.m 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UISlider+RACSignalSupport.h 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UISlider+RACSignalSupport.m 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIStepper+RACSignalSupport.h 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UIStepper+RACSignalSupport.m 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UISwitch+RACSignalSupport.h 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UISwitch+RACSignalSupport.m 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UITableViewCell+RACSignalSupport.h 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UITableViewCell+RACSignalSupport.m 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UITableViewHeaderFooterView+RACSignalSupport.h 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UITableViewHeaderFooterView+RACSignalSupport.m 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UITextField+RACSignalSupport.h 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UITextField+RACSignalSupport.m 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UITextView+RACSignalSupport.h 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/UITextView+RACSignalSupport.m 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/extobjc/RACEXTKeyPathCoding.h 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/extobjc/RACEXTRuntimeExtensions.h 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/extobjc/RACEXTRuntimeExtensions.m 234 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/extobjc/RACEXTScope.h 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/ReactiveCocoa/ReactiveCocoa/extobjc/RACmetamacros.h 666 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/SDAutoLayout/LICENSE 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/SDAutoLayout/README.md 182 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/SDAutoLayout/SDAutoLayoutDemo/SDAutoLayout/SDAutoLayout.h 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/SDAutoLayout/SDAutoLayoutDemo/SDAutoLayout/UITableView+SDAutoTableViewCellHeight.h 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/SDAutoLayout/SDAutoLayoutDemo/SDAutoLayout/UITableView+SDAutoTableViewCellHeight.m 537 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/SDAutoLayout/SDAutoLayoutDemo/SDAutoLayout/UIView+SDAutoLayout.h 484 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/SDAutoLayout/SDAutoLayoutDemo/SDAutoLayout/UIView+SDAutoLayout.m 1825 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/Pods-MIduo/Pods-MIduo-acknowledgements.markdown 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/Pods-MIduo/Pods-MIduo-acknowledgements.plist 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/Pods-MIduo/Pods-MIduo-frameworks.sh 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/Pods-MIduo/Pods-MIduo.debug.xcconfig 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/Pods-MIduo/Pods-MIduo.release.xcconfig 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/ReactiveCocoa/Info.plist 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa-dummy.m 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa-prefix.pch 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa-umbrella.h 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa.modulemap 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa.xcconfig 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/SDAutoLayout/Info.plist 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/SDAutoLayout/SDAutoLayout-dummy.m 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/SDAutoLayout/SDAutoLayout-prefix.pch 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/SDAutoLayout/SDAutoLayout-umbrella.h 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/SDAutoLayout/SDAutoLayout.modulemap 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Pods/Target Support Files/SDAutoLayout/SDAutoLayout.xcconfig 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MIduo.xcodeproj/project.pbxproj
@@ -615,6 +615,10 @@
        2D47AB2520E21186008BB5C9 /* ShareSDK.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 2D47AB0F20E21186008BB5C9 /* ShareSDK.bundle */; };
        2D47AB2620E21186008BB5C9 /* ShareSDKConnector.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D47AB1020E21186008BB5C9 /* ShareSDKConnector.framework */; };
        2D47AB2B20E235EC008BB5C9 /* FileSignature.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D47AB2A20E235EC008BB5C9 /* FileSignature.m */; };
        2D4A107620E49B3600AB72DE /* WXUserModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D4A107520E49B3600AB72DE /* WXUserModule.m */; };
        2D4A107920E4B47E00AB72DE /* WXUtilModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D4A107820E4B47E00AB72DE /* WXUtilModule.m */; };
        2D4A107C20E4C5C000AB72DE /* WeexNativeController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D4A107B20E4C5C000AB72DE /* WeexNativeController.m */; };
        2D4D84CC20E61A750012FDB6 /* WXCutomNewStrategyComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D4D84CB20E61A750012FDB6 /* WXCutomNewStrategyComponent.m */; };
        2D73332320C90D6800336CC8 /* WebP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D73332220C90D6700336CC8 /* WebP.framework */; };
        AD52310E1F1B6A24007FCFA1 /* OrderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD52310D1F1B6A24007FCFA1 /* OrderViewController.m */; };
/* End PBXBuildFile section */
@@ -1747,6 +1751,14 @@
        2D47AB1020E21186008BB5C9 /* ShareSDKConnector.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = ShareSDKConnector.framework; sourceTree = "<group>"; };
        2D47AB2920E235EC008BB5C9 /* FileSignature.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FileSignature.h; sourceTree = "<group>"; };
        2D47AB2A20E235EC008BB5C9 /* FileSignature.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FileSignature.m; sourceTree = "<group>"; };
        2D4A107420E49B3600AB72DE /* WXUserModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WXUserModule.h; sourceTree = "<group>"; };
        2D4A107520E49B3600AB72DE /* WXUserModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WXUserModule.m; sourceTree = "<group>"; };
        2D4A107720E4B47D00AB72DE /* WXUtilModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WXUtilModule.h; sourceTree = "<group>"; };
        2D4A107820E4B47E00AB72DE /* WXUtilModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WXUtilModule.m; sourceTree = "<group>"; };
        2D4A107A20E4C5C000AB72DE /* WeexNativeController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WeexNativeController.h; sourceTree = "<group>"; };
        2D4A107B20E4C5C000AB72DE /* WeexNativeController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WeexNativeController.m; sourceTree = "<group>"; };
        2D4D84CA20E61A750012FDB6 /* WXCutomNewStrategyComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WXCutomNewStrategyComponent.h; sourceTree = "<group>"; };
        2D4D84CB20E61A750012FDB6 /* WXCutomNewStrategyComponent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WXCutomNewStrategyComponent.m; sourceTree = "<group>"; };
        2D73332220C90D6700336CC8 /* WebP.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebP.framework; path = Pods/YYImage/Vendor/WebP.framework; sourceTree = "<group>"; };
        2D9767D720C7D7FE006EE24F /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
        A10E40577F379E83D85926C6 /* Pods_MIduo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MIduo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -3152,6 +3164,8 @@
        1875228D1E654D6900B6AE15 /* ç½‘页视图 */ = {
            isa = PBXGroup;
            children = (
                2D4A107A20E4C5C000AB72DE /* WeexNativeController.h */,
                2D4A107B20E4C5C000AB72DE /* WeexNativeController.m */,
                180DCD951EA85874008EC06B /* XYRWebViewController.h */,
                180DCD961EA85874008EC06B /* XYRWebViewController.m */,
                1875228E1E654D6900B6AE15 /* SureWebViewController.h */,
@@ -3576,6 +3590,7 @@
        18AC53451E5A917C006D1FDF /* æ•°æ® */ = {
            isa = PBXGroup;
            children = (
                2D4A107320E49A8C00AB72DE /* WeexDomain */,
                2D47AB2920E235EC008BB5C9 /* FileSignature.h */,
                2D47AB2A20E235EC008BB5C9 /* FileSignature.m */,
                18AC53831E5A9840006D1FDF /* YTHsharedManger.h */,
@@ -4100,6 +4115,35 @@
            path = Required;
            sourceTree = "<group>";
        };
        2D4A107320E49A8C00AB72DE /* WeexDomain */ = {
            isa = PBXGroup;
            children = (
                2D4D84C820E619320012FDB6 /* Module */,
                2D4D84C920E619920012FDB6 /* Component */,
            );
            path = WeexDomain;
            sourceTree = "<group>";
        };
        2D4D84C820E619320012FDB6 /* Module */ = {
            isa = PBXGroup;
            children = (
                2D4A107420E49B3600AB72DE /* WXUserModule.h */,
                2D4A107520E49B3600AB72DE /* WXUserModule.m */,
                2D4A107720E4B47D00AB72DE /* WXUtilModule.h */,
                2D4A107820E4B47E00AB72DE /* WXUtilModule.m */,
            );
            path = Module;
            sourceTree = "<group>";
        };
        2D4D84C920E619920012FDB6 /* Component */ = {
            isa = PBXGroup;
            children = (
                2D4D84CA20E61A750012FDB6 /* WXCutomNewStrategyComponent.h */,
                2D4D84CB20E61A750012FDB6 /* WXCutomNewStrategyComponent.m */,
            );
            path = Component;
            sourceTree = "<group>";
        };
        3EB2FCBC06FCFF59022C5ECD /* Frameworks */ = {
            isa = PBXGroup;
            children = (
@@ -4356,6 +4400,8 @@
                "${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework",
                "${BUILT_PRODUCTS_DIR}/MJRefresh/MJRefresh.framework",
                "${BUILT_PRODUCTS_DIR}/Masonry/Masonry.framework",
                "${BUILT_PRODUCTS_DIR}/ReactiveCocoa/ReactiveCocoa.framework",
                "${BUILT_PRODUCTS_DIR}/SDAutoLayout/SDAutoLayout.framework",
                "${BUILT_PRODUCTS_DIR}/SDCycleScrollView/SDCycleScrollView.framework",
                "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework",
                "${BUILT_PRODUCTS_DIR}/SVProgressHUD/SVProgressHUD.framework",
@@ -4375,6 +4421,8 @@
                "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MBProgressHUD.framework",
                "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MJRefresh.framework",
                "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Masonry.framework",
                "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactiveCocoa.framework",
                "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDAutoLayout.framework",
                "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDCycleScrollView.framework",
                "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework",
                "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SVProgressHUD.framework",
@@ -4432,6 +4480,7 @@
                1810FBFC1E7FBDBB005B42B3 /* SideSlipBaseTableViewCell.m in Sources */,
                1897D9BA1E5FDB70003DF6FE /* searchTableViewCell.m in Sources */,
                1896F25D1FD0E652009D6EEF /* classificationViewController.m in Sources */,
                2D4A107620E49B3600AB72DE /* WXUserModule.m in Sources */,
                1845C510209C562E009C639B /* ZXQRCodeFinderPatternFinder.m in Sources */,
                1845C4BD209C562E009C639B /* ZXRSSExpandedBlockParsedResult.m in Sources */,
                187522291E6526AE00B6AE15 /* CLLockVC.m in Sources */,
@@ -4572,6 +4621,7 @@
                187522901E654D6900B6AE15 /* SureWebViewController.m in Sources */,
                18D399AD1EA765AD00A01CD3 /* thirdClassificationViewController.m in Sources */,
                1897D99C1E5FCFAD003DF6FE /* RedPacketDetailTableViewCell.m in Sources */,
                2D4A107C20E4C5C000AB72DE /* WeexNativeController.m in Sources */,
                1845C514209C562E009C639B /* ZXQRCodeEncoder.m in Sources */,
                1845C507209C562E009C639B /* ZXQRCodeDecoderMetaData.m in Sources */,
                18826A991F3C4C9C00A8E7B5 /* XWFilterAnimator+XWMod.m in Sources */,
@@ -4644,6 +4694,7 @@
                18E5AE041E5EC9DB009F85E0 /* SettingTypeTwoTableViewCell.m in Sources */,
                18D3E3001FEB6C32001F29F5 /* userInfoTableViewCellS1.m in Sources */,
                18D4305A1E7A30770007CCB5 /* FilterBaseCollectionViewCell.m in Sources */,
                2D4A107920E4B47E00AB72DE /* WXUtilModule.m in Sources */,
                1845C497209C562D009C639B /* ZXRGBLuminanceSource.m in Sources */,
                18D430631E7A3AD90007CCB5 /* SideSlipPriceTableViewCell.m in Sources */,
                1845C486209C562D009C639B /* ZXGridSampler.m in Sources */,
@@ -4721,6 +4772,7 @@
                18826A8D1F3C4C9C00A8E7B5 /* XWCoolAnimator+XWLines.m in Sources */,
                1845C452209C562D009C639B /* ZXBizcardResultParser.m in Sources */,
                1845C476209C562D009C639B /* ZXMonochromeRectangleDetector.m in Sources */,
                2D4D84CC20E61A750012FDB6 /* WXCutomNewStrategyComponent.m in Sources */,
                1845C4D4209C562E009C639B /* ZXCode39Writer.m in Sources */,
                1892034020BE51C6008C1045 /* LBXScanNetAnimation.m in Sources */,
                1845C4B3209C562E009C639B /* ZXAI013103decoder.m in Sources */,
@@ -5027,6 +5079,7 @@
            buildSettings = {
                ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
                ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
                CLANG_ENABLE_OBJC_WEAK = YES;
                CODE_SIGN_ENTITLEMENTS = MIduo/MIduo.entitlements;
                DEVELOPMENT_TEAM = 98HSDT7AP4;
                ENABLE_BITCODE = NO;
@@ -5143,6 +5196,7 @@
            buildSettings = {
                ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
                ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
                CLANG_ENABLE_OBJC_WEAK = YES;
                CODE_SIGN_ENTITLEMENTS = MIduo/MIduo.entitlements;
                DEVELOPMENT_TEAM = 98HSDT7AP4;
                ENABLE_BITCODE = NO;
MIduo.xcworkspace/xcuserdata/mj.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
New file
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
   type = "0"
   version = "2.0">
   <Breakpoints>
      <BreakpointProxy
         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
         <BreakpointContent
            shouldBeEnabled = "Yes"
            ignoreCount = "0"
            continueAfterRunningActions = "No"
            filePath = "MIduo/&#x6570;&#x636e;/WeexDomain/WXUtilModule.m"
            timestampString = "551950582.96917"
            startingColumnNumber = "9223372036854775807"
            endingColumnNumber = "9223372036854775807"
            startingLineNumber = "135"
            endingLineNumber = "135"
            landmarkName = "-share:"
            landmarkType = "7">
         </BreakpointContent>
      </BreakpointProxy>
      <BreakpointProxy
         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
         <BreakpointContent
            shouldBeEnabled = "Yes"
            ignoreCount = "0"
            continueAfterRunningActions = "No"
            filePath = "MIduo/&#x754c;&#x9762;/&#x9996;&#x9875;/recommendViewController.m"
            timestampString = "551873944.957873"
            startingColumnNumber = "9223372036854775807"
            endingColumnNumber = "9223372036854775807"
            startingLineNumber = "516"
            endingLineNumber = "516"
            landmarkName = "-collectionView:didSelectItemAtIndexPath:"
            landmarkType = "7">
         </BreakpointContent>
      </BreakpointProxy>
      <BreakpointProxy
         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
         <BreakpointContent
            shouldBeEnabled = "Yes"
            ignoreCount = "0"
            continueAfterRunningActions = "No"
            filePath = "MIduo/&#x754c;&#x9762;/&#x7f51;&#x9875;&#x89c6;&#x56fe;/&#x5546;&#x54c1;&#x8be6;&#x60c5;/GoodDeTrViewController.m"
            timestampString = "551873944.958277"
            startingColumnNumber = "9223372036854775807"
            endingColumnNumber = "9223372036854775807"
            startingLineNumber = "290"
            endingLineNumber = "290"
            landmarkName = "-shareClicked:"
            landmarkType = "7">
         </BreakpointContent>
      </BreakpointProxy>
      <BreakpointProxy
         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
         <BreakpointContent
            shouldBeEnabled = "Yes"
            ignoreCount = "0"
            continueAfterRunningActions = "No"
            filePath = "MIduo/&#x754c;&#x9762;/&#x8d2d;&#x7269;&#x8f66;/shoppingCartViewController.m"
            timestampString = "551873944.958539"
            startingColumnNumber = "9223372036854775807"
            endingColumnNumber = "9223372036854775807"
            startingLineNumber = "399"
            endingLineNumber = "399"
            landmarkName = "-webView:shouldStartLoadWithRequest:navigationType:"
            landmarkType = "7">
         </BreakpointContent>
      </BreakpointProxy>
      <BreakpointProxy
         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
         <BreakpointContent
            shouldBeEnabled = "Yes"
            ignoreCount = "0"
            continueAfterRunningActions = "No"
            filePath = "MIduo/&#x6570;&#x636e;/WeexDomain/Component/WXCutomNewStrategyComponent.m"
            timestampString = "551956825.528976"
            startingColumnNumber = "9223372036854775807"
            endingColumnNumber = "9223372036854775807"
            startingLineNumber = "174"
            endingLineNumber = "174"
            landmarkName = "-buttonBack"
            landmarkType = "7">
         </BreakpointContent>
      </BreakpointProxy>
   </Breakpoints>
</Bucket>
MIduo/AppDelegate.m
@@ -49,6 +49,16 @@
#import "SJNComponet.h"
#import "WXImgLoaderDefaultImpl.h"
//#import "WXNavigationDefaultImpl.h"
/****** Weex ******/
// SDK
#import <WeexSDK/WeexSDK.h>
// Module
#import "WXUserModule.h"
#import "WXUtilModule.h"
// Component
#import "WXCutomNewStrategyComponent.h"
@interface AppDelegate ()<UNUserNotificationCenterDelegate,UITabBarControllerDelegate,WXApiDelegate>
@end
@@ -224,7 +234,10 @@
    
    return YES;
}
#pragma mark --- Weex初始化配置 ---
- (void)WeexInit{
    //business configuration
    NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
    //    CFShow(infoDictionary);
@@ -242,13 +255,19 @@
    
    //register custom module and component,optional
    [WXSDKEngine registerComponent:@"navgation" withClass:[SJNComponet class]];
    [WXSDKEngine registerComponent:@"topMenu" withClass:[WXCutomNewStrategyComponent class]];
    [WXSDKEngine registerModule:@"event" withClass:[SJModule class]];
    [WXSDKEngine registerModule:@"userModule" withClass:[WXUserModule class]];
    [WXSDKEngine registerModule:@"utilModule" withClass:[WXUtilModule class]];
    //register the implementation of protocol, optional
    [WXSDKEngine registerHandler:[WXImgLoaderDefaultImpl new] withProtocol:@protocol(WXImgLoaderProtocol)];
    
    //set the log level
    [WXLog setLogLevel: WXLogLevelAll];
    // è®¾ç½®æ—¥å¿—级别
    [WXLog setLogLevel:WXLogLevelError];
}
- (void)loginDeviceToken{
    
    NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
@@ -325,8 +344,11 @@
    [dic setObject:@"1" forKey:@"page"];
    [dic setObject:[[NSUserDefaults standardUserDefaults] objectForKey:@"userId"] forKey:@"uid"];
    
    [JYNetWorking Post:[NSString stringWithFormat:@"%@/%@",domainHTTP,@"customer/findAccountMessageList"] param:dic success:^(NSDictionary *object) {
        NSLog(@"%@",object);
    [JYNetWorking Post:[NSString stringWithFormat:@"%@/%@",domainHTTP,@"customer/findAccountMessageList"]
                 param:dic
               success:^(NSDictionary *object) {
        ALLog(@"%@",object);
        //        NSInteger code = [object[@"code"]integerValue];
        NSDictionary *dic = object[@"data"];
        NSArray *array = dic[@"list"];
MIduo/PrefixHeader.pch
@@ -14,6 +14,5 @@
#import "Common.h"
//#import <Foundation/Foundation.h>
//#import <UIKit/UIKit.h>
#import "FileSignature.h"
#endif /* PrefixHeader_pch */
MIduo/Êý¾Ý/Common.h
@@ -30,6 +30,13 @@
#import "NSString+YTH.h"
#import "UIImageView+YTH.h"
// ç­¾å
#import "FileSignature.h"
// æŽ§ä»¶è‡ªé€‚应
#import "SDAutoLayout.h"
// RAC
#import <ReactiveCocoa/ReactiveCocoa.h>
#import <AlibabaAuthSDK/ALBBSDK.h>         //淘宝登录
#import <WXApi.h>                          //微信登录
@@ -131,6 +138,8 @@
// 2.用代码形式代码
#define UIColorFromRGBValue(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
#define UICOLOR_FROM_RGB(rgbValue,trans) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:trans]
// 3.屏幕宽高
#define KScreenHp [[UIScreen mainScreen] bounds].size.height*1.0 // å±å¹•高度
#define KScreenWp [[UIScreen mainScreen] bounds].size.width*1.0 // å±å¹•宽度
@@ -173,9 +182,25 @@
// 6.每张图片前面的前缀
#define ImageUrl @"http://sovideo.cn:8080/BuWan"
// Log输出格式
// 7.Log输出格式
#ifdef DEBUG
#define ALLog(...) NSLog(@"%s ç¬¬%d行 \n %@\n\n",__func__,__LINE__,[NSString stringWithFormat:__VA_ARGS__])
#else
#define ALLog(...)
#endif
// --------------- å„种宽高 -------------
// å±å¹•宽高
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
// å·¥å…·æ é«˜åº¦
#define TAB_BAR_HEIGHT self.tabBarController.tabBar.frame.size.height
// å¯¼èˆªæ é«˜åº¦+状态栏高度
#define NAV_STATUS_BAR_HEIGHT ([[UIApplication sharedApplication] statusBarFrame].size.height + self.navigationController.navigationBar.frame.size.height)
// çŠ¶æ€æ é«˜åº¦
#define STATUS_BAR_HEIGHT [[UIApplication sharedApplication] statusBarFrame].size.height
// å¯¼èˆªæ é«˜åº¦
#define NAV_BAR_HEIGHT 44
// åŠ è½½æœ¬åœ°å›¾ç‰‡
#define ALIMAGE_NAMED(name)[UIImage imageNamed:name]
MIduo/Êý¾Ý/WeexDomain/Component/WXCutomNewStrategyComponent.h
New file
@@ -0,0 +1,13 @@
//
//  WXCutomNewStrategyComponent.h
//  MIduo
//
//  Created by é‡åº†è¿ˆå°–科技有限公司 on 2018/6/29.
//  Copyright Â© 2018å¹´ yeshi. All rights reserved.
//
#import <WeexSDK/WeexSDK.h>
@interface WXCutomNewStrategyComponent : WXComponent
@end
MIduo/Êý¾Ý/WeexDomain/Component/WXCutomNewStrategyComponent.m
New file
@@ -0,0 +1,201 @@
//
//  WXCutomNewStrategyComponent.m
//  MIduo
//
//  Created by é‡åº†è¿ˆå°–科技有限公司 on 2018/6/29.
//  Copyright Â© 2018å¹´ yeshi. All rights reserved.
//
#import "WXCutomNewStrategyComponent.h"
@interface WXCutomNewStrategyComponent ()
/// èƒŒæ™¯
@property (nonatomic, strong, nullable) UIView *navView;
/// å·¦æŒ‰é’®
@property (nonatomic, strong, nullable) UIButton *buttonBack;
/// æ ‡é¢˜
@property (nonatomic, strong, nullable) UILabel *labelTitle;
/// ç°çº¿
@property (nonatomic, strong, nullable) UIView *line;
/// title
@property (nonatomic, copy, nullable) NSString *title;
@end
@implementation WXCutomNewStrategyComponent
@synthesize weexInstance;
- (instancetype)initWithRef:(NSString *)ref
                       type:(NSString *)type
                     styles:(NSDictionary *)styles
                 attributes:(NSDictionary *)attributes
                     events:(NSArray *)events
               weexInstance:(WXSDKInstance *)weexInstance {
    self = [super initWithRef:ref
                         type:type
                       styles:styles
                   attributes:attributes
                       events:events
                 weexInstance:weexInstance];
    if (self) {
        // å›žåˆ°ä¸»çº¿ç¨‹è°ƒç”¨æ–¹æ³•
        dispatch_async(dispatch_get_main_queue(), ^{
            [self viewConfig];
        });
        if (attributes[@"title"]) {
            self.title = attributes[@"title"];
        }
    }
    return self;
}
#pragma mark --- é…ç½®è§†å›¾ ---
- (void)viewConfig {
    // if (!([self.weexInstance.viewController isKindOfClass:[MeController class]])) {
    [self.navView addSubview:self.buttonBack];
    self.buttonBack.sd_layout
    .leftSpaceToView(self.navView, 0)
    .bottomSpaceToView(self.navView, 0)
    .heightIs(44)
    .widthIs(60);
    // }
    [self.navView addSubview:self.labelTitle];
    self.labelTitle.sd_layout
    .leftSpaceToView(self.navView, 80)
    .rightSpaceToView(self.navView, 80)
    .heightIs(44)
    .bottomSpaceToView(self.navView, 0);
    // [self.navView addSubview:self.line];
    // self.line.sd_layout
    // .leftSpaceToView(self.navView, 0)
    // .rightSpaceToView(self.navView, 0)
    // .bottomSpaceToView(self.navView, 0)
    // .heightIs(0.5);
}
- (UIView *)loadView {
    [super loadView];
    UIView *views = [[UIView alloc] init];
    CGRect rect;
    if (IsiPhoneX) {
        rect = CGRectMake(0, 0, SCREEN_WIDTH, 88);
    } else {
        rect = CGRectMake(0, 0, SCREEN_WIDTH, 64);
    }
    views.frame = rect;
    [views addSubview:self.navView];
    return views;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    self.labelTitle.text = self.title;
}
- (void)updateAttributes:(NSDictionary *)attributes {
    [super updateAttributes:attributes];
    if (attributes[@"title"]) {
        self.title = attributes[@"title"];
        self.labelTitle.text = self.title;
    }
}
#pragma mark --- æ‡’加载 ---
- (UIView *)navView {
    if (!_navView) {
        _navView = [[UIView alloc] init];
        _navView.backgroundColor = YTHColor(229, 0, 92);
        CGRect rect;
        if (IsiPhoneX) {
            rect = CGRectMake(0, 0, SCREEN_WIDTH, 88);
        } else {
            rect = CGRectMake(0, 0, SCREEN_WIDTH, 64);
        }
        _navView.frame = rect;
    }
    return _navView;
}
- (UIButton *)buttonBack {
    if (!_buttonBack) {
        _buttonBack = [UIButton buttonWithType:UIButtonTypeCustom];
        UIImageView *imgViewBack = [[UIImageView alloc] init];
        imgViewBack.image = ALIMAGE_NAMED(@"第二版返回按钮");
        [_buttonBack addSubview:imgViewBack];
        CGFloat imaWidth = imgViewBack.image.size.width;
        CGFloat imaHeight = imgViewBack.image.size.height;
        imgViewBack.frame = CGRectMake(8, (44 - imaHeight) / 2, imaWidth, imaHeight);
        @weakify(self)
        [[_buttonBack rac_signalForControlEvents:UIControlEventTouchUpInside]
         subscribeNext:^(UIButton *button) {
             @strongify(self)
             [self.weexInstance.viewController.navigationController popViewControllerAnimated:YES];
         }];
    }
    return _buttonBack;
}
- (UILabel *)labelTitle {
    if (!_labelTitle) {
        _labelTitle = [[UILabel alloc] init];
        _labelTitle.textColor = [UIColor whiteColor];
        _labelTitle.font = [UIFont boldSystemFontOfSize:17.0];
        _labelTitle.textAlignment = NSTextAlignmentCenter;
    }
    return _labelTitle;
}
- (UIView *)line {
    if (!_line) {
        _line = [[UIView alloc] init];
        _line.backgroundColor = UICOLOR_FROM_RGB(0x000000, 0.3);
    }
    return _line;
}
@end
MIduo/Êý¾Ý/WeexDomain/Module/WXUserModule.h
New file
@@ -0,0 +1,14 @@
//
//  WXUserModule.h
//  MIduo
//
//  Created by é‡åº†è¿ˆå°–科技有限公司 on 2018/6/28.
//  Copyright Â© 2018å¹´ yeshi. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <WeexSDK/WeexSDK.h>
@interface WXUserModule : NSObject <WXModuleProtocol>
@end
MIduo/Êý¾Ý/WeexDomain/Module/WXUserModule.m
New file
@@ -0,0 +1,35 @@
//
//  WXUserModule.m
//  MIduo
//
//  Created by é‡åº†è¿ˆå°–科技有限公司 on 2018/6/28.
//  Copyright Â© 2018å¹´ yeshi. All rights reserved.
//
#import "WXUserModule.h"
@implementation WXUserModule
@synthesize weexInstance;
WX_EXPORT_METHOD_SYNC(@selector(getUserInfo))
WX_EXPORT_METHOD(@selector(login))
#pragma mark --- èŽ·å–ç”¨æˆ·ä¿¡æ¯ ---
- (NSString *)getUserInfo {
    NSString *str = @"测试信息";
    return str;
}
#pragma mark --- è·³è½¬åˆ°ç™»å½•界面 ---
- (void)login {
    LoginViewController *LoginVC = [[LoginViewController alloc] init];
    LoginVC.hidesBottomBarWhenPushed = YES;
    [weexInstance.viewController.navigationController pushViewController:LoginVC animated:YES];
}
@end
MIduo/Êý¾Ý/WeexDomain/Module/WXUtilModule.h
New file
@@ -0,0 +1,14 @@
//
//  WXUtilModule.h
//  MIduo
//
//  Created by é‡åº†è¿ˆå°–科技有限公司 on 2018/6/28.
//  Copyright Â© 2018å¹´ yeshi. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <WeexSDK/WeexSDK.h>
@interface WXUtilModule : NSObject <WXModuleProtocol>
@end
MIduo/Êý¾Ý/WeexDomain/Module/WXUtilModule.m
New file
@@ -0,0 +1,144 @@
//
//  WXUtilModule.m
//  MIduo
//
//  Created by é‡åº†è¿ˆå°–科技有限公司 on 2018/6/28.
//  Copyright Â© 2018å¹´ yeshi. All rights reserved.
//
#import "WXUtilModule.h"
#import "ShonpingShareViewController.h"
#import "SureWebViewController.h"
#import "GoodDeTrViewController.h"
#define Version [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]  //build号
#define Package @"com.yeshi.ec.RebateTicket"  //相当于包名
@implementation WXUtilModule
@synthesize weexInstance;
/// ç”Ÿæˆç­¾å
WX_EXPORT_METHOD_SYNC(@selector(getSign:))
/// è·³è½¬åˆ°å•†å“è¿‡åº¦é¡µ
WX_EXPORT_METHOD(@selector(jumpGoodsSplash:))
/// è·³è½¬åŽŸæœ‰çš„å•†å“è¯¦æƒ…
WX_EXPORT_METHOD(@selector(jumpGoodsDetail:))
/// è·³è½¬ç½‘页
WX_EXPORT_METHOD(@selector(jumpWeb:))
/// åˆ†äº«
WX_EXPORT_METHOD(@selector(share:))
/// ç»“束当前页面
WX_EXPORT_METHOD(@selector(finishPage))
#pragma mark --- ç”Ÿæˆç­¾å ---
- (NSString *)getSign:(NSString *)result {
    // å°†JSON字符串转化为NSData类型
    NSData *data = [result dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *tempParms = [NSJSONSerialization JSONObjectWithData:data
                                                              options:0
                                                                error:nil];
    NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithDictionary:tempParms];
    NSString *sign = [self sortingDictionaryWithdic:dic];
    return sign;
}
- (NSString *)sortingDictionaryWithdic:(NSDictionary *)dic {
    NSMutableArray *array = @[].mutableCopy;
    for (NSInteger index = 0; index < dic.allKeys.count; index ++) {
        [array addObject:[NSString stringWithFormat:@"%@=%@",dic.allKeys[index],dic.allValues[index]]];
    }
    NSArray *resultArray = [array sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        /*
         æŽ’序结果
         NSComparisonResult resuest = [obj1 compare:obj2];为从小到大,即升序;
         NSComparisonResult resuest = [obj2 compare:obj1];为从大到小,即降序;
         æ³¨æ„:compare方法是区分大小写的,即按照ASCII排序
         */
        //排序操作
        NSComparisonResult resuest = [obj1 compare:obj2];
        return resuest;
    }];
    ALLog(@"resultArray:%@",resultArray);
    NSString *resultString = @"";
    for (NSInteger index = 0; index < resultArray.count; index ++) {
        if (index == 0) {
            resultString = [NSString stringWithFormat:@"%@",resultArray[index]];
            continue;
        }
        resultString = [NSString stringWithFormat:@"%@&%@",resultString,resultArray[index]];
    }
    resultString = [resultString stringByAppendingString:@"&buXiNjie2017!"];
    resultString = [NSString md5:resultString];
    return resultString;
}
#pragma mark --- è·³è½¬åˆ°å•†å“è¿‡åº¦é¡µ ---
- (void)jumpGoodsSplash:(NSString *)taobaoGoodsID {
    GoodDeTrViewController *goodsDetailVC = [[GoodDeTrViewController alloc]init];
    goodsDetailVC.hidesBottomBarWhenPushed = YES;
    goodsDetailVC.goodsID = taobaoGoodsID;
    [weexInstance.viewController.navigationController pushViewController:goodsDetailVC animated:YES];
}
#pragma mark --- è·³è½¬åŽŸæœ‰å•†å“è¯¦æƒ… ---
- (void)jumpGoodsDetail:(NSString *)goodsID {
    SureWebViewController *webView=[[SureWebViewController alloc] init];
    [webView backClicked:^(NSString *string) {
    }];
    webView.goodsId = goodsID;
    webView.canDownRefresh = YES;
    webView.isGoodsDetail = YES;
    webView.hidesBottomBarWhenPushed = YES;
    [weexInstance.viewController.navigationController pushViewController:webView animated:YES];
}
#pragma mark --- è·³è·³è½¬ç½‘页 ---
- (void)jumpWeb:(NSString *)url {
    ShonpingShareViewController *shopVC = [[ShonpingShareViewController alloc]init];
    shopVC.urlString = url;
    shopVC.hidesBottomBarWhenPushed=YES;
    [weexInstance.viewController.navigationController pushViewController:shopVC animated:YES];
}
#pragma mark --- åˆ†äº« ---
- (void)share:(NSString *)type {
}
#pragma mark --- å€Ÿç»“束当前页面 ---
- (void)finishPage {
    [weexInstance.viewController.navigationController popViewControllerAnimated:YES];
}
@end
MIduo/½çÃæ/ÎÒµÄ/MineViewController.m
@@ -40,6 +40,9 @@
#import "MineThirdTableViewCell.h"
#import "shoppingCartViewController.h"
#import "SJFirstLessonsViewController.h"
#import "WeexNativeController.h"
#define Version [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]  //build号
#define Package @"com.yeshi.ec.RebateTicket"  //相当于包名
@interface MineViewController ()<UITableViewDelegate,UITableViewDataSource,LXAlertViewDelegate>{
@@ -99,6 +102,7 @@
}
- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor=XYRBackgroundColor;
    
    //初始化数据
@@ -125,7 +129,8 @@
    [dic setObject:[[NSUserDefaults standardUserDefaults] objectForKey:@"userId"] forKey:@"uid"];
    
    [JYNetWorking Post:[NSString stringWithFormat:@"%@/%@",domainHTTP,@"customer/findAccountMessageList"] param:dic success:^(NSDictionary *object) {
        NSLog(@"%@",object);
        ALLog(@"object:%@",object);
        //        NSInteger code = [object[@"code"]integerValue];
        NSDictionary *dic = object[@"data"];
        NSArray *array = dic[@"list"];
@@ -183,9 +188,8 @@
    }];
    
}
/**
 å®šåˆ¶å¯¼èˆªæ 
 */
#pragma mark --- å®šåˆ¶å¯¼èˆªæ  ---
-(void)CreatNavigationBar{
    //设置按钮
    UIView *messageView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 30, 30)];
@@ -218,20 +222,21 @@
    self.navigationController.navigationBar.titleTextAttributes=@{NSForegroundColorAttributeName:[UIColor whiteColor],NSFontAttributeName:[UIFont boldSystemFontOfSize:15]};
}
/**
 åˆ›å»ºTableView
 */
#pragma mark --- åˆ›å»ºTableView ---
-(void)CreatTableView{
    if (!_MineTableView) {
        _MineTableView=[[UITableView alloc] initWithFrame:CGRectMake(0, -10, KScreenW, KScreenH-kToolBarH-kStatusBarH) style:UITableViewStylePlain];
        _MineTableView.delegate=self;
        _MineTableView.dataSource=self;
        _MineTableView.estimatedRowHeight = 0;
        _MineTableView.estimatedSectionFooterHeight = 0;
        _MineTableView.estimatedSectionHeaderHeight = 0;
        _MineTableView.tableFooterView=[UIView new];
        _MineTableView.backgroundColor=[UIColor clearColor];
        _MineTableView.separatorStyle = UITableViewCellSelectionStyleNone;
        _MineTableView.showsVerticalScrollIndicator=NO;
//        _MineTableView.showsHorizontalScrollIndicator=NO;
//        _MineTableView.bounces = NO;
        //注册cell
        [_MineTableView registerNib:[UINib nibWithNibName:@"MineRedEnvelopesTableViewCell" bundle:nil] forCellReuseIdentifier:@"MineRedEnvelopesTableViewCell"];
@@ -378,13 +383,13 @@
    [dic setValue:[[NSUserDefaults standardUserDefaults] objectForKey:@"userId"] forKey:@"id"];
    
    [JYNetWorking Post:[NSString stringWithFormat:@"%@/%@",domainHTTP,@"customer/getuserinfo"] param:dic success:^(NSDictionary *object) {
        _userInfo = object[@"data"][@"user"];//保存当前用户信息
        self.userInfo = object[@"data"][@"user"];//保存当前用户信息
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(LogOutForTaoBao) name:@"MineViewController" object:nil];//监听退出登录的通知
        [self loginDeviceToken];
        //存储获取到的数据
        NSData *data=[NSKeyedArchiver archivedDataWithRootObject:_userInfo];
        NSData *data=[NSKeyedArchiver archivedDataWithRootObject:self.userInfo];
        [data writeToFile:USERINFO atomically:YES];
        [_MineTableView reloadData];//刷新
        [self->_MineTableView reloadData];//刷新
    
    } fail:^(id object) {
        
@@ -467,21 +472,31 @@
    MineThirdTableViewCell ç‚¹å‡»äº‹ä»¶
 */
#pragma mark --- æ–°æ‰‹æ”»ç•¥ ---
- (void)noviceTaped:(UIButton *)sender{
    XYRWebViewController *specialJumpVC=[[XYRWebViewController alloc] init];
    specialJumpVC.url=[YTHsharedManger startManger].weexUrlString;
    specialJumpVC.canDownRefresh=YES;
    specialJumpVC.backToRedBag=^(){
        
    };
    specialJumpVC.hidesBottomBarWhenPushed=YES;
    [self.navigationController pushViewController:specialJumpVC animated:YES];
    //    SJFirstLessonsViewController * firstVC = [[SJFirstLessonsViewController alloc]init];
//    firstVC .hidesBottomBarWhenPushed = YES;
//    [self.navigationController pushViewController:firstVC animated:YES];
    //    XYRWebViewController *specialJumpVC=[[XYRWebViewController alloc] init];
    //
    //    specialJumpVC.url=[YTHsharedManger startManger].weexUrlString;
    //    specialJumpVC.canDownRefresh=YES;
    //    specialJumpVC.backToRedBag=^(){
    //
    //    };
    //    specialJumpVC.hidesBottomBarWhenPushed = YES;
    //
    //    [self.navigationController pushViewController:specialJumpVC animated:YES];
    WeexNativeController *weexNativeVc = [[WeexNativeController alloc] init];
    weexNativeVc.urlString = @"http://192.168.1.122:9000/weex/gonglue.js";
    weexNativeVc.hidesBottomBarWhenPushed = YES;
    [self.navigationController pushViewController:weexNativeVc animated:YES];
}
#pragma mark --- å¸®åŠ©ä¸­å¿ƒ ---
- (void)helpTaped:(UIButton *)sender{
    XYRWebViewController *SureWebVC=[[XYRWebViewController alloc] init];
    SureWebVC.url=[[NSUserDefaults standardUserDefaults] objectForKey:@"help"];
    SureWebVC.backToRedBag=^(){
@@ -491,6 +506,7 @@
    [self.navigationController pushViewController:SureWebVC animated:YES];
}
#pragma mark --- è”系客服 ---
- (void)serviceTaped:(UIButton *)sender{
    
    ServiceViewController *serviceVC=[[ServiceViewController alloc] init];
@@ -499,11 +515,14 @@
}
#pragma mark --- è´­ç‰©è½¦ ---
- (void)buyCarTaped:(UIButton *)sender{
    shoppingCartViewController * shopCarVC = [[shoppingCartViewController alloc]init];
    shopCarVC.hidesBottomBarWhenPushed = YES;
    [self.navigationController pushViewController:shopCarVC animated:YES];
}
#pragma mark -LXAlertViewDelegate
- (void)lxAlertView:(LXAlertView *)alertView withButtonIndex:(NSInteger)buttonIndex{
    if (buttonIndex==780) {//不登录
@@ -528,19 +547,31 @@
#pragma mark -UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    if (indexPath.section==0) {
        if(indexPath.row==0){
            return 120;
        }else if(indexPath.row==1){
            return 68;
        }
    }else if(indexPath.section==1){
        return 100;
    }
    if (indexPath.section == 2) {
        if (indexPath.row == 0) {
            return 100;
        }else{
            return 50;
        }
    }
@@ -548,55 +579,73 @@
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    if (section>1) {
        return 8;
    }else{
        return CGFLOAT_MIN;
    }
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    return CGFLOAT_MIN;
}
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
    UIView *headerView=[[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenW, 8)];
    headerView.backgroundColor=[UIColor clearColor];
    return headerView;
}
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath{
    if(indexPath.section==0){
        if(indexPath.row==0){
            return NO;
        }
    }else if(indexPath.section==1){
        return NO;
    }
    return YES;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    if (indexPath.section==0) {
        switch (indexPath.row) {
            case 1:{//我的红包
            case 1: {
                // æˆ‘的红包
//                RedEnvelopesViewController *RedEnvelopesVC=[[RedEnvelopesViewController alloc] init];
//                RedEnvelopesVC.hidesBottomBarWhenPushed=YES;
//                [self.navigationController pushViewController:RedEnvelopesVC animated:YES];
               
                if ([[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]!=nil) {
                    BalanceViewController *balanceVC=[[BalanceViewController alloc] init];
                    balanceVC.hidesBottomBarWhenPushed=YES;
                    balanceVC.datasource = _userInfo;
                    [self.navigationController pushViewController:balanceVC animated:YES];
                }else{
                    //登录界面
                    LoginViewController *LoginVC=[[LoginViewController alloc] init];
                    LoginVC.hidesBottomBarWhenPushed=YES;
                    [self.navigationController pushViewController:LoginVC animated:YES];
                }
                
                    [self.navigationController pushViewController:balanceVC animated:YES];
                } else {
                    [self onLogin];
                }
            }
                break;
            default:
@@ -604,17 +653,20 @@
        }
        
    }else if (indexPath.section==2){
        switch (indexPath.row) {
            case 1:{
                if ([[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]!=nil) {
                    ComplainViewController *complainVC=[[ComplainViewController alloc] init];
                    complainVC.hidesBottomBarWhenPushed=YES;
                    [self.navigationController pushViewController:complainVC animated:YES];
                }else{
                    //登录界面
                    LoginViewController *LoginVC=[[LoginViewController alloc] init];
                    LoginVC.hidesBottomBarWhenPushed=YES;
                    [self.navigationController pushViewController:LoginVC animated:YES];
                    [self onLogin];
                }
               
            }break;
@@ -622,12 +674,13 @@
            case 2:{
                //分享有好礼
                if([[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]!=nil){
                    MainInviteViewController *mianVC = [[MainInviteViewController alloc]init];
                    
//                    XYRWebViewController *webView=[[XYRWebViewController alloc] init];
//                    webView.url = [NSString stringWithFormat:@"%@?id=%@",[[NSUserDefaults standardUserDefaults] objectForKey:@"haoli"],[[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]];;
//                    webView.canDownRefresh = YES;
//                    webView.canshare = YES;
                    // ebView.canshare = YES;
//                    webView.backToRedBag = ^{
//
//                    };
@@ -635,67 +688,91 @@
                    mianVC.hidesBottomBarWhenPushed=YES;
                    
                    [self.navigationController pushViewController:mianVC animated:YES];
                }else{
                    //登录界面
                    LoginViewController *LoginVC=[[LoginViewController alloc] init];
                    LoginVC.hidesBottomBarWhenPushed=YES;
                    [self.navigationController pushViewController:LoginVC animated:YES];
                    [self onLogin];
                }
            }
                break;
            case 5:{//帮助
            case 5: {
                // å¸®åŠ©
                XYRWebViewController *SureWebVC=[[XYRWebViewController alloc] init];
                SureWebVC.url=[[NSUserDefaults standardUserDefaults] objectForKey:@"help"];
                SureWebVC.backToRedBag=^(){
                    
                };
                SureWebVC.hidesBottomBarWhenPushed=YES;
                [self.navigationController pushViewController:SureWebVC animated:YES];
            }
                break;
            case 4:{
                ServiceViewController *serviceVC=[[ServiceViewController alloc] init];
                serviceVC.hidesBottomBarWhenPushed=YES;
                [self.navigationController pushViewController:serviceVC animated:YES];
            }break;
                
            case 3:{//关于我们
                XYRWebViewController *aboutWebVC=[[XYRWebViewController alloc] init];
                aboutWebVC.url=[[NSUserDefaults standardUserDefaults] objectForKey:@"about"];
                aboutWebVC.backToRedBag=^(){
                // XYRWebViewController *aboutWebVC=[[XYRWebViewController alloc] init];
                // aboutWebVC.url=[[NSUserDefaults standardUserDefaults] objectForKey:@"about"];
                // aboutWebVC.backToRedBag=^(){
                //
                // };
                // aboutWebVC.hidesBottomBarWhenPushed=YES;
                // [self.navigationController pushViewController:aboutWebVC animated:YES];
                    
                };
                aboutWebVC.hidesBottomBarWhenPushed=YES;
                [self.navigationController pushViewController:aboutWebVC animated:YES];
                WeexNativeController *weexNativeVc = [[WeexNativeController alloc] init];
                weexNativeVc.urlString = @"http://192.168.1.122:9000/weex/weex_test.js";
                weexNativeVc.hidesBottomBarWhenPushed = YES;
                [self.navigationController pushViewController:weexNativeVc animated:YES];
            }
                break;
            default:
                break;
        }
    }
}
#pragma mark -UITableViewDataSource
#pragma mark --- UITableViewDataSource ---
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    if(section==0){
        return 2;
    }else if(section==1){
        return 1;
    }else{
        return 4;
    }
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    if (indexPath.section==0) {
        if (indexPath.row==0) {
            MineHeaderTableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:@"MineHeaderTableViewCell"];
            NSMutableAttributedString *mineRedBagMessage=[NSMutableAttributedString new];
            cell.backgroundColor=YTHColor(229, 0, 92);
            //我的红包
            {
                NSMutableAttributedString *TipMessage=[[NSMutableAttributedString alloc] initWithString:@"余额 "];
@@ -707,14 +784,23 @@
            //红包金额
            {
                NSString *myHongBao=@"0.00";
                if ([[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]!=nil) {
                    if ([[_userInfo allKeys] containsObject:@"myHongBao"]){
                        int YY=[[_userInfo objectForKey:@"myHongBao"] floatValue]*100;
                        if (YY/10000>0) {
                            cell.redBagMessageW.constant=165.0f;
                        }else if (YY/1000>0){
                            cell.redBagMessageW.constant=145.0f;
                        }else{
                            cell.redBagMessageW.constant=130.0f;
                        }
                        
@@ -735,120 +821,145 @@
                yuanMessage.yy_color=[UIColor whiteColor];
                [mineRedBagMessage appendAttributedString:yuanMessage];
            }
            cell.redBagMessage.numberOfLines = 1;
            cell.redBagMessage.textVerticalAlignment = YYTextVerticalAlignmentTop;
            cell.redBagMessage.attributedText = mineRedBagMessage;
            cell.IDLabel.text = [NSString stringWithFormat:@"ID:%@",[[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]];
            if ([[NSUserDefaults standardUserDefaults] objectForKey:@"userId"] ==nil) {
                cell.IDLabel.hidden = YES;
                cell.gradeButton.hidden = YES;
            }else{
                cell.IDLabel.hidden = NO;
                cell.gradeButton.hidden = NO;
            }
//            NSInteger rank = [_userInfo[@"rank"]integerValue];
//            NSString *gradeString ;
            cell.gradeImage.hidden = NO;
            
//            if (rank == 0) {
//                gradeString = @"普通";
//                cell.gradeImage.hidden = YES;
//            }else if (rank == 1) {
//                gradeString = @"铜冠";
//            }else if(rank == 2){
//                gradeString = @"银冠";
//            }else {
//                gradeString = @"金冠";
//            }
//            [cell.gradeButton setTitle:[NSString stringWithFormat:@"等级:%@会员>",gradeString] forState:UIControlStateNormal];
//            if (rank == 0) {
//                [cell.gradeButton setTitle:[NSString stringWithFormat:@"等级:%@>",gradeString] forState:UIControlStateNormal];
//
//            }
            [cell.gradeLabelImage setYthImageWithURL:[_userInfo objectForKey:@"rankNamePicture"] placeholderImage:[UIImage imageNamed:@""]];
//            [cell.gradeButton addTarget:self action:@selector(gradeTaped:) forControlEvents:UIControlEventTouchUpInside];
            [cell.gradeLabelImage setYthImageWithURL:[_userInfo objectForKey:@"rankNamePicture"]
                                    placeholderImage:[UIImage imageNamed:@""]];
            NSString * rankIconString = [NSString stringWithFormat:@"%@",[_userInfo objectForKey:@"rankIcon"]];
            [cell.gradeImage setYthImageWithURL:rankIconString placeholderImage:[UIImage imageNamed:@""]];
            if (rankIconString.length == 0) {
                cell.gradeImage.hidden = YES;
            }
            cell.gradeImage.contentMode = UIViewContentModeScaleAspectFit;
            //立即登录按钮
            {
                [cell.login addTarget:self action:@selector(LoginWithTaoBao:) forControlEvents:UIControlEventTouchUpInside];
                [cell.imageLogin addTarget:self action:@selector(LoginWithTaoBao:) forControlEvents:UIControlEventTouchUpInside];
                [cell.login addTarget:self
                               action:@selector(LoginWithTaoBao:)
                     forControlEvents:UIControlEventTouchUpInside];
                [cell.imageLogin addTarget:self
                                    action:@selector(LoginWithTaoBao:)
                          forControlEvents:UIControlEventTouchUpInside];
            }
            
            //我的红包按钮
            {
                [cell.MIneRedPacketBtn addTarget:self action:@selector(mineRedPacketHasClicked:) forControlEvents:UIControlEventTouchUpInside];
                [cell.MIneRedPacketBtn addTarget:self
                                          action:@selector(mineRedPacketHasClicked:)
                                forControlEvents:UIControlEventTouchUpInside];
            }
            
            //我的红包地帮助
            {
                [cell.helper addTarget:self action:@selector(RedPacketHelperClicked:) forControlEvents:UIControlEventTouchUpInside];
                [cell.helper addTarget:self
                                action:@selector(RedPacketHelperClicked:)
                      forControlEvents:UIControlEventTouchUpInside];
            }
            //去提现的点击事件
            [cell.withdraw addTarget:self action:@selector(gotoWithDraw:) forControlEvents:UIControlEventTouchUpInside];
            [cell.withdraw addTarget:self
                              action:@selector(gotoWithDraw:)
                    forControlEvents:UIControlEventTouchUpInside];
            
            if([[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]!=nil){
                //设置头像
                [cell.TaoBaoIcon setYthImageWithURL:[_userInfo objectForKey:@"portrait"] placeholderImage:[UIImage imageNamed:@"默认头像1"]];
                [cell.TaoBaoIcon setYthImageWithURL:[_userInfo objectForKey:@"portrait"]
                                   placeholderImage:[UIImage imageNamed:@"默认头像1"]];
                //设置昵称
                [cell.login setTitle:[_userInfo objectForKey:@"nickName"] forState:UIControlStateSelected];
                [cell.login setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected];
                [cell.login setTitle:[_userInfo objectForKey:@"nickName"]
                            forState:UIControlStateSelected];
                [cell.login setTitleColor:[UIColor whiteColor]
                                 forState:UIControlStateSelected];
                [cell.login setTintColor:[UIColor clearColor]];
                [cell.login setSelected:YES];
                [cell.imageLogin setSelected:YES];
                cell.gradeLabelImage.hidden = NO;
                cell.gradeButton.hidden = NO;
                cell.loginLayout.constant = cell.login.titleLabel.text.length * 16 + 10;
            }else{
                [cell.TaoBaoIcon setImage:[UIImage imageNamed:@"默认头像1"]];
                [cell.login setSelected:NO];
                cell.loginLayout.constant = cell.login.titleLabel.text.length * 16 + 10;
                [cell.imageLogin setSelected:NO];
                cell.loginLayout.constant = cell.login.titleLabel.text.length * 16 + 10;
                cell.gradeLabelImage.hidden = YES;
                cell.gradeButton.hidden = YES;
                cell.gradeImage.hidden = YES;
            }
            return cell;
        }else if(indexPath.row==1){
            MineRedEnvelopesTableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:@"MineRedEnvelopesTableViewCell"];
            MineRedEnvelopesTableViewCell *cell =
            [tableView dequeueReusableCellWithIdentifier:@"MineRedEnvelopesTableViewCell"];
            cell.selectionStyle=UITableViewCellSelectionStyleNone;
            
            NSString *noOpenHongBao=@"0.00";
            if ([[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]!=nil) {
                if ([[_userInfo allKeys] containsObject:@"myHongBao"]){
                    noOpenHongBao=[NSString stringWithFormat:@"%.2f",[[_userInfo objectForKey:@"myHongBao"]doubleValue]];
                    noOpenHongBao=[NSString stringWithFormat:@"%.2f",
                                   [[_userInfo objectForKey:@"myHongBao"]doubleValue]];
                }
            }
            cell.notOpenRMB.text=noOpenHongBao;
//            if([[_userInfo objectForKey:@"canOpenHongBao"] intValue]>0){
//                [cell.redPoint setHidden:NO];
//            }else{
//                [cell.redPoint setHidden:YES];
//            }
            return cell;
        }
    }else if (indexPath.section==1){
        if(indexPath.row==0){
            MineToolBarTableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:@"MineToolBarTableViewCell"];
            cell.accessoryType=UITableViewCellAccessoryNone;
            [cell.orderBtn addTarget:self action:@selector(GoToOrder:) forControlEvents:UIControlEventTouchUpInside];
            [cell.collectBtn addTarget:self action:@selector(GoTocollect:) forControlEvents:UIControlEventTouchUpInside];
            [cell.FootprintBtn addTarget:self action:@selector(GoToFootprint:) forControlEvents:UIControlEventTouchUpInside];
            return cell;
        }
    }else if (indexPath.section==2){
        if (indexPath.row == 0) {
            MineThirdTableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:@"MineThirdTableViewCell"];
//            if (!cell) {
//                cell = [[NSBundle mainBundle] loadNibNamed:@"MineThirdTableViewCell" owner:self options:nil].firstObject;
//            }
            [cell.noviceButton addTarget:self action:@selector(noviceTaped:) forControlEvents:UIControlEventTouchUpInside];
            [cell.helpButton addTarget:self action:@selector(helpTaped:) forControlEvents:UIControlEventTouchUpInside];
            [cell.servieveButton addTarget:self action:@selector(serviceTaped:) forControlEvents:UIControlEventTouchUpInside];
@@ -858,10 +969,12 @@
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
            return cell;
        }
        MineHelperTableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:@"MineHelperTableViewCell"];
        cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
        [cell.cellImage setImage:[UIImage imageNamed:grounpData2[indexPath.row - 1]]];
        [cell.cellTitle setText:grounpData2[indexPath.row - 1]];
        if (indexPath.row == 2) {
            [cell.cellTitle setText:@"邀请有奖"];
        }
@@ -870,10 +983,9 @@
    return nil;
}
/**
 è®¢å•
 */
#pragma mark ---  è®¢å• ---
-(void)GoToOrder:(UIButton *)sender{
    NSString * openIDString = [NSString stringWithFormat:@"%@",_userInfo[@"openid"]];
    if (openIDString.length != 0 && [[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]!=nil) {
@@ -881,13 +993,17 @@
        OrderVC.type=@"订单";
        OrderVC.hidesBottomBarWhenPushed=YES;
        [self.navigationController pushViewController:OrderVC animated:YES];
    }else{
        if ([[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]==nil) {//用户有登录
            //登录界面
            LoginViewController *LoginVC=[[LoginViewController alloc] init];
            LoginVC.hidesBottomBarWhenPushed=YES;
            [self.navigationController pushViewController:LoginVC animated:YES];
        }else{//用户登录了,但是并未绑定淘宝
        } else {
            //用户登录了,但是并未绑定淘宝
            Alert=[[LXAlertView alloc] init];
            Alert.delegate=self;
            Alert.isDriving=YES;
@@ -897,73 +1013,37 @@
    }
}
/**
 è¿›å…¥æ”¶è—ç•Œé¢
 */
#pragma mark --- è¿›å…¥æ”¶è—ç•Œé¢ ---
-(void)GoTocollect:(UIButton *)sender{
    if ([[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]==nil) {//用户有登录
        //登录界面
        LoginViewController *LoginVC=[[LoginViewController alloc] init];
        LoginVC.hidesBottomBarWhenPushed=YES;
        [self.navigationController pushViewController:LoginVC animated:YES];
    }else{
        MinCollectViewController *collectVC = [[MinCollectViewController alloc]init];
        collectVC.hidesBottomBarWhenPushed=YES;
        [self.navigationController pushViewController:collectVC animated:YES];
//        Alert=[[LXAlertView alloc] init];
//        Alert.delegate=self;
//        Alert.isDriving=YES;
//        Alert.fatherViewController=self;
//        [Alert show];
    }
    }
    
}
-(NSMutableDictionary *)CommonDictionary{
    NSString *device=[NSString DeviceIdentifier];
    NSString *AppSecre=@"23649898";
    NSString *apiversion=@"1";
    NSString *platform=@"ios";
    NSString *appid = @"24567001";
    NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithCapacity:0];
    [dic setObject:AppSecre forKey:@"appkey"];
    [dic setObject:device forKey:@"device"];
    [dic setObject:Package forKey:@"packages"];
    [dic setObject:Version forKey:@"version"];
    [dic setObject:apiversion forKey:@"apiversion"];
    [dic setObject:platform forKey:@"platform"];
    [dic setObject:appid forKey:@"appid"];
    //现在的时间
    NSTimeInterval timeNow = [[NSDate date] timeIntervalSince1970];
    long long int date = (long long int)timeNow*1000;
    NSString *timeStr=[NSString stringWithFormat:@"%lld",date];
    [dic setObject:timeStr forKey:@"time"];
    //加密方法
    NSArray * array = [[NSArray alloc]initWithObjects:AppSecre,device,Package,Version,apiversion,platform,timeStr,nil];
    //排序
    NSArray *resultArrayrr = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        NSComparisonResult result = [obj1 compare:obj2];
        return result == NSOrderedDescending; // å‡åº
    }];
    NSString *sign =[[NSString alloc] init];
    for (int i=0; i<resultArrayrr.count; i++) {
        sign=[sign stringByAppendingString:resultArrayrr[i]];
    }
    sign=[sign stringByAppendingString:@"buXiNjie2017!"];
    [dic setObject:[NSString md5:sign] forKey:@"sign"];
    return dic;
}
/**
 è¶³è¿¹
 */
#pragma mark --- è¶³è¿¹ ---
-(void)GoToFootprint:(UIButton *)sender{
    FootprintsViewController *FootprintsVC=[[FootprintsViewController alloc] init];
    FootprintsVC.hidesBottomBarWhenPushed=YES;
    [self.navigationController pushViewController:FootprintsVC animated:YES];
}
#pragma mark --- ç™»å½• ---
- (void)onLogin {
    // ç™»å½•界面
    LoginViewController *LoginVC=[[LoginViewController alloc] init];
    LoginVC.hidesBottomBarWhenPushed = YES;
    [self.navigationController pushViewController:LoginVC animated:YES];
}
@end
MIduo/½çÃæ/ÍøÒ³ÊÓͼ/WeexNativeController.h
New file
@@ -0,0 +1,16 @@
//
//  WeexNativeController.h
//  MIduo
//
//  Created by é‡åº†è¿ˆå°–科技有限公司 on 2018/6/28.
//  Copyright Â© 2018å¹´ yeshi. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface WeexNativeController : UIViewController
/// æ¸²æŸ“地址
@property (nonatomic, copy) NSString *urlString;
@end
MIduo/½çÃæ/ÍøÒ³ÊÓͼ/WeexNativeController.m
New file
@@ -0,0 +1,94 @@
//
//  WeexNativeController.m
//  MIduo
//
//  Created by é‡åº†è¿ˆå°–科技有限公司 on 2018/6/28.
//  Copyright Â© 2018å¹´ yeshi. All rights reserved.
//
#import "WeexNativeController.h"
#import <WeexSDK/WXSDKInstance.h>
@interface WeexNativeController ()
@property (nonatomic, strong) WXSDKInstance *instance;
@end
@implementation WeexNativeController
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.navigationController setNavigationBarHidden:YES animated:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.navigationController setNavigationBarHidden:NO animated:animated];
}
- (void)viewDidLoad {
    [super viewDidLoad];
    [self viewConfig];
}
- (void)viewConfig {
    // èƒŒæ™¯
    self.view.backgroundColor = [UIColor whiteColor];
    // åˆå§‹åŒ–
    self.instance = [[WXSDKInstance alloc] init];
    self.instance.viewController = self;
   // CGRect rect = CGRectMake(0, NAV_STATUS_BAR_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT - NAV_STATUS_BAR_HEIGHT - TAB_BAR_HEIGHT);
    CGRect rect = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
    self.instance.frame = rect;
    __weak typeof(self) weakSelf = self;
    _instance.onCreate = ^(UIView *view) {
        [weakSelf.view addSubview:view];
    };
    // æ¸²æŸ“错误
    _instance.onFailed = ^(NSError *error) {
        ALLog(@"error:%@",error);
        //process failure
    };
    // æ¸²æŸ“完成
    _instance.renderFinish = ^ (UIView *view) {
        ALLog(@"success");
        //process renderFinish
    };
    // @"http://192.168.1.122:9000/weex/gonglue.js"
    // @"http://192.168.1.122:9000/weex/weex_test.js"
    // @"http://192.168.1.122:9000/weex/refresh.js"
    if (self.urlString) {
        NSURL *url = [NSURL URLWithString:self.urlString];
        // å¼€å§‹æ¸²æŸ“
        [self.instance renderWithURL:url];
    }
}
#pragma mark --- é”€æ¯ ---
- (void)dealloc {
    [self.instance destroyInstance];
    [self.instance forceGarbageCollection];
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end
MIduo/½çÃæ/ÍøÒ³ÊÓͼ/ÉÌÆ·ÏêÇé/GoodDeTrViewController.m
@@ -284,7 +284,7 @@
    [dic setObject:_goodsID forKey:@"id"];
    
    [JYNetWorking Post:[NSString stringWithFormat:@"%@/%@",domainHTTP,@"share/getGoodsShareUrl"] param:dic success:^(NSDictionary *object) {
        NSLog(@"%@",object);
        ShonpingShareViewController *shopVC = [[ShonpingShareViewController alloc]init];
        shopVC.urlString = object[@"data"];
        shopVC.hidesBottomBarWhenPushed=YES;
Podfile
@@ -24,6 +24,8 @@
pod 'IQKeyboardManager'
pod 'WechatOpenSDK'
pod 'WeexSDK', '0.17.0'
pod 'SDAutoLayout'
pod 'ReactiveCocoa', :git => 'https://github.com/zhao0/ReactiveCocoa.git', :tag => '2.5.2'
 
pod â€˜UMengUShare/UI’
# é›†æˆå¾®ä¿¡(精简版0.2M)
Podfile.lock
@@ -42,6 +42,14 @@
    - SecurityGuardSDK
    - SGMain
    - SGSecurityBody
  - ReactiveCocoa (2.5.2):
    - ReactiveCocoa/UI (= 2.5.2)
  - ReactiveCocoa/Core (2.5.2):
    - ReactiveCocoa/no-arc
  - ReactiveCocoa/no-arc (2.5.2)
  - ReactiveCocoa/UI (2.5.2):
    - ReactiveCocoa/Core
  - SDAutoLayout (2.2.0)
  - SDCycleScrollView (1.75):
    - SDWebImage (>= 4.0.0)
  - SDWebImage (4.2.2):
@@ -91,6 +99,8 @@
  - Masonry
  - MBProgressHUD
  - MJRefresh
  - ReactiveCocoa (from `https://github.com/zhao0/ReactiveCocoa.git`, tag `2.5.2`)
  - SDAutoLayout
  - SDCycleScrollView (~> 1.75)
  - SDWebImage
  - SVProgressHUD
@@ -126,6 +136,7 @@
    - Masonry
    - MBProgressHUD
    - MJRefresh
    - SDAutoLayout
    - SDCycleScrollView
    - SDWebImage
    - SVProgressHUD
@@ -142,6 +153,16 @@
    - YYText
    - YYWebImage
EXTERNAL SOURCES:
  ReactiveCocoa:
    :git: https://github.com/zhao0/ReactiveCocoa.git
    :tag: 2.5.2
CHECKOUT OPTIONS:
  ReactiveCocoa:
    :git: https://github.com/zhao0/ReactiveCocoa.git
    :tag: 2.5.2
SPEC CHECKSUMS:
  AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67
  AlibabaAuthSDK: b5d7c1964f195c1182d9410e3158c469d25876fa
@@ -154,6 +175,8 @@
  MBProgressHUD: e7baa36a220447d8aeb12769bf0585582f3866d9
  MJRefresh: 5f8552bc25ca8751c010f621c1098dbdaacbccd6
  mtop: 1513ec32f69174bd7c95a07d393f26ef1cad3af7
  ReactiveCocoa: 3ff25b1bd992ac79c5c79b26b6c0c1713b715bb2
  SDAutoLayout: c5509e77ae75735d9a39f7bc83dba6d3f75d49d8
  SDCycleScrollView: 884b88f0266dd4708a0e1934975c69cb971707b1
  SDWebImage: 89a9d32cd520bbb46eb14e541d5109b3564af198
  SecurityGuardSDK: 05f6d782189160f2b23b731eed5cb314ce584855
@@ -174,6 +197,6 @@
  YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
  YYWebImage: 5f7f36aee2ae293f016d418c7d6ba05c4863e928
PODFILE CHECKSUM: cdfe344091c61fb3d985762320ca1222bb9dbe95
PODFILE CHECKSUM: 350af71aa54c8676cfffcde27ef14709c686e016
COCOAPODS: 1.5.3
Pods/Local Podspecs/ReactiveCocoa.podspec.json
New file
@@ -0,0 +1,58 @@
{
  "name": "ReactiveCocoa",
  "version": "2.5.2",
  "summary": "A framework for composing and transforming streams of values.",
  "homepage": "https://github.com/blog/1107-reactivecocoa-is-now-open-source",
  "authors": {
    "Josh Abernathy": "josh@github.com"
  },
  "source": {
    "git": "https://github.com/ReactiveCocoa/ReactiveCocoa.git",
    "tag": "2.5.2"
  },
  "license": "MIT",
  "description": "ReactiveCocoa (RAC) is an Objective-C framework for Functional Reactive Programming. It provides APIs for composing and transforming streams of values.",
  "requires_arc": true,
  "platforms": {
    "ios": "6.0",
    "osx": "10.8"
  },
  "default_subspecs": "UI",
  "prepare_command": "find . \\( -regex '.*EXT.*\\.[mh]$' -o -regex '.*metamacros\\.[mh]$' \\) -execdir mv {} RAC{} \\;\nfind . -regex '.*\\.[hm]' -exec sed -i '' -E 's@\"(EXT.*|metamacros)\\.h\"@\"RAC\\1.h\"@' {} \\;\nfind . -regex '.*\\.[hm]' -exec sed -i '' -E 's@<ReactiveCocoa/(EXT.*)\\.h>@<ReactiveCocoa/RAC\\1.h>@' {} \\;",
  "subspecs": [
    {
      "name": "no-arc",
      "source_files": "ReactiveCocoa/RACObjCRuntime.{h,m}",
      "requires_arc": false
    },
    {
      "name": "UI",
      "dependencies": {
        "ReactiveCocoa/Core": [
        ]
      },
      "source_files": "ReactiveCocoa/*{AppKit,NSControl,NSText,UI,MK}*",
      "ios": {
        "exclude_files": "ReactiveCocoa/*{AppKit,NSControl,NSText}*"
      },
      "osx": {
        "exclude_files": "ReactiveCocoa/*{UI,MK}*"
      }
    },
    {
      "name": "Core",
      "dependencies": {
        "ReactiveCocoa/no-arc": [
        ]
      },
      "source_files": [
        "ReactiveCocoa/*.{d,h,m}",
        "ReactiveCocoa/extobjc/*.{h,m}"
      ],
      "private_header_files": "ReactiveCocoa/*Private.h",
      "exclude_files": "ReactiveCocoa/*{RACObjCRuntime,AppKit,NSControl,NSText,UIActionSheet,UI,MK}*"
    }
  ]
}
Pods/Manifest.lock
@@ -42,6 +42,14 @@
    - SecurityGuardSDK
    - SGMain
    - SGSecurityBody
  - ReactiveCocoa (2.5.2):
    - ReactiveCocoa/UI (= 2.5.2)
  - ReactiveCocoa/Core (2.5.2):
    - ReactiveCocoa/no-arc
  - ReactiveCocoa/no-arc (2.5.2)
  - ReactiveCocoa/UI (2.5.2):
    - ReactiveCocoa/Core
  - SDAutoLayout (2.2.0)
  - SDCycleScrollView (1.75):
    - SDWebImage (>= 4.0.0)
  - SDWebImage (4.2.2):
@@ -91,6 +99,8 @@
  - Masonry
  - MBProgressHUD
  - MJRefresh
  - ReactiveCocoa (from `https://github.com/zhao0/ReactiveCocoa.git`, tag `2.5.2`)
  - SDAutoLayout
  - SDCycleScrollView (~> 1.75)
  - SDWebImage
  - SVProgressHUD
@@ -126,6 +136,7 @@
    - Masonry
    - MBProgressHUD
    - MJRefresh
    - SDAutoLayout
    - SDCycleScrollView
    - SDWebImage
    - SVProgressHUD
@@ -142,6 +153,16 @@
    - YYText
    - YYWebImage
EXTERNAL SOURCES:
  ReactiveCocoa:
    :git: https://github.com/zhao0/ReactiveCocoa.git
    :tag: 2.5.2
CHECKOUT OPTIONS:
  ReactiveCocoa:
    :git: https://github.com/zhao0/ReactiveCocoa.git
    :tag: 2.5.2
SPEC CHECKSUMS:
  AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67
  AlibabaAuthSDK: b5d7c1964f195c1182d9410e3158c469d25876fa
@@ -154,6 +175,8 @@
  MBProgressHUD: e7baa36a220447d8aeb12769bf0585582f3866d9
  MJRefresh: 5f8552bc25ca8751c010f621c1098dbdaacbccd6
  mtop: 1513ec32f69174bd7c95a07d393f26ef1cad3af7
  ReactiveCocoa: 3ff25b1bd992ac79c5c79b26b6c0c1713b715bb2
  SDAutoLayout: c5509e77ae75735d9a39f7bc83dba6d3f75d49d8
  SDCycleScrollView: 884b88f0266dd4708a0e1934975c69cb971707b1
  SDWebImage: 89a9d32cd520bbb46eb14e541d5109b3564af198
  SecurityGuardSDK: 05f6d782189160f2b23b731eed5cb314ce584855
@@ -174,6 +197,6 @@
  YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
  YYWebImage: 5f7f36aee2ae293f016d418c7d6ba05c4863e928
PODFILE CHECKSUM: cdfe344091c61fb3d985762320ca1222bb9dbe95
PODFILE CHECKSUM: 350af71aa54c8676cfffcde27ef14709c686e016
COCOAPODS: 1.5.3
Pods/Pods.xcodeproj/project.pbxproj
Diff too large
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/Pods-MIduo.xcscheme
@@ -14,7 +14,7 @@
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "3A22172D434A84E2BED002011ABFFA64"
               BlueprintIdentifier = "48016486296AF72C325ED70A8AB16F71"
               BuildableName = "Pods_MIduo.framework"
               BlueprintName = "Pods-MIduo"
               ReferencedContainer = "container:Pods.xcodeproj">
@@ -45,7 +45,7 @@
      <MacroExpansion>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "3A22172D434A84E2BED002011ABFFA64"
            BlueprintIdentifier = "48016486296AF72C325ED70A8AB16F71"
            BuildableName = "Pods_MIduo.framework"
            BlueprintName = "Pods-MIduo"
            ReferencedContainer = "container:Pods.xcodeproj">
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/ReactiveCocoa.xcscheme
New file
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
   LastUpgradeVersion = "0930"
   version = "1.3">
   <BuildAction
      parallelizeBuildables = "YES"
      buildImplicitDependencies = "YES">
      <BuildActionEntries>
         <BuildActionEntry
            buildForAnalyzing = "YES"
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "YES"
            buildForArchiving = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "22747522C67490AB7C743C0EDC3DD15C"
               BlueprintName = "ReactiveCocoa"
               ReferencedContainer = "container:Pods.xcodeproj"
               BuildableName = "ReactiveCocoa.framework">
            </BuildableReference>
         </BuildActionEntry>
      </BuildActionEntries>
   </BuildAction>
   <TestAction
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES"
      buildConfiguration = "Debug">
      <AdditionalOptions>
      </AdditionalOptions>
   </TestAction>
   <LaunchAction
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      launchStyle = "0"
      useCustomWorkingDirectory = "NO"
      ignoresPersistentStateOnLaunch = "NO"
      debugDocumentVersioning = "YES"
      debugServiceExtension = "internal"
      buildConfiguration = "Debug"
      allowLocationSimulation = "YES">
      <AdditionalOptions>
      </AdditionalOptions>
   </LaunchAction>
   <ProfileAction
      savedToolIdentifier = ""
      useCustomWorkingDirectory = "NO"
      debugDocumentVersioning = "YES"
      buildConfiguration = "Release"
      shouldUseLaunchSchemeArgsEnv = "YES">
   </ProfileAction>
   <AnalyzeAction
      buildConfiguration = "Debug">
   </AnalyzeAction>
   <ArchiveAction
      buildConfiguration = "Release"
      revealArchiveInOrganizer = "YES">
   </ArchiveAction>
</Scheme>
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/SDAutoLayout.xcscheme
New file
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
   LastUpgradeVersion = "0930"
   version = "1.3">
   <BuildAction
      parallelizeBuildables = "YES"
      buildImplicitDependencies = "YES">
      <BuildActionEntries>
         <BuildActionEntry
            buildForAnalyzing = "YES"
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "YES"
            buildForArchiving = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "C220E04FFDB20994ECFAF4229DC6519C"
               BlueprintName = "SDAutoLayout"
               ReferencedContainer = "container:Pods.xcodeproj"
               BuildableName = "SDAutoLayout.framework">
            </BuildableReference>
         </BuildActionEntry>
      </BuildActionEntries>
   </BuildAction>
   <TestAction
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES"
      buildConfiguration = "Debug">
      <AdditionalOptions>
      </AdditionalOptions>
   </TestAction>
   <LaunchAction
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      launchStyle = "0"
      useCustomWorkingDirectory = "NO"
      ignoresPersistentStateOnLaunch = "NO"
      debugDocumentVersioning = "YES"
      debugServiceExtension = "internal"
      buildConfiguration = "Debug"
      allowLocationSimulation = "YES">
      <AdditionalOptions>
      </AdditionalOptions>
   </LaunchAction>
   <ProfileAction
      savedToolIdentifier = ""
      useCustomWorkingDirectory = "NO"
      debugDocumentVersioning = "YES"
      buildConfiguration = "Release"
      shouldUseLaunchSchemeArgsEnv = "YES">
   </ProfileAction>
   <AnalyzeAction
      buildConfiguration = "Debug">
   </AnalyzeAction>
   <ArchiveAction
      buildConfiguration = "Release"
      revealArchiveInOrganizer = "YES">
   </ArchiveAction>
</Scheme>
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/SDCycleScrollView.xcscheme
@@ -14,7 +14,7 @@
            buildForArchiving = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "E0F5B143DCFD49C7743D124A754004DB"
               BlueprintIdentifier = "710215391D75D349326B1ED2B527B6F8"
               BlueprintName = "SDCycleScrollView"
               ReferencedContainer = "container:Pods.xcodeproj"
               BuildableName = "SDCycleScrollView.framework">
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/SDWebImage.xcscheme
@@ -14,7 +14,7 @@
            buildForArchiving = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "82A0FD10ACF7A1B27DFD9D000077ED25"
               BlueprintIdentifier = "C2AF5635AA2D5DE6AF427D00DDF08B8B"
               BlueprintName = "SDWebImage"
               ReferencedContainer = "container:Pods.xcodeproj"
               BuildableName = "SDWebImage.framework">
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/SVProgressHUD.xcscheme
@@ -14,7 +14,7 @@
            buildForArchiving = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "AC07BE35ABEE396697331DAF1F1C2194"
               BlueprintIdentifier = "BE245B5C9297BF1C6CEBC216DCF583C9"
               BlueprintName = "SVProgressHUD"
               ReferencedContainer = "container:Pods.xcodeproj"
               BuildableName = "SVProgressHUD.framework">
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/UICollectionViewLeftAlignedLayout.xcscheme
@@ -14,7 +14,7 @@
            buildForArchiving = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "6CE053D037D9F8F34C38CE2542E758AE"
               BlueprintIdentifier = "7BBD6DAC561AC67DE8B0778A50DE76FA"
               BlueprintName = "UICollectionViewLeftAlignedLayout"
               ReferencedContainer = "container:Pods.xcodeproj"
               BuildableName = "UICollectionViewLeftAlignedLayout.framework">
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/WeexSDK.xcscheme
@@ -14,7 +14,7 @@
            buildForArchiving = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "936EAFEECAFF4B0C24365F6FA0F579F8"
               BlueprintIdentifier = "F5CC79CABF3EB68155BBAC44E6BEB02F"
               BlueprintName = "WeexSDK"
               ReferencedContainer = "container:Pods.xcodeproj"
               BuildableName = "WeexSDK.framework">
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/YYCache.xcscheme
@@ -14,7 +14,7 @@
            buildForArchiving = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "F2E3E3E84749C68EADE5D091728D6003"
               BlueprintIdentifier = "B7AC216168E7D33E12FE87F8033E8188"
               BlueprintName = "YYCache"
               ReferencedContainer = "container:Pods.xcodeproj"
               BuildableName = "YYCache.framework">
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/YYImage.xcscheme
@@ -14,7 +14,7 @@
            buildForArchiving = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "2F43E20F0C6BC7A4D165C6ED6020EC01"
               BlueprintIdentifier = "D7F52115619489CC5BF8E43AF326506F"
               BlueprintName = "YYImage"
               ReferencedContainer = "container:Pods.xcodeproj"
               BuildableName = "YYImage.framework">
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/YYKeyboardManager.xcscheme
@@ -14,7 +14,7 @@
            buildForArchiving = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "30110AFEC19F9992820EC7BFF62F8F71"
               BlueprintIdentifier = "CCCA6A4BD5213B6BAB5028A6C0AA8E88"
               BlueprintName = "YYKeyboardManager"
               ReferencedContainer = "container:Pods.xcodeproj"
               BuildableName = "YYKeyboardManager.framework">
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/YYModel.xcscheme
@@ -14,7 +14,7 @@
            buildForArchiving = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "2A875314E3E852FC303A3A10B689EA2F"
               BlueprintIdentifier = "958B834E1966066B2D163978D140ED27"
               BlueprintName = "YYModel"
               ReferencedContainer = "container:Pods.xcodeproj"
               BuildableName = "YYModel.framework">
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/YYText.xcscheme
@@ -14,7 +14,7 @@
            buildForArchiving = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "7B6602B179E085507A7FA0DAF65A5C88"
               BlueprintIdentifier = "AD2B403DBB958A70AC5AA6C751B1C28F"
               BlueprintName = "YYText"
               ReferencedContainer = "container:Pods.xcodeproj"
               BuildableName = "YYText.framework">
Pods/Pods.xcodeproj/xcuserdata/mj.xcuserdatad/xcschemes/YYWebImage.xcscheme
@@ -14,7 +14,7 @@
            buildForArchiving = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "35B77BA8685871584392661E95FA51D0"
               BlueprintIdentifier = "5B4D3D6FFB2EA70AF6FECCA3860395DD"
               BlueprintName = "YYWebImage"
               ReferencedContainer = "container:Pods.xcodeproj"
               BuildableName = "YYWebImage.framework">
Pods/ReactiveCocoa/LICENSE.md
New file
@@ -0,0 +1,19 @@
**Copyright (c) 2012 - 2015, GitHub, Inc.**
**All rights reserved.**
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Pods/ReactiveCocoa/README.md
New file
@@ -0,0 +1,553 @@
# ReactiveCocoa [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
ReactiveCocoa (RAC) is an Objective-C framework inspired by [Functional Reactive
Programming][]. It provides APIs for **composing and transforming streams of
values**.
If you're already familiar with functional reactive programming or know the basic
premise of ReactiveCocoa, check out the [Documentation][] folder for a framework
overview and more in-depth information about how it all works in practice.
## New to ReactiveCocoa?
ReactiveCocoa is documented like crazy, and there's a wealth of introductory
material available to explain what RAC is and how you can use it.
If you want to learn more, we recommend these resources, roughly in order:
 1. [Introduction](#introduction)
 1. [When to use ReactiveCocoa](#when-to-use-reactivecocoa)
 1. [Framework Overview][]
 1. [Basic Operators][]
 1. [Header documentation](ReactiveCocoa)
 1. Previously answered [Stack Overflow](https://github.com/ReactiveCocoa/ReactiveCocoa/wiki)
    questions and [GitHub issues](https://github.com/ReactiveCocoa/ReactiveCocoa/issues?labels=question&state=closed)
 1. The rest of the [Documentation][] folder
 1. [Functional Reactive Programming on iOS](https://leanpub.com/iosfrp/)
    (eBook)
If you have any further questions, please feel free to [file an issue](https://github.com/ReactiveCocoa/ReactiveCocoa/issues/new).
## Introduction
ReactiveCocoa is inspired by [functional reactive
programming](http://blog.maybeapps.com/post/42894317939/input-and-output).
Rather than using mutable variables which are replaced and modified in-place,
RAC provides signals (represented by `RACSignal`) that capture present and
future values.
By chaining, combining, and reacting to signals, software can be written
declaratively, without the need for code that continually observes and updates
values.
For example, a text field can be bound to the latest time, even as it changes,
instead of using additional code that watches the clock and updates the
text field every second.  It works much like KVO, but with blocks instead of
overriding `-observeValueForKeyPath:ofObject:change:context:`.
Signals can also represent asynchronous operations, much like [futures and
promises][]. This greatly simplifies asynchronous software, including networking
code.
One of the major advantages of RAC is that it provides a single, unified
approach to dealing with asynchronous behaviors, including delegate methods,
callback blocks, target-action mechanisms, notifications, and KVO.
Here's a simple example:
```objc
// When self.username changes, logs the new name to the console.
//
// RACObserve(self, username) creates a new RACSignal that sends the current
// value of self.username, then the new value whenever it changes.
// -subscribeNext: will execute the block whenever the signal sends a value.
[RACObserve(self, username) subscribeNext:^(NSString *newName) {
    NSLog(@"%@", newName);
}];
```
But unlike KVO notifications, signals can be chained together and operated on:
```objc
// Only logs names that starts with "j".
//
// -filter returns a new RACSignal that only sends a new value when its block
// returns YES.
[[RACObserve(self, username)
    filter:^(NSString *newName) {
        return [newName hasPrefix:@"j"];
    }]
    subscribeNext:^(NSString *newName) {
        NSLog(@"%@", newName);
    }];
```
Signals can also be used to derive state. Instead of observing properties and
setting other properties in response to the new values, RAC makes it possible to
express properties in terms of signals and operations:
```objc
// Creates a one-way binding so that self.createEnabled will be
// true whenever self.password and self.passwordConfirmation
// are equal.
//
// RAC() is a macro that makes the binding look nicer.
//
// +combineLatest:reduce: takes an array of signals, executes the block with the
// latest value from each signal whenever any of them changes, and returns a new
// RACSignal that sends the return value of that block as values.
RAC(self, createEnabled) = [RACSignal
    combineLatest:@[ RACObserve(self, password), RACObserve(self, passwordConfirmation) ]
    reduce:^(NSString *password, NSString *passwordConfirm) {
        return @([passwordConfirm isEqualToString:password]);
    }];
```
Signals can be built on any stream of values over time, not just KVO. For
example, they can also represent button presses:
```objc
// Logs a message whenever the button is pressed.
//
// RACCommand creates signals to represent UI actions. Each signal can
// represent a button press, for example, and have additional work associated
// with it.
//
// -rac_command is an addition to NSButton. The button will send itself on that
// command whenever it's pressed.
self.button.rac_command = [[RACCommand alloc] initWithSignalBlock:^(id _) {
    NSLog(@"button was pressed!");
    return [RACSignal empty];
}];
```
Or asynchronous network operations:
```objc
// Hooks up a "Log in" button to log in over the network.
//
// This block will be run whenever the login command is executed, starting
// the login process.
self.loginCommand = [[RACCommand alloc] initWithSignalBlock:^(id sender) {
    // The hypothetical -logIn method returns a signal that sends a value when
    // the network request finishes.
    return [client logIn];
}];
// -executionSignals returns a signal that includes the signals returned from
// the above block, one for each time the command is executed.
[self.loginCommand.executionSignals subscribeNext:^(RACSignal *loginSignal) {
    // Log a message whenever we log in successfully.
    [loginSignal subscribeCompleted:^{
        NSLog(@"Logged in successfully!");
    }];
}];
// Executes the login command when the button is pressed.
self.loginButton.rac_command = self.loginCommand;
```
Signals can also represent timers, other UI events, or anything else that
changes over time.
Using signals for asynchronous operations makes it possible to build up more
complex behavior by chaining and transforming those signals. Work can easily be
triggered after a group of operations completes:
```objc
// Performs 2 network operations and logs a message to the console when they are
// both completed.
//
// +merge: takes an array of signals and returns a new RACSignal that passes
// through the values of all of the signals and completes when all of the
// signals complete.
//
// -subscribeCompleted: will execute the block when the signal completes.
[[RACSignal
    merge:@[ [client fetchUserRepos], [client fetchOrgRepos] ]]
    subscribeCompleted:^{
        NSLog(@"They're both done!");
    }];
```
Signals can be chained to sequentially execute asynchronous operations, instead
of nesting callbacks with blocks. This is similar to how [futures and promises][]
are usually used:
```objc
// Logs in the user, then loads any cached messages, then fetches the remaining
// messages from the server. After that's all done, logs a message to the
// console.
//
// The hypothetical -logInUser methods returns a signal that completes after
// logging in.
//
// -flattenMap: will execute its block whenever the signal sends a value, and
// returns a new RACSignal that merges all of the signals returned from the block
// into a single signal.
[[[[client
    logInUser]
    flattenMap:^(User *user) {
        // Return a signal that loads cached messages for the user.
        return [client loadCachedMessagesForUser:user];
    }]
    flattenMap:^(NSArray *messages) {
        // Return a signal that fetches any remaining messages.
        return [client fetchMessagesAfterMessage:messages.lastObject];
    }]
    subscribeNext:^(NSArray *newMessages) {
        NSLog(@"New messages: %@", newMessages);
    } completed:^{
        NSLog(@"Fetched all messages.");
    }];
```
RAC even makes it easy to bind to the result of an asynchronous operation:
```objc
// Creates a one-way binding so that self.imageView.image will be set as the user's
// avatar as soon as it's downloaded.
//
// The hypothetical -fetchUserWithUsername: method returns a signal which sends
// the user.
//
// -deliverOn: creates new signals that will do their work on other queues. In
// this example, it's used to move work to a background queue and then back to the main thread.
//
// -map: calls its block with each user that's fetched and returns a new
// RACSignal that sends values returned from the block.
RAC(self.imageView, image) = [[[[client
    fetchUserWithUsername:@"joshaber"]
    deliverOn:[RACScheduler scheduler]]
    map:^(User *user) {
        // Download the avatar (this is done on a background queue).
        return [[NSImage alloc] initWithContentsOfURL:user.avatarURL];
    }]
    // Now the assignment will be done on the main thread.
    deliverOn:RACScheduler.mainThreadScheduler];
```
That demonstrates some of what RAC can do, but it doesn't demonstrate why RAC is
so powerful. It's hard to appreciate RAC from README-sized examples, but it
makes it possible to write code with less state, less boilerplate, better code
locality, and better expression of intent.
For more sample code, check out [C-41][] or [GroceryList][], which are real iOS
apps written using ReactiveCocoa. Additional information about RAC can be found
in the [Documentation][] folder.
## When to use ReactiveCocoa
Upon first glance, ReactiveCocoa is very abstract, and it can be difficult to
understand how to apply it to concrete problems.
Here are some of the use cases that RAC excels at.
### Handling asynchronous or event-driven data sources
Much of Cocoa programming is focused on reacting to user events or changes in
application state. Code that deals with such events can quickly become very
complex and spaghetti-like, with lots of callbacks and state variables to handle
ordering issues.
Patterns that seem superficially different, like UI callbacks, network
responses, and KVO notifications, actually have a lot in common. [RACSignal][]
unifies all these different APIs so that they can be composed together and
manipulated in the same way.
For example, the following code:
```objc
static void *ObservationContext = &ObservationContext;
- (void)viewDidLoad {
    [super viewDidLoad];
    [LoginManager.sharedManager addObserver:self forKeyPath:@"loggingIn" options:NSKeyValueObservingOptionInitial context:&ObservationContext];
    [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(loggedOut:) name:UserDidLogOutNotification object:LoginManager.sharedManager];
    [self.usernameTextField addTarget:self action:@selector(updateLogInButton) forControlEvents:UIControlEventEditingChanged];
    [self.passwordTextField addTarget:self action:@selector(updateLogInButton) forControlEvents:UIControlEventEditingChanged];
    [self.logInButton addTarget:self action:@selector(logInPressed:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)dealloc {
    [LoginManager.sharedManager removeObserver:self forKeyPath:@"loggingIn" context:ObservationContext];
    [NSNotificationCenter.defaultCenter removeObserver:self];
}
- (void)updateLogInButton {
    BOOL textFieldsNonEmpty = self.usernameTextField.text.length > 0 && self.passwordTextField.text.length > 0;
    BOOL readyToLogIn = !LoginManager.sharedManager.isLoggingIn && !self.loggedIn;
    self.logInButton.enabled = textFieldsNonEmpty && readyToLogIn;
}
- (IBAction)logInPressed:(UIButton *)sender {
    [[LoginManager sharedManager]
        logInWithUsername:self.usernameTextField.text
        password:self.passwordTextField.text
        success:^{
            self.loggedIn = YES;
        } failure:^(NSError *error) {
            [self presentError:error];
        }];
}
- (void)loggedOut:(NSNotification *)notification {
    self.loggedIn = NO;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (context == ObservationContext) {
        [self updateLogInButton];
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}
```
… could be expressed in RAC like so:
```objc
- (void)viewDidLoad {
    [super viewDidLoad];
    @weakify(self);
    RAC(self.logInButton, enabled) = [RACSignal
        combineLatest:@[
            self.usernameTextField.rac_textSignal,
            self.passwordTextField.rac_textSignal,
            RACObserve(LoginManager.sharedManager, loggingIn),
            RACObserve(self, loggedIn)
        ] reduce:^(NSString *username, NSString *password, NSNumber *loggingIn, NSNumber *loggedIn) {
            return @(username.length > 0 && password.length > 0 && !loggingIn.boolValue && !loggedIn.boolValue);
        }];
    [[self.logInButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(UIButton *sender) {
        @strongify(self);
        RACSignal *loginSignal = [LoginManager.sharedManager
            logInWithUsername:self.usernameTextField.text
            password:self.passwordTextField.text];
            [loginSignal subscribeError:^(NSError *error) {
                @strongify(self);
                [self presentError:error];
            } completed:^{
                @strongify(self);
                self.loggedIn = YES;
            }];
    }];
    RAC(self, loggedIn) = [[NSNotificationCenter.defaultCenter
        rac_addObserverForName:UserDidLogOutNotification object:nil]
        mapReplace:@NO];
}
```
### Chaining dependent operations
Dependencies are most often found in network requests, where a previous request
to the server needs to complete before the next one can be constructed, and so
on:
```objc
[client logInWithSuccess:^{
    [client loadCachedMessagesWithSuccess:^(NSArray *messages) {
        [client fetchMessagesAfterMessage:messages.lastObject success:^(NSArray *nextMessages) {
            NSLog(@"Fetched all messages.");
        } failure:^(NSError *error) {
            [self presentError:error];
        }];
    } failure:^(NSError *error) {
        [self presentError:error];
    }];
} failure:^(NSError *error) {
    [self presentError:error];
}];
```
ReactiveCocoa makes this pattern particularly easy:
```objc
[[[[client logIn]
    then:^{
        return [client loadCachedMessages];
    }]
    flattenMap:^(NSArray *messages) {
        return [client fetchMessagesAfterMessage:messages.lastObject];
    }]
    subscribeError:^(NSError *error) {
        [self presentError:error];
    } completed:^{
        NSLog(@"Fetched all messages.");
    }];
```
### Parallelizing independent work
Working with independent data sets in parallel and then combining them into
a final result is non-trivial in Cocoa, and often involves a lot of
synchronization:
```objc
__block NSArray *databaseObjects;
__block NSArray *fileContents;
NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init];
NSBlockOperation *databaseOperation = [NSBlockOperation blockOperationWithBlock:^{
    databaseObjects = [databaseClient fetchObjectsMatchingPredicate:predicate];
}];
NSBlockOperation *filesOperation = [NSBlockOperation blockOperationWithBlock:^{
    NSMutableArray *filesInProgress = [NSMutableArray array];
    for (NSString *path in files) {
        [filesInProgress addObject:[NSData dataWithContentsOfFile:path]];
    }
    fileContents = [filesInProgress copy];
}];
NSBlockOperation *finishOperation = [NSBlockOperation blockOperationWithBlock:^{
    [self finishProcessingDatabaseObjects:databaseObjects fileContents:fileContents];
    NSLog(@"Done processing");
}];
[finishOperation addDependency:databaseOperation];
[finishOperation addDependency:filesOperation];
[backgroundQueue addOperation:databaseOperation];
[backgroundQueue addOperation:filesOperation];
[backgroundQueue addOperation:finishOperation];
```
The above code can be cleaned up and optimized by simply composing signals:
```objc
RACSignal *databaseSignal = [[databaseClient
    fetchObjectsMatchingPredicate:predicate]
    subscribeOn:[RACScheduler scheduler]];
RACSignal *fileSignal = [RACSignal startEagerlyWithScheduler:[RACScheduler scheduler] block:^(id<RACSubscriber> subscriber) {
    NSMutableArray *filesInProgress = [NSMutableArray array];
    for (NSString *path in files) {
        [filesInProgress addObject:[NSData dataWithContentsOfFile:path]];
    }
    [subscriber sendNext:[filesInProgress copy]];
    [subscriber sendCompleted];
}];
[[RACSignal
    combineLatest:@[ databaseSignal, fileSignal ]
    reduce:^ id (NSArray *databaseObjects, NSArray *fileContents) {
        [self finishProcessingDatabaseObjects:databaseObjects fileContents:fileContents];
        return nil;
    }]
    subscribeCompleted:^{
        NSLog(@"Done processing");
    }];
```
### Simplifying collection transformations
Higher-order functions like `map`, `filter`, `fold`/`reduce` are sorely missing
from Foundation, leading to loop-focused code like this:
```objc
NSMutableArray *results = [NSMutableArray array];
for (NSString *str in strings) {
    if (str.length < 2) {
        continue;
    }
    NSString *newString = [str stringByAppendingString:@"foobar"];
    [results addObject:newString];
}
```
[RACSequence][] allows any Cocoa collection to be manipulated in a uniform and
declarative way:
```objc
RACSequence *results = [[strings.rac_sequence
    filter:^ BOOL (NSString *str) {
        return str.length >= 2;
    }]
    map:^(NSString *str) {
        return [str stringByAppendingString:@"foobar"];
    }];
```
## System Requirements
ReactiveCocoa supports OS X 10.8+ and iOS 8.0+.
## Importing ReactiveCocoa
To add RAC to your application:
 1. Add the ReactiveCocoa repository as a submodule of your application's
    repository.
 1. Run `script/bootstrap` from within the ReactiveCocoa folder.
 1. Drag and drop `ReactiveCocoa.xcodeproj` into your
    application's Xcode project or workspace.
 1. On the "Build Phases" tab of your application target, add RAC to the "Link
    Binary With Libraries" phase.
    * **On iOS**, add `libReactiveCocoa-iOS.a`.
    * **On OS X**, add `ReactiveCocoa.framework`. RAC must also be added to any
      "Copy Frameworks" build phase. If you don't already have one, simply add
      a "Copy Files" build phase and target the "Frameworks" destination.
 1. Add `"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/include"
    $(inherited)` to the "Header Search Paths" build setting (this is only
    necessary for archive builds, but it has no negative effect otherwise).
 1. **For iOS targets**, add `-ObjC` to the "Other Linker Flags" build setting.
 1. **If you added RAC to a project (not a workspace)**, you will also need to
    add the appropriate RAC target to the "Target Dependencies" of your
    application.
If you would prefer to use [CocoaPods](http://cocoapods.org), there are some
[ReactiveCocoa
podspecs](https://github.com/CocoaPods/Specs/tree/master/Specs/ReactiveCocoa) that
have been generously contributed by third parties.
To see a project already set up with RAC, check out [C-41][] or [GroceryList][],
which are real iOS apps written using ReactiveCocoa.
## Standalone Development
If you’re working on RAC in isolation instead of integrating it into another project, you’ll want to open `ReactiveCocoa.xcworkspace` and not the `.xcodeproj`.
## More Info
ReactiveCocoa is based on .NET's [Reactive
Extensions](http://msdn.microsoft.com/en-us/data/gg577609) (Rx). Most of the
principles of Rx apply to RAC as well. There are some really good Rx resources
out there:
* [Reactive Extensions MSDN entry](http://msdn.microsoft.com/en-us/library/hh242985.aspx)
* [Reactive Extensions for .NET Introduction](http://leecampbell.blogspot.com/2010/08/reactive-extensions-for-net.html)
* [Rx - Channel 9 videos](http://channel9.msdn.com/tags/Rx/)
* [Reactive Extensions wiki](http://rxwiki.wikidot.com/)
* [101 Rx Samples](http://rxwiki.wikidot.com/101samples)
* [Programming Reactive Extensions and LINQ](http://www.amazon.com/Programming-Reactive-Extensions-Jesse-Liberty/dp/1430237473)
RAC and Rx are both frameworks inspired by functional reactive programming. Here
are some resources related to FRP:
* [What is FRP? - Elm Language](http://elm-lang.org/learn/What-is-FRP.elm)
* [What is Functional Reactive Programming - Stack Overflow](http://stackoverflow.com/questions/1028250/what-is-functional-reactive-programming/1030631#1030631)
* [Specification for a Functional Reactive Language - Stack Overflow](http://stackoverflow.com/questions/5875929/specification-for-a-functional-reactive-programming-language#5878525)
* [Escape from Callback Hell](http://elm-lang.org/learn/Escape-from-Callback-Hell.elm)
* [Principles of Reactive Programming on Coursera](https://www.coursera.org/course/reactive)
[Basic Operators]: Documentation/BasicOperators.md
[Documentation]: Documentation
[Framework Overview]: Documentation/FrameworkOverview.md
[Functional Reactive Programming]: http://en.wikipedia.org/wiki/Functional_reactive_programming
[GroceryList]:  https://github.com/jspahrsummers/GroceryList
[RACSequence]: ReactiveCocoa/RACSequence.h
[RACSignal]: ReactiveCocoa/RACSignal.h
[futures and promises]: http://en.wikipedia.org/wiki/Futures_and_promises
[C-41]: https://github.com/AshFurrow/C-41
Pods/ReactiveCocoa/ReactiveCocoa/MKAnnotationView+RACSignalSupport.h
New file
@@ -0,0 +1,29 @@
//
//  MKAnnotationView+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Zak Remer on 3/31/15.
//  Copyright (c) 2015 GitHub. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
@class RACSignal;
@interface MKAnnotationView (RACSignalSupport)
/// A signal which will send a RACUnit whenever -prepareForReuse is invoked upon
/// the receiver.
///
/// Examples
///
///  [[[self.cancelButton
///     rac_signalForControlEvents:UIControlEventTouchUpInside]
///     takeUntil:self.rac_prepareForReuseSignal]
///     subscribeNext:^(UIButton *x) {
///         // do other things
///     }];
@property (nonatomic, strong, readonly) RACSignal *rac_prepareForReuseSignal;
@end
Pods/ReactiveCocoa/ReactiveCocoa/MKAnnotationView+RACSignalSupport.m
New file
@@ -0,0 +1,31 @@
//
//  MKAnnotationView+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Zak Remer on 3/31/15.
//  Copyright (c) 2015 GitHub. All rights reserved.
//
#import "MKAnnotationView+RACSignalSupport.h"
#import "NSObject+RACDescription.h"
#import "NSObject+RACSelectorSignal.h"
#import "RACSignal+Operations.h"
#import "RACUnit.h"
#import <objc/runtime.h>
@implementation MKAnnotationView (RACSignalSupport)
- (RACSignal *)rac_prepareForReuseSignal {
    RACSignal *signal = objc_getAssociatedObject(self, _cmd);
    if (signal != nil) return signal;
    signal = [[[self
        rac_signalForSelector:@selector(prepareForReuse)]
        mapReplace:RACUnit.defaultUnit]
        setNameWithFormat:@"%@ -rac_prepareForReuseSignal", self.rac_description];
    objc_setAssociatedObject(self, _cmd, signal, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    return signal;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSArray+RACSequenceAdditions.h
New file
@@ -0,0 +1,20 @@
//
//  NSArray+RACSequenceAdditions.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSequence;
@interface NSArray (RACSequenceAdditions)
/// Creates and returns a sequence corresponding to the receiver.
///
/// Mutating the receiver will not affect the sequence after it's been created.
@property (nonatomic, copy, readonly) RACSequence *rac_sequence;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSArray+RACSequenceAdditions.m
New file
@@ -0,0 +1,18 @@
//
//  NSArray+RACSequenceAdditions.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "NSArray+RACSequenceAdditions.h"
#import "RACArraySequence.h"
@implementation NSArray (RACSequenceAdditions)
- (RACSequence *)rac_sequence {
    return [RACArraySequence sequenceWithArray:self offset:0];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSData+RACSupport.h
New file
@@ -0,0 +1,22 @@
//
//  NSData+RACSupport.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 5/11/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACScheduler;
@class RACSignal;
@interface NSData (RACSupport)
// Read the data at the URL using -[NSData initWithContentsOfURL:options:error:].
// Sends the data or the error.
//
// scheduler - cannot be nil.
+ (RACSignal *)rac_readContentsOfURL:(NSURL *)URL options:(NSDataReadingOptions)options scheduler:(RACScheduler *)scheduler;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSData+RACSupport.m
New file
@@ -0,0 +1,35 @@
//
//  NSData+RACSupport.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 5/11/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "NSData+RACSupport.h"
#import "RACReplaySubject.h"
#import "RACScheduler.h"
@implementation NSData (RACSupport)
+ (RACSignal *)rac_readContentsOfURL:(NSURL *)URL options:(NSDataReadingOptions)options scheduler:(RACScheduler *)scheduler {
    NSCParameterAssert(scheduler != nil);
    RACReplaySubject *subject = [RACReplaySubject subject];
    [subject setNameWithFormat:@"+rac_readContentsOfURL: %@ options: %lu scheduler: %@", URL, (unsigned long)options, scheduler];
    [scheduler schedule:^{
        NSError *error = nil;
        NSData *data = [[NSData alloc] initWithContentsOfURL:URL options:options error:&error];
        if (data == nil) {
            [subject sendError:error];
        } else {
            [subject sendNext:data];
            [subject sendCompleted];
        }
    }];
    return subject;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSDictionary+RACSequenceAdditions.h
New file
@@ -0,0 +1,31 @@
//
//  NSDictionary+RACSequenceAdditions.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSequence;
@interface NSDictionary (RACSequenceAdditions)
/// Creates and returns a sequence of RACTuple key/value pairs. The key will be
/// the first element in the tuple, and the value will be the second.
///
/// Mutating the receiver will not affect the sequence after it's been created.
@property (nonatomic, copy, readonly) RACSequence *rac_sequence;
/// Creates and returns a sequence corresponding to the keys in the receiver.
///
/// Mutating the receiver will not affect the sequence after it's been created.
@property (nonatomic, copy, readonly) RACSequence *rac_keySequence;
/// Creates and returns a sequence corresponding to the values in the receiver.
///
/// Mutating the receiver will not affect the sequence after it's been created.
@property (nonatomic, copy, readonly) RACSequence *rac_valueSequence;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSDictionary+RACSequenceAdditions.m
New file
@@ -0,0 +1,34 @@
//
//  NSDictionary+RACSequenceAdditions.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "NSDictionary+RACSequenceAdditions.h"
#import "NSArray+RACSequenceAdditions.h"
#import "RACSequence.h"
#import "RACTuple.h"
@implementation NSDictionary (RACSequenceAdditions)
- (RACSequence *)rac_sequence {
    NSDictionary *immutableDict = [self copy];
    // TODO: First class support for dictionary sequences.
    return [immutableDict.allKeys.rac_sequence map:^(id key) {
        id value = immutableDict[key];
        return RACTuplePack(key, value);
    }];
}
- (RACSequence *)rac_keySequence {
    return self.allKeys.rac_sequence;
}
- (RACSequence *)rac_valueSequence {
    return self.allValues.rac_sequence;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSEnumerator+RACSequenceAdditions.h
New file
@@ -0,0 +1,20 @@
//
//  NSEnumerator+RACSequenceAdditions.h
//  ReactiveCocoa
//
//  Created by Uri Baghin on 07/01/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSequence;
@interface NSEnumerator (RACSequenceAdditions)
/// Creates and returns a sequence corresponding to the receiver.
///
/// The receiver is exhausted lazily as the sequence is enumerated.
@property (nonatomic, copy, readonly) RACSequence *rac_sequence;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSEnumerator+RACSequenceAdditions.m
New file
@@ -0,0 +1,22 @@
//
//  NSEnumerator+RACSequenceAdditions.m
//  ReactiveCocoa
//
//  Created by Uri Baghin on 07/01/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "NSEnumerator+RACSequenceAdditions.h"
#import "RACSequence.h"
@implementation NSEnumerator (RACSequenceAdditions)
- (RACSequence *)rac_sequence {
    return [RACSequence sequenceWithHeadBlock:^{
        return [self nextObject];
    } tailBlock:^{
        return self.rac_sequence;
    }];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSFileHandle+RACSupport.h
New file
@@ -0,0 +1,19 @@
//
//  NSFileHandle+RACSupport.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 5/10/12.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSignal;
@interface NSFileHandle (RACSupport)
// Read any available data in the background and send it. Completes when data
// length is <= 0.
- (RACSignal *)rac_readInBackground;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSFileHandle+RACSupport.m
New file
@@ -0,0 +1,40 @@
//
//  NSFileHandle+RACSupport.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 5/10/12.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "NSFileHandle+RACSupport.h"
#import "NSNotificationCenter+RACSupport.h"
#import "NSObject+RACDescription.h"
#import "RACReplaySubject.h"
#import "RACDisposable.h"
@implementation NSFileHandle (RACSupport)
- (RACSignal *)rac_readInBackground {
    RACReplaySubject *subject = [RACReplaySubject subject];
    [subject setNameWithFormat:@"%@ -rac_readInBackground", self.rac_description];
    RACSignal *dataNotification = [[[NSNotificationCenter defaultCenter] rac_addObserverForName:NSFileHandleReadCompletionNotification object:self] map:^(NSNotification *note) {
        return note.userInfo[NSFileHandleNotificationDataItem];
    }];
    __block RACDisposable *subscription = [dataNotification subscribeNext:^(NSData *data) {
        if (data.length > 0) {
            [subject sendNext:data];
            [self readInBackgroundAndNotify];
        } else {
            [subject sendCompleted];
            [subscription dispose];
        }
    }];
    [self readInBackgroundAndNotify];
    return subject;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSIndexSet+RACSequenceAdditions.h
New file
@@ -0,0 +1,21 @@
//
//  NSIndexSet+RACSequenceAdditions.h
//  ReactiveCocoa
//
//  Created by Sergey Gavrilyuk on 12/17/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSequence;
@interface NSIndexSet (RACSequenceAdditions)
/// Creates and returns a sequence of indexes (as `NSNumber`s) corresponding to
/// the receiver.
///
/// Mutating the receiver will not affect the sequence after it's been created.
@property (nonatomic, copy, readonly) RACSequence *rac_sequence;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSIndexSet+RACSequenceAdditions.m
New file
@@ -0,0 +1,18 @@
//
//  NSIndexSet+RACSequenceAdditions.m
//  ReactiveCocoa
//
//  Created by Sergey Gavrilyuk on 12/17/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "NSIndexSet+RACSequenceAdditions.h"
#import "RACIndexSetSequence.h"
@implementation NSIndexSet (RACSequenceAdditions)
- (RACSequence *)rac_sequence {
    return [RACIndexSetSequence sequenceWithIndexSet:self];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSInvocation+RACTypeParsing.h
New file
@@ -0,0 +1,56 @@
//
//  NSInvocation+RACTypeParsing.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 11/17/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACTuple;
// A private category of methods to handle wrapping and unwrapping of values.
@interface NSInvocation (RACTypeParsing)
// Sets the argument for the invocation at the given index by unboxing the given
// object based on the type signature of the argument.
//
// This does not support C arrays or unions.
//
// Note that calling this on a char * or const char * argument can cause all
// arguments to be retained.
//
// object - The object to unbox and set as the argument.
// index  - The index of the argument to set.
- (void)rac_setArgument:(id)object atIndex:(NSUInteger)index;
// Gets the argument for the invocation at the given index based on the
// invocation's method signature. The value is then wrapped in the appropriate
// object type.
//
// This does not support C arrays or unions.
//
// index  - The index of the argument to get.
//
// Returns the argument of the invocation, wrapped in an object.
- (id)rac_argumentAtIndex:(NSUInteger)index;
// Arguments tuple for the invocation.
//
// The arguments tuple excludes implicit variables `self` and `_cmd`.
//
// See -rac_argumentAtIndex: and -rac_setArgumentAtIndex: for further
// description of the underlying behavior.
@property (nonatomic, copy) RACTuple *rac_argumentsTuple;
// Gets the return value from the invocation based on the invocation's method
// signature. The value is then wrapped in the appropriate object type.
//
// This does not support C arrays or unions.
//
// Returns the return value of the invocation, wrapped in an object. Voids are
// returned as `RACUnit.defaultUnit`.
- (id)rac_returnValue;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSInvocation+RACTypeParsing.m
New file
@@ -0,0 +1,232 @@
//
//  NSInvocation+RACTypeParsing.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 11/17/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "NSInvocation+RACTypeParsing.h"
#import "RACTuple.h"
#import "RACUnit.h"
#import <CoreGraphics/CoreGraphics.h>
@implementation NSInvocation (RACTypeParsing)
- (void)rac_setArgument:(id)object atIndex:(NSUInteger)index {
#define PULL_AND_SET(type, selector) \
    do { \
        type val = [object selector]; \
        [self setArgument:&val atIndex:(NSInteger)index]; \
    } while (0)
    const char *argType = [self.methodSignature getArgumentTypeAtIndex:index];
    // Skip const type qualifier.
    if (argType[0] == 'r') {
        argType++;
    }
    if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0) {
        [self setArgument:&object atIndex:(NSInteger)index];
    } else if (strcmp(argType, @encode(char)) == 0) {
        PULL_AND_SET(char, charValue);
    } else if (strcmp(argType, @encode(int)) == 0) {
        PULL_AND_SET(int, intValue);
    } else if (strcmp(argType, @encode(short)) == 0) {
        PULL_AND_SET(short, shortValue);
    } else if (strcmp(argType, @encode(long)) == 0) {
        PULL_AND_SET(long, longValue);
    } else if (strcmp(argType, @encode(long long)) == 0) {
        PULL_AND_SET(long long, longLongValue);
    } else if (strcmp(argType, @encode(unsigned char)) == 0) {
        PULL_AND_SET(unsigned char, unsignedCharValue);
    } else if (strcmp(argType, @encode(unsigned int)) == 0) {
        PULL_AND_SET(unsigned int, unsignedIntValue);
    } else if (strcmp(argType, @encode(unsigned short)) == 0) {
        PULL_AND_SET(unsigned short, unsignedShortValue);
    } else if (strcmp(argType, @encode(unsigned long)) == 0) {
        PULL_AND_SET(unsigned long, unsignedLongValue);
    } else if (strcmp(argType, @encode(unsigned long long)) == 0) {
        PULL_AND_SET(unsigned long long, unsignedLongLongValue);
    } else if (strcmp(argType, @encode(float)) == 0) {
        PULL_AND_SET(float, floatValue);
    } else if (strcmp(argType, @encode(double)) == 0) {
        PULL_AND_SET(double, doubleValue);
    } else if (strcmp(argType, @encode(BOOL)) == 0) {
        PULL_AND_SET(BOOL, boolValue);
    } else if (strcmp(argType, @encode(char *)) == 0) {
        const char *cString = [object UTF8String];
        [self setArgument:&cString atIndex:(NSInteger)index];
        [self retainArguments];
    } else if (strcmp(argType, @encode(void (^)(void))) == 0) {
        [self setArgument:&object atIndex:(NSInteger)index];
    } else {
        NSCParameterAssert([object isKindOfClass:NSValue.class]);
        NSUInteger valueSize = 0;
        NSGetSizeAndAlignment([object objCType], &valueSize, NULL);
#if DEBUG
        NSUInteger argSize = 0;
        NSGetSizeAndAlignment(argType, &argSize, NULL);
        NSCAssert(valueSize == argSize, @"Value size does not match argument size in -rac_setArgument: %@ atIndex: %lu", object, (unsigned long)index);
#endif
        unsigned char valueBytes[valueSize];
        [object getValue:valueBytes];
        [self setArgument:valueBytes atIndex:(NSInteger)index];
    }
#undef PULL_AND_SET
}
- (id)rac_argumentAtIndex:(NSUInteger)index {
#define WRAP_AND_RETURN(type) \
    do { \
        type val = 0; \
        [self getArgument:&val atIndex:(NSInteger)index]; \
        return @(val); \
    } while (0)
    const char *argType = [self.methodSignature getArgumentTypeAtIndex:index];
    // Skip const type qualifier.
    if (argType[0] == 'r') {
        argType++;
    }
    if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0) {
        __autoreleasing id returnObj;
        [self getArgument:&returnObj atIndex:(NSInteger)index];
        return returnObj;
    } else if (strcmp(argType, @encode(char)) == 0) {
        WRAP_AND_RETURN(char);
    } else if (strcmp(argType, @encode(int)) == 0) {
        WRAP_AND_RETURN(int);
    } else if (strcmp(argType, @encode(short)) == 0) {
        WRAP_AND_RETURN(short);
    } else if (strcmp(argType, @encode(long)) == 0) {
        WRAP_AND_RETURN(long);
    } else if (strcmp(argType, @encode(long long)) == 0) {
        WRAP_AND_RETURN(long long);
    } else if (strcmp(argType, @encode(unsigned char)) == 0) {
        WRAP_AND_RETURN(unsigned char);
    } else if (strcmp(argType, @encode(unsigned int)) == 0) {
        WRAP_AND_RETURN(unsigned int);
    } else if (strcmp(argType, @encode(unsigned short)) == 0) {
        WRAP_AND_RETURN(unsigned short);
    } else if (strcmp(argType, @encode(unsigned long)) == 0) {
        WRAP_AND_RETURN(unsigned long);
    } else if (strcmp(argType, @encode(unsigned long long)) == 0) {
        WRAP_AND_RETURN(unsigned long long);
    } else if (strcmp(argType, @encode(float)) == 0) {
        WRAP_AND_RETURN(float);
    } else if (strcmp(argType, @encode(double)) == 0) {
        WRAP_AND_RETURN(double);
    } else if (strcmp(argType, @encode(BOOL)) == 0) {
        WRAP_AND_RETURN(BOOL);
    } else if (strcmp(argType, @encode(char *)) == 0) {
        WRAP_AND_RETURN(const char *);
    } else if (strcmp(argType, @encode(void (^)(void))) == 0) {
        __unsafe_unretained id block = nil;
        [self getArgument:&block atIndex:(NSInteger)index];
        return [block copy];
    } else {
        NSUInteger valueSize = 0;
        NSGetSizeAndAlignment(argType, &valueSize, NULL);
        unsigned char valueBytes[valueSize];
        [self getArgument:valueBytes atIndex:(NSInteger)index];
        return [NSValue valueWithBytes:valueBytes objCType:argType];
    }
    return nil;
#undef WRAP_AND_RETURN
}
- (RACTuple *)rac_argumentsTuple {
    NSUInteger numberOfArguments = self.methodSignature.numberOfArguments;
    NSMutableArray *argumentsArray = [NSMutableArray arrayWithCapacity:numberOfArguments - 2];
    for (NSUInteger index = 2; index < numberOfArguments; index++) {
        [argumentsArray addObject:[self rac_argumentAtIndex:index] ?: RACTupleNil.tupleNil];
    }
    return [RACTuple tupleWithObjectsFromArray:argumentsArray];
}
- (void)setRac_argumentsTuple:(RACTuple *)arguments {
    NSCAssert(arguments.count == self.methodSignature.numberOfArguments - 2, @"Number of supplied arguments (%lu), does not match the number expected by the signature (%lu)", (unsigned long)arguments.count, (unsigned long)self.methodSignature.numberOfArguments - 2);
    NSUInteger index = 2;
    for (id arg in arguments) {
        [self rac_setArgument:(arg == RACTupleNil.tupleNil ? nil : arg) atIndex:index];
        index++;
    }
}
- (id)rac_returnValue {
#define WRAP_AND_RETURN(type) \
    do { \
        type val = 0; \
        [self getReturnValue:&val]; \
        return @(val); \
    } while (0)
    const char *returnType = self.methodSignature.methodReturnType;
    // Skip const type qualifier.
    if (returnType[0] == 'r') {
        returnType++;
    }
    if (strcmp(returnType, @encode(id)) == 0 || strcmp(returnType, @encode(Class)) == 0 || strcmp(returnType, @encode(void (^)(void))) == 0) {
        __autoreleasing id returnObj;
        [self getReturnValue:&returnObj];
        return returnObj;
    } else if (strcmp(returnType, @encode(char)) == 0) {
        WRAP_AND_RETURN(char);
    } else if (strcmp(returnType, @encode(int)) == 0) {
        WRAP_AND_RETURN(int);
    } else if (strcmp(returnType, @encode(short)) == 0) {
        WRAP_AND_RETURN(short);
    } else if (strcmp(returnType, @encode(long)) == 0) {
        WRAP_AND_RETURN(long);
    } else if (strcmp(returnType, @encode(long long)) == 0) {
        WRAP_AND_RETURN(long long);
    } else if (strcmp(returnType, @encode(unsigned char)) == 0) {
        WRAP_AND_RETURN(unsigned char);
    } else if (strcmp(returnType, @encode(unsigned int)) == 0) {
        WRAP_AND_RETURN(unsigned int);
    } else if (strcmp(returnType, @encode(unsigned short)) == 0) {
        WRAP_AND_RETURN(unsigned short);
    } else if (strcmp(returnType, @encode(unsigned long)) == 0) {
        WRAP_AND_RETURN(unsigned long);
    } else if (strcmp(returnType, @encode(unsigned long long)) == 0) {
        WRAP_AND_RETURN(unsigned long long);
    } else if (strcmp(returnType, @encode(float)) == 0) {
        WRAP_AND_RETURN(float);
    } else if (strcmp(returnType, @encode(double)) == 0) {
        WRAP_AND_RETURN(double);
    } else if (strcmp(returnType, @encode(BOOL)) == 0) {
        WRAP_AND_RETURN(BOOL);
    } else if (strcmp(returnType, @encode(char *)) == 0) {
        WRAP_AND_RETURN(const char *);
    } else if (strcmp(returnType, @encode(void)) == 0) {
        return RACUnit.defaultUnit;
    } else {
        NSUInteger valueSize = 0;
        NSGetSizeAndAlignment(returnType, &valueSize, NULL);
        unsigned char valueBytes[valueSize];
        [self getReturnValue:valueBytes];
        return [NSValue valueWithBytes:valueBytes objCType:returnType];
    }
    return nil;
#undef WRAP_AND_RETURN
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSNotificationCenter+RACSupport.h
New file
@@ -0,0 +1,18 @@
//
//  NSNotificationCenter+RACSupport.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 5/10/12.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSignal;
@interface NSNotificationCenter (RACSupport)
// Sends the NSNotification every time the notification is posted.
- (RACSignal *)rac_addObserverForName:(NSString *)notificationName object:(id)object;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSNotificationCenter+RACSupport.m
New file
@@ -0,0 +1,31 @@
//
//  NSNotificationCenter+RACSupport.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 5/10/12.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "NSNotificationCenter+RACSupport.h"
#import "RACEXTScope.h"
#import "RACSignal.h"
#import "RACSubscriber.h"
#import "RACDisposable.h"
@implementation NSNotificationCenter (RACSupport)
- (RACSignal *)rac_addObserverForName:(NSString *)notificationName object:(id)object {
    @unsafeify(object);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        @strongify(object);
        id observer = [self addObserverForName:notificationName object:object queue:nil usingBlock:^(NSNotification *note) {
            [subscriber sendNext:note];
        }];
        return [RACDisposable disposableWithBlock:^{
            [self removeObserver:observer];
        }];
    }] setNameWithFormat:@"-rac_addObserverForName: %@ object: <%@: %p>", notificationName, [object class], object];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACDeallocating.h
New file
@@ -0,0 +1,34 @@
//
//  NSObject+RACDeallocating.h
//  ReactiveCocoa
//
//  Created by Kazuo Koga on 2013/03/15.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACCompoundDisposable;
@class RACDisposable;
@class RACSignal;
@interface NSObject (RACDeallocating)
/// The compound disposable which will be disposed of when the receiver is
/// deallocated.
@property (atomic, readonly, strong) RACCompoundDisposable *rac_deallocDisposable;
/// Returns a signal that will complete immediately before the receiver is fully
/// deallocated. If already deallocated when the signal is subscribed to,
/// a `completed` event will be sent immediately.
- (RACSignal *)rac_willDeallocSignal;
@end
@interface NSObject (RACDeallocatingDeprecated)
- (RACSignal *)rac_didDeallocSignal __attribute__((deprecated("Use -rac_willDeallocSignal")));
- (void)rac_addDeallocDisposable:(RACDisposable *)disposable __attribute__((deprecated("Add disposables to -rac_deallocDisposable instead")));
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACDeallocating.m
New file
@@ -0,0 +1,129 @@
//
//  NSObject+RACDeallocating.m
//  ReactiveCocoa
//
//  Created by Kazuo Koga on 2013/03/15.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "NSObject+RACDeallocating.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACReplaySubject.h"
#import <objc/message.h>
#import <objc/runtime.h>
static const void *RACObjectCompoundDisposable = &RACObjectCompoundDisposable;
static NSMutableSet *swizzledClasses() {
    static dispatch_once_t onceToken;
    static NSMutableSet *swizzledClasses = nil;
    dispatch_once(&onceToken, ^{
        swizzledClasses = [[NSMutableSet alloc] init];
    });
    return swizzledClasses;
}
static void swizzleDeallocIfNeeded(Class classToSwizzle) {
    @synchronized (swizzledClasses()) {
        NSString *className = NSStringFromClass(classToSwizzle);
        if ([swizzledClasses() containsObject:className]) return;
        SEL deallocSelector = sel_registerName("dealloc");
        __block void (*originalDealloc)(__unsafe_unretained id, SEL) = NULL;
        id newDealloc = ^(__unsafe_unretained id self) {
            RACCompoundDisposable *compoundDisposable = objc_getAssociatedObject(self, RACObjectCompoundDisposable);
            [compoundDisposable dispose];
            if (originalDealloc == NULL) {
                struct objc_super superInfo = {
                    .receiver = self,
                    .super_class = class_getSuperclass(classToSwizzle)
                };
                void (*msgSend)(struct objc_super *, SEL) = (__typeof__(msgSend))objc_msgSendSuper;
                msgSend(&superInfo, deallocSelector);
            } else {
                originalDealloc(self, deallocSelector);
            }
        };
        IMP newDeallocIMP = imp_implementationWithBlock(newDealloc);
        if (!class_addMethod(classToSwizzle, deallocSelector, newDeallocIMP, "v@:")) {
            // The class already contains a method implementation.
            Method deallocMethod = class_getInstanceMethod(classToSwizzle, deallocSelector);
            // We need to store original implementation before setting new implementation
            // in case method is called at the time of setting.
            originalDealloc = (__typeof__(originalDealloc))method_getImplementation(deallocMethod);
            // We need to store original implementation again, in case it just changed.
            originalDealloc = (__typeof__(originalDealloc))method_setImplementation(deallocMethod, newDeallocIMP);
        }
        [swizzledClasses() addObject:className];
    }
}
@implementation NSObject (RACDeallocating)
- (RACSignal *)rac_willDeallocSignal {
    RACSignal *signal = objc_getAssociatedObject(self, _cmd);
    if (signal != nil) return signal;
    RACReplaySubject *subject = [RACReplaySubject subject];
    [self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
        [subject sendCompleted];
    }]];
    objc_setAssociatedObject(self, _cmd, subject, OBJC_ASSOCIATION_RETAIN);
    return subject;
}
- (RACCompoundDisposable *)rac_deallocDisposable {
    @synchronized (self) {
        RACCompoundDisposable *compoundDisposable = objc_getAssociatedObject(self, RACObjectCompoundDisposable);
        if (compoundDisposable != nil) return compoundDisposable;
        swizzleDeallocIfNeeded(self.class);
        compoundDisposable = [RACCompoundDisposable compoundDisposable];
        objc_setAssociatedObject(self, RACObjectCompoundDisposable, compoundDisposable, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        return compoundDisposable;
    }
}
@end
@implementation NSObject (RACDeallocatingDeprecated)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
- (RACSignal *)rac_didDeallocSignal {
    RACSubject *subject = [RACSubject subject];
    RACScopedDisposable *disposable = [[RACDisposable
        disposableWithBlock:^{
            [subject sendCompleted];
        }]
        asScopedDisposable];
    objc_setAssociatedObject(self, (__bridge void *)disposable, disposable, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    return subject;
}
- (void)rac_addDeallocDisposable:(RACDisposable *)disposable {
    [self.rac_deallocDisposable addDisposable:disposable];
}
#pragma clang diagnostic pop
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACDescription.h
New file
@@ -0,0 +1,21 @@
//
//  NSObject+RACDescription.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-05-13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
// A private category providing a terser but faster alternative to -description.
@interface NSObject (RACDescription)
// A simplified description of the receiver, which does not invoke -description
// (and thus should be much faster in many cases).
//
// This is for debugging purposes only, and will return a constant string
// unless the RAC_DEBUG_SIGNAL_NAMES environment variable is set.
- (NSString *)rac_description;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACDescription.m
New file
@@ -0,0 +1,50 @@
//
//  NSObject+RACDescription.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-05-13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "NSObject+RACDescription.h"
#import "RACTuple.h"
@implementation NSObject (RACDescription)
- (NSString *)rac_description {
    if (getenv("RAC_DEBUG_SIGNAL_NAMES") != NULL) {
        return [[NSString alloc] initWithFormat:@"<%@: %p>", self.class, self];
    } else {
        return @"(description skipped)";
    }
}
@end
@implementation NSValue (RACDescription)
- (NSString *)rac_description {
    return self.description;
}
@end
@implementation NSString (RACDescription)
- (NSString *)rac_description {
    return self.description;
}
@end
@implementation RACTuple (RACDescription)
- (NSString *)rac_description {
    if (getenv("RAC_DEBUG_SIGNAL_NAMES") != NULL) {
        return self.allObjects.description;
    } else {
        return @"(description skipped)";
    }
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACKVOWrapper.h
New file
@@ -0,0 +1,46 @@
//
//  NSObject+RACKVOWrapper.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 10/11/11.
//  Copyright (c) 2011 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACDisposable;
@class RACKVOTrampoline;
// A private category providing a block based interface to KVO.
@interface NSObject (RACKVOWrapper)
// Adds the given block as the callbacks for when the key path changes.
//
// Unlike direct KVO observation, this handles deallocation of `weak` properties
// by generating an appropriate notification. This will only occur if there is
// an `@property` declaration visible in the observed class, with the `weak`
// memory management attribute.
//
// The observation does not need to be explicitly removed. It will be removed
// when the observer or the receiver deallocate.
//
// keyPath  - The key path to observe. Must not be nil.
// options  - The KVO observation options.
// observer - The object that requested the observation. May be nil.
// block    - The block called when the value at the key path changes. It is
//            passed the current value of the key path and the extended KVO
//            change dictionary including RAC-specific keys and values. Must not
//            be nil.
//
// Returns a disposable that can be used to stop the observation.
- (RACDisposable *)rac_observeKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)observer block:(void (^)(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent))block;
@end
typedef void (^RACKVOBlock)(id target, id observer, NSDictionary *change);
@interface NSObject (RACKVOWrapperDeprecated)
- (RACKVOTrampoline *)rac_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block __attribute((deprecated("Use rac_observeKeyPath:options:observer:block: instead.")));
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACKVOWrapper.m
New file
@@ -0,0 +1,213 @@
//
//  NSObject+RACKVOWrapper.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 10/11/11.
//  Copyright (c) 2011 GitHub. All rights reserved.
//
#import "NSObject+RACKVOWrapper.h"
#import "RACEXTRuntimeExtensions.h"
#import "RACEXTScope.h"
#import "NSObject+RACDeallocating.h"
#import "NSString+RACKeyPathUtilities.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACKVOTrampoline.h"
#import "RACSerialDisposable.h"
@implementation NSObject (RACKVOWrapper)
- (RACDisposable *)rac_observeKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver block:(void (^)(id, NSDictionary *, BOOL, BOOL))block {
    NSCParameterAssert(block != nil);
    NSCParameterAssert(keyPath.rac_keyPathComponents.count > 0);
    keyPath = [keyPath copy];
    NSObject *strongObserver = weakObserver;
    NSArray *keyPathComponents = keyPath.rac_keyPathComponents;
    BOOL keyPathHasOneComponent = (keyPathComponents.count == 1);
    NSString *keyPathHead = keyPathComponents[0];
    NSString *keyPathTail = keyPath.rac_keyPathByDeletingFirstKeyPathComponent;
    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    // The disposable that groups all disposal necessary to clean up the callbacks
    // added to the value of the first key path component.
    RACSerialDisposable *firstComponentSerialDisposable = [RACSerialDisposable serialDisposableWithDisposable:[RACCompoundDisposable compoundDisposable]];
    RACCompoundDisposable * (^firstComponentDisposable)(void) = ^{
        return (RACCompoundDisposable *)firstComponentSerialDisposable.disposable;
    };
    [disposable addDisposable:firstComponentSerialDisposable];
    BOOL shouldAddDeallocObserver = NO;
    objc_property_t property = class_getProperty(object_getClass(self), keyPathHead.UTF8String);
    if (property != NULL) {
        rac_propertyAttributes *attributes = rac_copyPropertyAttributes(property);
        if (attributes != NULL) {
            @onExit {
                free(attributes);
            };
            BOOL isObject = attributes->objectClass != nil || strstr(attributes->type, @encode(id)) == attributes->type;
            BOOL isProtocol = attributes->objectClass == NSClassFromString(@"Protocol");
            BOOL isBlock = strcmp(attributes->type, @encode(void(^)())) == 0;
            BOOL isWeak = attributes->weak;
            // If this property isn't actually an object (or is a Class object),
            // no point in observing the deallocation of the wrapper returned by
            // KVC.
            //
            // If this property is an object, but not declared `weak`, we
            // don't need to watch for it spontaneously being set to nil.
            //
            // Attempting to observe non-weak properties will result in
            // broken behavior for dynamic getters, so don't even try.
            shouldAddDeallocObserver = isObject && isWeak && !isBlock && !isProtocol;
        }
    }
    // Adds the callback block to the value's deallocation. Also adds the logic to
    // clean up the callback to the firstComponentDisposable.
    void (^addDeallocObserverToPropertyValue)(NSObject *) = ^(NSObject *value) {
        if (!shouldAddDeallocObserver) return;
        // If a key path value is the observer, commonly when a key path begins
        // with "self", we prevent deallocation triggered callbacks for any such key
        // path components. Thus, the observer's deallocation is not considered a
        // change to the key path.
        if (value == weakObserver) return;
        NSDictionary *change = @{
            NSKeyValueChangeKindKey: @(NSKeyValueChangeSetting),
            NSKeyValueChangeNewKey: NSNull.null,
        };
        RACCompoundDisposable *valueDisposable = value.rac_deallocDisposable;
        RACDisposable *deallocDisposable = [RACDisposable disposableWithBlock:^{
            block(nil, change, YES, keyPathHasOneComponent);
        }];
        [valueDisposable addDisposable:deallocDisposable];
        [firstComponentDisposable() addDisposable:[RACDisposable disposableWithBlock:^{
            [valueDisposable removeDisposable:deallocDisposable];
        }]];
    };
    // Adds the callback block to the remaining path components on the value. Also
    // adds the logic to clean up the callbacks to the firstComponentDisposable.
    void (^addObserverToValue)(NSObject *) = ^(NSObject *value) {
        RACDisposable *observerDisposable = [value rac_observeKeyPath:keyPathTail options:(options & ~NSKeyValueObservingOptionInitial) observer:weakObserver block:block];
        [firstComponentDisposable() addDisposable:observerDisposable];
    };
    // Observe only the first key path component, when the value changes clean up
    // the callbacks on the old value, add callbacks to the new value and call the
    // callback block as needed.
    //
    // Note this does not use NSKeyValueObservingOptionInitial so this only
    // handles changes to the value, callbacks to the initial value must be added
    // separately.
    NSKeyValueObservingOptions trampolineOptions = (options | NSKeyValueObservingOptionPrior) & ~NSKeyValueObservingOptionInitial;
    RACKVOTrampoline *trampoline = [[RACKVOTrampoline alloc] initWithTarget:self observer:strongObserver keyPath:keyPathHead options:trampolineOptions block:^(id trampolineTarget, id trampolineObserver, NSDictionary *change) {
        // If this is a prior notification, clean up all the callbacks added to the
        // previous value and call the callback block. Everything else is deferred
        // until after we get the notification after the change.
        if ([change[NSKeyValueChangeNotificationIsPriorKey] boolValue]) {
            [firstComponentDisposable() dispose];
            if ((options & NSKeyValueObservingOptionPrior) != 0) {
                block([trampolineTarget valueForKeyPath:keyPath], change, NO, keyPathHasOneComponent);
            }
            return;
        }
        // From here the notification is not prior.
        NSObject *value = [trampolineTarget valueForKey:keyPathHead];
        // If the value has changed but is nil, there is no need to add callbacks to
        // it, just call the callback block.
        if (value == nil) {
            block(nil, change, NO, keyPathHasOneComponent);
            return;
        }
        // From here the notification is not prior and the value is not nil.
        // Create a new firstComponentDisposable while getting rid of the old one at
        // the same time, in case this is being called concurrently.
        RACDisposable *oldFirstComponentDisposable = [firstComponentSerialDisposable swapInDisposable:[RACCompoundDisposable compoundDisposable]];
        [oldFirstComponentDisposable dispose];
        addDeallocObserverToPropertyValue(value);
        // If there are no further key path components, there is no need to add the
        // other callbacks, just call the callback block with the value itself.
        if (keyPathHasOneComponent) {
            block(value, change, NO, keyPathHasOneComponent);
            return;
        }
        // The value has changed, is not nil, and there are more key path components
        // to consider. Add the callbacks to the value for the remaining key path
        // components and call the callback block with the current value of the full
        // key path.
        addObserverToValue(value);
        block([value valueForKeyPath:keyPathTail], change, NO, keyPathHasOneComponent);
    }];
    // Stop the KVO observation when this one is disposed of.
    [disposable addDisposable:trampoline];
    // Add the callbacks to the initial value if needed.
    NSObject *value = [self valueForKey:keyPathHead];
    if (value != nil) {
        addDeallocObserverToPropertyValue(value);
        if (!keyPathHasOneComponent) {
            addObserverToValue(value);
        }
    }
    // Call the block with the initial value if needed.
    if ((options & NSKeyValueObservingOptionInitial) != 0) {
        id initialValue = [self valueForKeyPath:keyPath];
        NSDictionary *initialChange = @{
            NSKeyValueChangeKindKey: @(NSKeyValueChangeSetting),
            NSKeyValueChangeNewKey: initialValue ?: NSNull.null,
        };
        block(initialValue, initialChange, NO, keyPathHasOneComponent);
    }
    RACCompoundDisposable *observerDisposable = strongObserver.rac_deallocDisposable;
    RACCompoundDisposable *selfDisposable = self.rac_deallocDisposable;
    // Dispose of this observation if the receiver or the observer deallocate.
    [observerDisposable addDisposable:disposable];
    [selfDisposable addDisposable:disposable];
    return [RACDisposable disposableWithBlock:^{
        [disposable dispose];
        [observerDisposable removeDisposable:disposable];
        [selfDisposable removeDisposable:disposable];
    }];
}
@end
@implementation NSObject (RACKVOWrapperDeprecated)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
- (RACKVOTrampoline *)rac_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block {
    return [[RACKVOTrampoline alloc] initWithTarget:self observer:observer keyPath:keyPath options:options block:block];
}
#pragma clang diagnostic pop
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACLifting.h
New file
@@ -0,0 +1,61 @@
//
//  NSObject+RACLifting.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 10/13/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSignal;
@interface NSObject (RACLifting)
/// Lifts the selector on the receiver into the reactive world. The selector will
/// be invoked whenever any signal argument sends a value, but only after each
/// signal has sent an initial value.
///
/// It will replay the most recently sent value to new subscribers.
///
/// This does not support C arrays or unions.
///
/// selector    - The selector on self to invoke.
/// firstSignal - The signal corresponding to the first method argument. This
///               must not be nil.
/// ...         - A list of RACSignals corresponding to the remaining arguments.
///               There must be a non-nil signal for each method argument.
///
/// Examples
///
///   [button rac_liftSelector:@selector(setTitleColor:forState:) withSignals:textColorSignal, [RACSignal return:@(UIControlStateNormal)], nil];
///
/// Returns a signal which sends the return value from each invocation of the
/// selector. If the selector returns void, it instead sends RACUnit.defaultUnit.
/// It completes only after all the signal arguments complete.
- (RACSignal *)rac_liftSelector:(SEL)selector withSignals:(RACSignal *)firstSignal, ... NS_REQUIRES_NIL_TERMINATION;
/// Like -rac_liftSelector:withSignals:, but accepts an array instead of
/// a variadic list of arguments.
- (RACSignal *)rac_liftSelector:(SEL)selector withSignalsFromArray:(NSArray *)signals;
/// Like -rac_liftSelector:withSignals:, but accepts a signal sending tuples of
/// arguments instead of a variadic list of arguments.
- (RACSignal *)rac_liftSelector:(SEL)selector withSignalOfArguments:(RACSignal *)arguments;
@end
@interface NSObject (RACLiftingDeprecated)
- (RACSignal *)rac_liftSelector:(SEL)selector withObjects:(id)arg, ... __attribute__((deprecated("Use -rac_liftSelector:withSignals: instead")));
- (RACSignal *)rac_liftSelector:(SEL)selector withObjectsFromArray:(NSArray *)args __attribute__((deprecated("Use -rac_liftSelector:withSignalsFromArray: instead")));
- (RACSignal *)rac_liftBlock:(id)block withArguments:(id)arg, ... NS_REQUIRES_NIL_TERMINATION __attribute__((deprecated("Use +combineLatest:reduce: instead")));
- (RACSignal *)rac_liftBlock:(id)block withArgumentsFromArray:(NSArray *)args __attribute__((deprecated("Use +combineLatest:reduce: instead")));
@end
@interface NSObject (RACLiftingUnavailable)
- (instancetype)rac_lift __attribute__((unavailable("Use -rac_liftSelector:withSignals: instead")));
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACLifting.m
New file
@@ -0,0 +1,142 @@
//
//  NSObject+RACLifting.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 10/13/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "NSObject+RACLifting.h"
#import "RACEXTScope.h"
#import "NSInvocation+RACTypeParsing.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACDescription.h"
#import "RACSignal+Operations.h"
#import "RACTuple.h"
@implementation NSObject (RACLifting)
- (RACSignal *)rac_liftSelector:(SEL)selector withSignalOfArguments:(RACSignal *)arguments {
    NSCParameterAssert(selector != NULL);
    NSCParameterAssert(arguments != nil);
    @unsafeify(self);
    NSMethodSignature *methodSignature = [self methodSignatureForSelector:selector];
    NSCAssert(methodSignature != nil, @"%@ does not respond to %@", self, NSStringFromSelector(selector));
    return [[[[arguments
        takeUntil:self.rac_willDeallocSignal]
        map:^(RACTuple *arguments) {
            @strongify(self);
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
            invocation.selector = selector;
            invocation.rac_argumentsTuple = arguments;
            [invocation invokeWithTarget:self];
            return invocation.rac_returnValue;
        }]
        replayLast]
        setNameWithFormat:@"%@ -rac_liftSelector: %s withSignalsOfArguments: %@", self.rac_description, sel_getName(selector), arguments];
}
- (RACSignal *)rac_liftSelector:(SEL)selector withSignalsFromArray:(NSArray *)signals {
    NSCParameterAssert(signals != nil);
    NSCParameterAssert(signals.count > 0);
    NSMethodSignature *methodSignature = [self methodSignatureForSelector:selector];
    NSCAssert(methodSignature != nil, @"%@ does not respond to %@", self, NSStringFromSelector(selector));
    NSUInteger numberOfArguments __attribute__((unused)) = methodSignature.numberOfArguments - 2;
    NSCAssert(numberOfArguments == signals.count, @"Wrong number of signals for %@ (expected %lu, got %lu)", NSStringFromSelector(selector), (unsigned long)numberOfArguments, (unsigned long)signals.count);
    return [[self
        rac_liftSelector:selector withSignalOfArguments:[RACSignal combineLatest:signals]]
        setNameWithFormat:@"%@ -rac_liftSelector: %s withSignalsFromArray: %@", self.rac_description, sel_getName(selector), signals];
}
- (RACSignal *)rac_liftSelector:(SEL)selector withSignals:(RACSignal *)firstSignal, ... {
    NSCParameterAssert(firstSignal != nil);
    NSMutableArray *signals = [NSMutableArray array];
    va_list args;
    va_start(args, firstSignal);
    for (id currentSignal = firstSignal; currentSignal != nil; currentSignal = va_arg(args, id)) {
        NSCAssert([currentSignal isKindOfClass:RACSignal.class], @"Argument %@ is not a RACSignal", currentSignal);
        [signals addObject:currentSignal];
    }
    va_end(args);
    return [[self
        rac_liftSelector:selector withSignalsFromArray:signals]
        setNameWithFormat:@"%@ -rac_liftSelector: %s withSignals: %@", self.rac_description, sel_getName(selector), signals];
}
@end
@implementation NSObject (RACLiftingDeprecated)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
static NSArray *RACMapArgumentsToSignals(NSArray *args) {
    NSMutableArray *mappedArgs = [NSMutableArray array];
    for (id arg in args) {
        if ([arg isEqual:RACTupleNil.tupleNil]) {
            [mappedArgs addObject:[RACSignal return:nil]];
        } else if ([arg isKindOfClass:RACSignal.class]) {
            [mappedArgs addObject:arg];
        } else {
            [mappedArgs addObject:[RACSignal return:arg]];
        }
    }
    return mappedArgs;
}
- (RACSignal *)rac_liftSelector:(SEL)selector withObjects:(id)arg, ... {
    NSMethodSignature *methodSignature = [self methodSignatureForSelector:selector];
    NSMutableArray *arguments = [NSMutableArray array];
    va_list args;
    va_start(args, arg);
    for (NSUInteger i = 2; i < methodSignature.numberOfArguments; i++) {
        id currentObject = (i == 2 ? arg : va_arg(args, id));
        [arguments addObject:currentObject ?: RACTupleNil.tupleNil];
    }
    va_end(args);
    return [self rac_liftSelector:selector withObjectsFromArray:arguments];
}
- (RACSignal *)rac_liftSelector:(SEL)selector withObjectsFromArray:(NSArray *)args {
    return [self rac_liftSelector:selector withSignalsFromArray:RACMapArgumentsToSignals(args)];
}
- (RACSignal *)rac_liftBlock:(id)block withArguments:(id)arg, ... {
    NSMutableArray *arguments = [NSMutableArray array];
    va_list args;
    va_start(args, arg);
    for (id currentObject = arg; currentObject != nil; currentObject = va_arg(args, id)) {
        [arguments addObject:currentObject];
    }
    va_end(args);
    return [self rac_liftBlock:block withArgumentsFromArray:arguments];
}
- (RACSignal *)rac_liftBlock:(id)block withArgumentsFromArray:(NSArray *)args {
    return [[[[RACSignal
        combineLatest:RACMapArgumentsToSignals(args)]
        reduceEach:block]
        takeUntil:self.rac_willDeallocSignal]
        replayLast];
}
#pragma clang diagnostic pop
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACPropertySubscribing.h
New file
@@ -0,0 +1,105 @@
//
//  NSObject+RACPropertySubscribing.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/2/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RACEXTKeyPathCoding.h"
#import "RACmetamacros.h"
/// Creates a signal which observes `KEYPATH` on `TARGET` for changes.
///
/// In either case, the observation continues until `TARGET` _or self_ is
/// deallocated. If any intermediate object is deallocated instead, it will be
/// assumed to have been set to nil.
///
/// Make sure to `@strongify(self)` when using this macro within a block! The
/// macro will _always_ reference `self`, which can silently introduce a retain
/// cycle within a block. As a result, you should make sure that `self` is a weak
/// reference (e.g., created by `@weakify` and `@strongify`) before the
/// expression that uses `RACObserve`.
///
/// Examples
///
///    // Observes self, and doesn't stop until self is deallocated.
///    RACSignal *selfSignal = RACObserve(self, arrayController.items);
///
///    // Observes the array controller, and stops when self _or_ the array
///    // controller is deallocated.
///    RACSignal *arrayControllerSignal = RACObserve(self.arrayController, items);
///
///    // Observes obj.arrayController, and stops when self _or_ the array
///    // controller is deallocated.
///    RACSignal *signal2 = RACObserve(obj.arrayController, items);
///
///    @weakify(self);
///    RACSignal *signal3 = [anotherSignal flattenMap:^(NSArrayController *arrayController) {
///        // Avoids a retain cycle because of RACObserve implicitly referencing
///        // self.
///        @strongify(self);
///        return RACObserve(arrayController, items);
///    }];
///
/// Returns a signal which sends the current value of the key path on
/// subscription, then sends the new value every time it changes, and sends
/// completed if self or observer is deallocated.
#define RACObserve(TARGET, KEYPATH) \
    ({ \
        __weak id target_ = (TARGET); \
        [target_ rac_valuesForKeyPath:@keypath(TARGET, KEYPATH) observer:self]; \
    })
@class RACDisposable;
@class RACSignal;
@interface NSObject (RACPropertySubscribing)
/// Creates a signal to observe the value at the given key path.
///
/// The initial value is sent on subscription, the subsequent values are sent
/// from whichever thread the change occured on, even if it doesn't have a valid
/// scheduler.
///
/// Returns a signal that immediately sends the receiver's current value at the
/// given keypath, then any changes thereafter.
- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer;
/// Creates a signal to observe the changes of the given key path.
///
/// The initial value is sent on subscription, the subsequent values are sent
/// from whichever thread the change occured on, even if it doesn't have a valid
/// scheduler.
///
/// Returns a signal that sends tuples containing the current value at the key
/// path and the change dictionary for each KVO callback.
- (RACSignal *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)observer;
@end
#define RACAble(...) \
    metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \
        (_RACAbleObject(self, __VA_ARGS__)) \
        (_RACAbleObject(__VA_ARGS__))
#define _RACAbleObject(object, property) [object rac_signalForKeyPath:@keypath(object, property) observer:self]
#define RACAbleWithStart(...) \
    metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \
        (_RACAbleWithStartObject(self, __VA_ARGS__)) \
        (_RACAbleWithStartObject(__VA_ARGS__))
#define _RACAbleWithStartObject(object, property) [object rac_signalWithStartingValueForKeyPath:@keypath(object, property) observer:self]
@interface NSObject (RACPropertySubscribingDeprecated)
+ (RACSignal *)rac_signalFor:(NSObject *)object keyPath:(NSString *)keyPath observer:(NSObject *)observer __attribute__((deprecated("Use -rac_valuesForKeyPath:observer: or RACObserve() instead.")));
+ (RACSignal *)rac_signalWithStartingValueFor:(NSObject *)object keyPath:(NSString *)keyPath observer:(NSObject *)observer __attribute__((deprecated("Use -rac_valuesForKeyPath:observer: or RACObserve() instead.")));
+ (RACSignal *)rac_signalWithChangesFor:(NSObject *)object keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(NSObject *)observer __attribute__((deprecated("Use -rac_valuesAndChangesForKeyPath:options:observer: instead.")));
- (RACSignal *)rac_signalForKeyPath:(NSString *)keyPath observer:(NSObject *)observer __attribute__((deprecated("Use -rac_valuesForKeyPath:observer: or RACObserve() instead.")));
- (RACSignal *)rac_signalWithStartingValueForKeyPath:(NSString *)keyPath observer:(NSObject *)observer __attribute__((deprecated("Use -rac_valuesForKeyPath:observer: or RACObserve() instead.")));
- (RACDisposable *)rac_deriveProperty:(NSString *)keyPath from:(RACSignal *)signal __attribute__((deprecated("Use -[RACSignal setKeyPath:onObject:] instead")));
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACPropertySubscribing.m
New file
@@ -0,0 +1,159 @@
//
//  NSObject+RACPropertySubscribing.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/2/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "NSObject+RACPropertySubscribing.h"
#import "RACEXTScope.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACDescription.h"
#import "NSObject+RACKVOWrapper.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACKVOTrampoline.h"
#import "RACSubscriber.h"
#import "RACSignal+Operations.h"
#import "RACTuple.h"
#import <libkern/OSAtomic.h>
@implementation NSObject (RACPropertySubscribing)
- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer {
    return [[[self
        rac_valuesAndChangesForKeyPath:keyPath options:NSKeyValueObservingOptionInitial observer:observer]
        map:^(RACTuple *value) {
            // -map: because it doesn't require the block trampoline that -reduceEach: uses
            return value[0];
        }]
        setNameWithFormat:@"RACObserve(%@, %@)", self.rac_description, keyPath];
}
- (RACSignal *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver {
    NSObject *strongObserver = weakObserver;
    keyPath = [keyPath copy];
    NSRecursiveLock *objectLock = [[NSRecursiveLock alloc] init];
    objectLock.name = @"org.reactivecocoa.ReactiveCocoa.NSObjectRACPropertySubscribing";
    __weak NSObject *weakSelf = self;
    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];
                return nil;
            }
            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];
}
@end
static RACSignal *signalWithoutChangesFor(Class class, NSObject *object, NSString *keyPath, NSKeyValueObservingOptions options, NSObject *observer) {
    NSCParameterAssert(object != nil);
    NSCParameterAssert(keyPath != nil);
    NSCParameterAssert(observer != nil);
    keyPath = [keyPath copy];
    @unsafeify(object);
    return [[class
        rac_signalWithChangesFor:object keyPath:keyPath options:options observer:observer]
        map:^(NSDictionary *change) {
            @strongify(object);
            return [object valueForKeyPath:keyPath];
        }];
}
@implementation NSObject (RACPropertySubscribingDeprecated)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
+ (RACSignal *)rac_signalFor:(NSObject *)object keyPath:(NSString *)keyPath observer:(NSObject *)observer {
    return signalWithoutChangesFor(self, object, keyPath, 0, observer);
}
+ (RACSignal *)rac_signalWithStartingValueFor:(NSObject *)object keyPath:(NSString *)keyPath observer:(NSObject *)observer {
    return signalWithoutChangesFor(self, object, keyPath, NSKeyValueObservingOptionInitial, observer);
}
+ (RACSignal *)rac_signalWithChangesFor:(NSObject *)object keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(NSObject *)observer {
    @unsafeify(observer, object);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        @strongify(observer, object);
        RACKVOTrampoline *KVOTrampoline = [object rac_addObserver:observer forKeyPath:keyPath options:options block:^(id target, id observer, NSDictionary *change) {
            [subscriber sendNext:change];
        }];
        @weakify(subscriber);
        RACDisposable *deallocDisposable = [RACDisposable disposableWithBlock:^{
            @strongify(subscriber);
            [KVOTrampoline dispose];
            [subscriber sendCompleted];
        }];
        [observer.rac_deallocDisposable addDisposable:deallocDisposable];
        [object.rac_deallocDisposable addDisposable:deallocDisposable];
        RACCompoundDisposable *observerDisposable = observer.rac_deallocDisposable;
        RACCompoundDisposable *objectDisposable = object.rac_deallocDisposable;
        return [RACDisposable disposableWithBlock:^{
            [observerDisposable removeDisposable:deallocDisposable];
            [objectDisposable removeDisposable:deallocDisposable];
            [KVOTrampoline dispose];
        }];
    }] setNameWithFormat:@"RACAble(%@, %@)", object.rac_description, keyPath];
}
- (RACSignal *)rac_signalForKeyPath:(NSString *)keyPath observer:(NSObject *)observer {
    return [self.class rac_signalFor:self keyPath:keyPath observer:observer];
}
- (RACSignal *)rac_signalWithStartingValueForKeyPath:(NSString *)keyPath observer:(NSObject *)observer {
    return [self.class rac_signalWithStartingValueFor:self keyPath:keyPath observer:observer];
}
- (RACDisposable *)rac_deriveProperty:(NSString *)keyPath from:(RACSignal *)signal {
    return [signal setKeyPath:keyPath onObject:self];
}
#pragma clang diagnostic pop
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACSelectorSignal.h
New file
@@ -0,0 +1,79 @@
//
//  NSObject+RACSelectorSignal.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/18/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSignal;
/// The domain for any errors originating from -rac_signalForSelector:.
extern NSString * const RACSelectorSignalErrorDomain;
/// -rac_signalForSelector: was going to add a new method implementation for
/// `selector`, but another thread added an implementation before it was able to.
///
/// This will _not_ occur for cases where a method implementation exists before
/// -rac_signalForSelector: is invoked.
extern const NSInteger RACSelectorSignalErrorMethodSwizzlingRace;
@interface NSObject (RACSelectorSignal)
/// Creates a signal associated with the receiver, which will send a tuple of the
/// method's arguments each time the given selector is invoked.
///
/// If the selector is already implemented on the receiver, the existing
/// implementation will be invoked _before_ the signal fires.
///
/// If the selector is not yet implemented on the receiver, the injected
/// implementation will have a `void` return type and accept only object
/// arguments. Invoking the added implementation with non-object values, or
/// expecting a return value, will result in undefined behavior.
///
/// This is useful for changing an event or delegate callback into a signal. For
/// example, on an NSView:
///
///     [[view rac_signalForSelector:@selector(mouseDown:)] subscribeNext:^(RACTuple *args) {
///         NSEvent *event = args.first;
///         NSLog(@"mouse button pressed: %@", event);
///     }];
///
/// selector - The selector for whose invocations are to be observed. If it
///            doesn't exist, it will be implemented to accept object arguments
///            and return void. This cannot have C arrays or unions as arguments
///            or C arrays, unions, structs, complex or vector types as return
///            type.
///
/// Returns a signal which will send a tuple of arguments upon each invocation of
/// the selector, then completes when the receiver is deallocated. `next` events
/// will be sent synchronously from the thread that invoked the method. If
/// a runtime call fails, the signal will send an error in the
/// RACSelectorSignalErrorDomain.
- (RACSignal *)rac_signalForSelector:(SEL)selector;
/// Behaves like -rac_signalForSelector:, but if the selector is not yet
/// implemented on the receiver, its method signature is looked up within
/// `protocol`, and may accept non-object arguments.
///
/// If the selector is not yet implemented and has a return value, the injected
/// method will return all zero bits (equal to `nil`, `NULL`, 0, 0.0f, etc.).
///
/// selector - The selector for whose invocations are to be observed. If it
///            doesn't exist, it will be implemented using information from
///            `protocol`, and may accept non-object arguments and return
///            a value. This cannot have C arrays or unions as arguments or
///            return type.
/// protocol - The protocol in which `selector` is declared. This will be used
///            for type information if the selector is not already implemented on
///            the receiver. This must not be `NULL`, and `selector` must exist
///            in this protocol.
///
/// Returns a signal which will send a tuple of arguments on each invocation of
/// the selector, or an error in RACSelectorSignalErrorDomain if a runtime
/// call fails.
- (RACSignal *)rac_signalForSelector:(SEL)selector fromProtocol:(Protocol *)protocol;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSObject+RACSelectorSignal.m
New file
@@ -0,0 +1,330 @@
//
//  NSObject+RACSelectorSignal.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/18/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "NSObject+RACSelectorSignal.h"
#import "RACEXTRuntimeExtensions.h"
#import "NSInvocation+RACTypeParsing.h"
#import "NSObject+RACDeallocating.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACObjCRuntime.h"
#import "RACSubject.h"
#import "RACTuple.h"
#import "NSObject+RACDescription.h"
#import <objc/message.h>
#import <objc/runtime.h>
NSString * const RACSelectorSignalErrorDomain = @"RACSelectorSignalErrorDomain";
const NSInteger RACSelectorSignalErrorMethodSwizzlingRace = 1;
static NSString * const RACSignalForSelectorAliasPrefix = @"rac_alias_";
static NSString * const RACSubclassSuffix = @"_RACSelectorSignal";
static void *RACSubclassAssociationKey = &RACSubclassAssociationKey;
static NSMutableSet *swizzledClasses() {
    static NSMutableSet *set;
    static dispatch_once_t pred;
    dispatch_once(&pred, ^{
        set = [[NSMutableSet alloc] init];
    });
    return set;
}
@implementation NSObject (RACSelectorSignal)
static BOOL RACForwardInvocation(id self, NSInvocation *invocation) {
    SEL aliasSelector = RACAliasForSelector(invocation.selector);
    RACSubject *subject = objc_getAssociatedObject(self, aliasSelector);
    Class class = object_getClass(invocation.target);
    BOOL respondsToAlias = [class instancesRespondToSelector:aliasSelector];
    if (respondsToAlias) {
        invocation.selector = aliasSelector;
        [invocation invoke];
    }
    if (subject == nil) return respondsToAlias;
    [subject sendNext:invocation.rac_argumentsTuple];
    return YES;
}
static void RACSwizzleForwardInvocation(Class class) {
    SEL forwardInvocationSEL = @selector(forwardInvocation:);
    Method forwardInvocationMethod = class_getInstanceMethod(class, forwardInvocationSEL);
    // Preserve any existing implementation of -forwardInvocation:.
    void (*originalForwardInvocation)(id, SEL, NSInvocation *) = NULL;
    if (forwardInvocationMethod != NULL) {
        originalForwardInvocation = (__typeof__(originalForwardInvocation))method_getImplementation(forwardInvocationMethod);
    }
    // Set up a new version of -forwardInvocation:.
    //
    // If the selector has been passed to -rac_signalForSelector:, invoke
    // the aliased method, and forward the arguments to any attached signals.
    //
    // If the selector has not been passed to -rac_signalForSelector:,
    // invoke any existing implementation of -forwardInvocation:. If there
    // was no existing implementation, throw an unrecognized selector
    // exception.
    id newForwardInvocation = ^(id self, NSInvocation *invocation) {
        BOOL matched = RACForwardInvocation(self, invocation);
        if (matched) return;
        if (originalForwardInvocation == NULL) {
            [self doesNotRecognizeSelector:invocation.selector];
        } else {
            originalForwardInvocation(self, forwardInvocationSEL, invocation);
        }
    };
    class_replaceMethod(class, forwardInvocationSEL, imp_implementationWithBlock(newForwardInvocation), "v@:@");
}
static void RACSwizzleRespondsToSelector(Class class) {
    SEL respondsToSelectorSEL = @selector(respondsToSelector:);
    // Preserve existing implementation of -respondsToSelector:.
    Method respondsToSelectorMethod = class_getInstanceMethod(class, respondsToSelectorSEL);
    BOOL (*originalRespondsToSelector)(id, SEL, SEL) = (__typeof__(originalRespondsToSelector))method_getImplementation(respondsToSelectorMethod);
    // Set up a new version of -respondsToSelector: that returns YES for methods
    // added by -rac_signalForSelector:.
    //
    // If the selector has a method defined on the receiver's actual class, and
    // if that method's implementation is _objc_msgForward, then returns whether
    // the instance has a signal for the selector.
    // Otherwise, call the original -respondsToSelector:.
    id newRespondsToSelector = ^ BOOL (id self, SEL selector) {
        Method method = rac_getImmediateInstanceMethod(class, selector);
        if (method != NULL && method_getImplementation(method) == _objc_msgForward) {
            SEL aliasSelector = RACAliasForSelector(selector);
            if (objc_getAssociatedObject(self, aliasSelector) != nil) return YES;
        }
        return originalRespondsToSelector(self, respondsToSelectorSEL, selector);
    };
    class_replaceMethod(class, respondsToSelectorSEL, imp_implementationWithBlock(newRespondsToSelector), method_getTypeEncoding(respondsToSelectorMethod));
}
static void RACSwizzleGetClass(Class class, Class statedClass) {
    SEL selector = @selector(class);
    Method method = class_getInstanceMethod(class, selector);
    IMP newIMP = imp_implementationWithBlock(^(id self) {
        return statedClass;
    });
    class_replaceMethod(class, selector, newIMP, method_getTypeEncoding(method));
}
static void RACSwizzleMethodSignatureForSelector(Class class) {
    IMP newIMP = imp_implementationWithBlock(^(id self, SEL selector) {
        // Don't send the -class message to the receiver because we've changed
        // that to return the original class.
        Class actualClass = object_getClass(self);
        Method method = class_getInstanceMethod(actualClass, selector);
        if (method == NULL) {
            // Messages that the original class dynamically implements fall
            // here.
            //
            // Call the original class' -methodSignatureForSelector:.
            struct objc_super target = {
                .super_class = class_getSuperclass(class),
                .receiver = self,
            };
            NSMethodSignature * (*messageSend)(struct objc_super *, SEL, SEL) = (__typeof__(messageSend))objc_msgSendSuper;
            return messageSend(&target, @selector(methodSignatureForSelector:), selector);
        }
        char const *encoding = method_getTypeEncoding(method);
        return [NSMethodSignature signatureWithObjCTypes:encoding];
    });
    SEL selector = @selector(methodSignatureForSelector:);
    Method methodSignatureForSelectorMethod = class_getInstanceMethod(class, selector);
    class_replaceMethod(class, selector, newIMP, method_getTypeEncoding(methodSignatureForSelectorMethod));
}
// It's hard to tell which struct return types use _objc_msgForward, and
// which use _objc_msgForward_stret instead, so just exclude all struct, array,
// union, complex and vector return types.
static void RACCheckTypeEncoding(const char *typeEncoding) {
#if !NS_BLOCK_ASSERTIONS
    // Some types, including vector types, are not encoded. In these cases the
    // signature starts with the size of the argument frame.
    NSCAssert(*typeEncoding < '1' || *typeEncoding > '9', @"unknown method return type not supported in type encoding: %s", typeEncoding);
    NSCAssert(strstr(typeEncoding, "(") != typeEncoding, @"union method return type not supported");
    NSCAssert(strstr(typeEncoding, "{") != typeEncoding, @"struct method return type not supported");
    NSCAssert(strstr(typeEncoding, "[") != typeEncoding, @"array method return type not supported");
    NSCAssert(strstr(typeEncoding, @encode(_Complex float)) != typeEncoding, @"complex float method return type not supported");
    NSCAssert(strstr(typeEncoding, @encode(_Complex double)) != typeEncoding, @"complex double method return type not supported");
    NSCAssert(strstr(typeEncoding, @encode(_Complex long double)) != typeEncoding, @"complex long double method return type not supported");
#endif // !NS_BLOCK_ASSERTIONS
}
static RACSignal *NSObjectRACSignalForSelector(NSObject *self, SEL selector, Protocol *protocol) {
    SEL aliasSelector = RACAliasForSelector(selector);
    @synchronized (self) {
        RACSubject *subject = objc_getAssociatedObject(self, aliasSelector);
        if (subject != nil) return subject;
        Class class = RACSwizzleClass(self);
        NSCAssert(class != nil, @"Could not swizzle class of %@", self);
        subject = [[RACSubject subject] setNameWithFormat:@"%@ -rac_signalForSelector: %s", self.rac_description, sel_getName(selector)];
        objc_setAssociatedObject(self, aliasSelector, subject, OBJC_ASSOCIATION_RETAIN);
        [self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
            [subject sendCompleted];
        }]];
        Method targetMethod = class_getInstanceMethod(class, selector);
        if (targetMethod == NULL) {
            const char *typeEncoding;
            if (protocol == NULL) {
                typeEncoding = RACSignatureForUndefinedSelector(selector);
            } else {
                // Look for the selector as an optional instance method.
                struct objc_method_description methodDescription = protocol_getMethodDescription(protocol, selector, NO, YES);
                if (methodDescription.name == NULL) {
                    // Then fall back to looking for a required instance
                    // method.
                    methodDescription = protocol_getMethodDescription(protocol, selector, YES, YES);
                    NSCAssert(methodDescription.name != NULL, @"Selector %@ does not exist in <%s>", NSStringFromSelector(selector), protocol_getName(protocol));
                }
                typeEncoding = methodDescription.types;
            }
            RACCheckTypeEncoding(typeEncoding);
            // Define the selector to call -forwardInvocation:.
            if (!class_addMethod(class, selector, _objc_msgForward, typeEncoding)) {
                NSDictionary *userInfo = @{
                    NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedString(@"A race condition occurred implementing %@ on class %@", nil), NSStringFromSelector(selector), class],
                    NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Invoke -rac_signalForSelector: again to override the implementation.", nil)
                };
                return [RACSignal error:[NSError errorWithDomain:RACSelectorSignalErrorDomain code:RACSelectorSignalErrorMethodSwizzlingRace userInfo:userInfo]];
            }
        } else if (method_getImplementation(targetMethod) != _objc_msgForward) {
            // Make a method alias for the existing method implementation.
            const char *typeEncoding = method_getTypeEncoding(targetMethod);
            RACCheckTypeEncoding(typeEncoding);
            BOOL addedAlias __attribute__((unused)) = class_addMethod(class, aliasSelector, method_getImplementation(targetMethod), typeEncoding);
            NSCAssert(addedAlias, @"Original implementation for %@ is already copied to %@ on %@", NSStringFromSelector(selector), NSStringFromSelector(aliasSelector), class);
            // Redefine the selector to call -forwardInvocation:.
            class_replaceMethod(class, selector, _objc_msgForward, method_getTypeEncoding(targetMethod));
        }
        return subject;
    }
}
static SEL RACAliasForSelector(SEL originalSelector) {
    NSString *selectorName = NSStringFromSelector(originalSelector);
    return NSSelectorFromString([RACSignalForSelectorAliasPrefix stringByAppendingString:selectorName]);
}
static const char *RACSignatureForUndefinedSelector(SEL selector) {
    const char *name = sel_getName(selector);
    NSMutableString *signature = [NSMutableString stringWithString:@"v@:"];
    while ((name = strchr(name, ':')) != NULL) {
        [signature appendString:@"@"];
        name++;
    }
    return signature.UTF8String;
}
static Class RACSwizzleClass(NSObject *self) {
    Class statedClass = self.class;
    Class baseClass = object_getClass(self);
    // The "known dynamic subclass" is the subclass generated by RAC.
    // It's stored as an associated object on every instance that's already
    // been swizzled, so that even if something else swizzles the class of
    // this instance, we can still access the RAC generated subclass.
    Class knownDynamicSubclass = objc_getAssociatedObject(self, RACSubclassAssociationKey);
    if (knownDynamicSubclass != Nil) return knownDynamicSubclass;
    NSString *className = NSStringFromClass(baseClass);
    if (statedClass != baseClass) {
        // If the class is already lying about what it is, it's probably a KVO
        // dynamic subclass or something else that we shouldn't subclass
        // ourselves.
        //
        // Just swizzle -forwardInvocation: in-place. Since the object's class
        // was almost certainly dynamically changed, we shouldn't see another of
        // these classes in the hierarchy.
        //
        // Additionally, swizzle -respondsToSelector: because the default
        // implementation may be ignorant of methods added to this class.
        @synchronized (swizzledClasses()) {
            if (![swizzledClasses() containsObject:className]) {
                RACSwizzleForwardInvocation(baseClass);
                RACSwizzleRespondsToSelector(baseClass);
                RACSwizzleGetClass(baseClass, statedClass);
                RACSwizzleGetClass(object_getClass(baseClass), statedClass);
                RACSwizzleMethodSignatureForSelector(baseClass);
                [swizzledClasses() addObject:className];
            }
        }
        return baseClass;
    }
    const char *subclassName = [className stringByAppendingString:RACSubclassSuffix].UTF8String;
    Class subclass = objc_getClass(subclassName);
    if (subclass == nil) {
        subclass = [RACObjCRuntime createClass:subclassName inheritingFromClass:baseClass];
        if (subclass == nil) return nil;
        RACSwizzleForwardInvocation(subclass);
        RACSwizzleRespondsToSelector(subclass);
        RACSwizzleGetClass(subclass, statedClass);
        RACSwizzleGetClass(object_getClass(subclass), statedClass);
        RACSwizzleMethodSignatureForSelector(subclass);
        objc_registerClassPair(subclass);
    }
    object_setClass(self, subclass);
    objc_setAssociatedObject(self, RACSubclassAssociationKey, subclass, OBJC_ASSOCIATION_ASSIGN);
    return subclass;
}
- (RACSignal *)rac_signalForSelector:(SEL)selector {
    NSCParameterAssert(selector != NULL);
    return NSObjectRACSignalForSelector(self, selector, NULL);
}
- (RACSignal *)rac_signalForSelector:(SEL)selector fromProtocol:(Protocol *)protocol {
    NSCParameterAssert(selector != NULL);
    NSCParameterAssert(protocol != NULL);
    return NSObjectRACSignalForSelector(self, selector, protocol);
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSOrderedSet+RACSequenceAdditions.h
New file
@@ -0,0 +1,20 @@
//
//  NSOrderedSet+RACSequenceAdditions.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSequence;
@interface NSOrderedSet (RACSequenceAdditions)
/// Creates and returns a sequence corresponding to the receiver.
///
/// Mutating the receiver will not affect the sequence after it's been created.
@property (nonatomic, copy, readonly) RACSequence *rac_sequence;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSOrderedSet+RACSequenceAdditions.m
New file
@@ -0,0 +1,19 @@
//
//  NSOrderedSet+RACSequenceAdditions.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "NSOrderedSet+RACSequenceAdditions.h"
#import "NSArray+RACSequenceAdditions.h"
@implementation NSOrderedSet (RACSequenceAdditions)
- (RACSequence *)rac_sequence {
    // TODO: First class support for ordered set sequences.
    return self.array.rac_sequence;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSSet+RACSequenceAdditions.h
New file
@@ -0,0 +1,20 @@
//
//  NSSet+RACSequenceAdditions.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSequence;
@interface NSSet (RACSequenceAdditions)
/// Creates and returns a sequence corresponding to the receiver.
///
/// Mutating the receiver will not affect the sequence after it's been created.
@property (nonatomic, copy, readonly) RACSequence *rac_sequence;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSSet+RACSequenceAdditions.m
New file
@@ -0,0 +1,19 @@
//
//  NSSet+RACSequenceAdditions.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "NSSet+RACSequenceAdditions.h"
#import "NSArray+RACSequenceAdditions.h"
@implementation NSSet (RACSequenceAdditions)
- (RACSequence *)rac_sequence {
    // TODO: First class support for set sequences.
    return self.allObjects.rac_sequence;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSString+RACKeyPathUtilities.h
New file
@@ -0,0 +1,34 @@
//
//  NSString+RACKeyPathUtilities.h
//  ReactiveCocoa
//
//  Created by Uri Baghin on 05/05/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
// A private category of methods to extract parts of a key path.
@interface NSString (RACKeyPathUtilities)
// Returns an array of the components of the receiver.
//
// Calling this method on a string that isn't a key path is considered undefined
// behavior.
- (NSArray *)rac_keyPathComponents;
// Returns a key path with all the components of the receiver except for the
// last one.
//
// Calling this method on a string that isn't a key path is considered undefined
// behavior.
- (NSString *)rac_keyPathByDeletingLastKeyPathComponent;
// Returns a key path with all the components of the receiver expect for the
// first one.
//
// Calling this method on a string that isn't a key path is considered undefined
// behavior.
- (NSString *)rac_keyPathByDeletingFirstKeyPathComponent;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSString+RACKeyPathUtilities.m
New file
@@ -0,0 +1,36 @@
//
//  NSString+RACKeyPathUtilities.m
//  ReactiveCocoa
//
//  Created by Uri Baghin on 05/05/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "NSString+RACKeyPathUtilities.h"
@implementation NSString (RACKeyPathUtilities)
- (NSArray *)rac_keyPathComponents {
    if (self.length == 0) {
        return nil;
    }
    return [self componentsSeparatedByString:@"."];
}
- (NSString *)rac_keyPathByDeletingLastKeyPathComponent {
    NSUInteger lastDotIndex = [self rangeOfString:@"." options:NSBackwardsSearch].location;
    if (lastDotIndex == NSNotFound) {
        return nil;
    }
    return [self substringToIndex:lastDotIndex];
}
- (NSString *)rac_keyPathByDeletingFirstKeyPathComponent {
    NSUInteger firstDotIndex = [self rangeOfString:@"."].location;
    if (firstDotIndex == NSNotFound) {
        return nil;
    }
    return [self substringFromIndex:firstDotIndex + 1];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSString+RACSequenceAdditions.h
New file
@@ -0,0 +1,21 @@
//
//  NSString+RACSequenceAdditions.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSequence;
@interface NSString (RACSequenceAdditions)
/// Creates and returns a sequence containing strings corresponding to each
/// composed character sequence in the receiver.
///
/// Mutating the receiver will not affect the sequence after it's been created.
@property (nonatomic, copy, readonly) RACSequence *rac_sequence;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSString+RACSequenceAdditions.m
New file
@@ -0,0 +1,18 @@
//
//  NSString+RACSequenceAdditions.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "NSString+RACSequenceAdditions.h"
#import "RACStringSequence.h"
@implementation NSString (RACSequenceAdditions)
- (RACSequence *)rac_sequence {
    return [RACStringSequence sequenceWithString:self offset:0];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSString+RACSupport.h
New file
@@ -0,0 +1,22 @@
//
//  NSString+RACSupport.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 5/11/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACScheduler;
@class RACSignal;
@interface NSString (RACSupport)
// Reads in the contents of the file using +[NSString stringWithContentsOfURL:usedEncoding:error:].
// Note that encoding won't be valid until the signal completes successfully.
//
// scheduler - cannot be nil.
+ (RACSignal *)rac_readContentsOfURL:(NSURL *)URL usedEncoding:(NSStringEncoding *)encoding scheduler:(RACScheduler *)scheduler;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSString+RACSupport.m
New file
@@ -0,0 +1,35 @@
//
//  NSString+RACSupport.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 5/11/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "NSString+RACSupport.h"
#import "RACReplaySubject.h"
#import "RACScheduler.h"
@implementation NSString (RACSupport)
+ (RACSignal *)rac_readContentsOfURL:(NSURL *)URL usedEncoding:(NSStringEncoding *)encoding scheduler:(RACScheduler *)scheduler {
    NSCParameterAssert(scheduler != nil);
    RACReplaySubject *subject = [RACReplaySubject subject];
    [subject setNameWithFormat:@"+rac_readContentsOfURL: %@ usedEncoding:scheduler: %@", URL, scheduler];
    [scheduler schedule:^{
        NSError *error = nil;
        NSString *string = [NSString stringWithContentsOfURL:URL usedEncoding:encoding error:&error];
        if (string == nil) {
            [subject sendError:error];
        } else {
            [subject sendNext:string];
            [subject sendCompleted];
        }
    }];
    return subject;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSURLConnection+RACSupport.h
New file
@@ -0,0 +1,25 @@
//
//  NSURLConnection+RACSupport.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-10-01.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSignal;
@interface NSURLConnection (RACSupport)
// Lazily loads data for the given request in the background.
//
// request - The URL request to load. This must not be nil.
//
// Returns a signal which will begin loading the request upon each subscription,
// then send a `RACTuple` of the received `NSURLResponse` and downloaded
// `NSData`, and complete on a background thread. If any errors occur, the
// returned signal will error out.
+ (RACSignal *)rac_sendAsynchronousRequest:(NSURLRequest *)request;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSURLConnection+RACSupport.m
New file
@@ -0,0 +1,52 @@
//
//  NSURLConnection+RACSupport.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-10-01.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "NSURLConnection+RACSupport.h"
#import "RACDisposable.h"
#import "RACSignal.h"
#import "RACSubscriber.h"
#import "RACTuple.h"
@implementation NSURLConnection (RACSupport)
+ (RACSignal *)rac_sendAsynchronousRequest:(NSURLRequest *)request {
    NSCParameterAssert(request != nil);
    return [[RACSignal
        createSignal:^(id<RACSubscriber> subscriber) {
            NSOperationQueue *queue = [[NSOperationQueue alloc] init];
            queue.name = @"org.reactivecocoa.ReactiveCocoa.NSURLConnectionRACSupport";
            [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                // The docs say that `nil` data means an error occurred, but
                // `nil` responses can also occur in practice (circumstances
                // unknown). Consider either to be an error.
                //
                // Note that _empty_ data is not necessarily erroneous, as there
                // may be headers but no HTTP body.
                if (response == nil || data == nil) {
                    [subscriber sendError:error];
                } else {
                    [subscriber sendNext:RACTuplePack(response, data)];
                    [subscriber sendCompleted];
                }
            }];
            return [RACDisposable disposableWithBlock:^{
                // It's not clear if this will actually cancel the connection,
                // but we can at least prevent _some_ unnecessary work --
                // without writing all the code for a proper delegate, which
                // doesn't really belong in RAC.
                queue.suspended = YES;
                [queue cancelAllOperations];
            }];
        }]
        setNameWithFormat:@"+rac_sendAsynchronousRequest: %@", request];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSUserDefaults+RACSupport.h
New file
@@ -0,0 +1,27 @@
//
//  NSUserDefaults+RACSupport.h
//  ReactiveCocoa
//
//  Created by Matt Diephouse on 12/19/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACChannelTerminal;
@interface NSUserDefaults (RACSupport)
/// Creates and returns a terminal for binding the user defaults key.
///
/// **Note:** The value in the user defaults is *asynchronously* updated with
/// values sent to the channel.
///
/// key - The user defaults key to create the channel terminal for.
///
/// Returns a channel terminal that sends the value of the user defaults key
/// upon subscription, sends an updated value whenever the default changes, and
/// updates the default asynchronously with values it receives.
- (RACChannelTerminal *)rac_channelTerminalForKey:(NSString *)key;
@end
Pods/ReactiveCocoa/ReactiveCocoa/NSUserDefaults+RACSupport.m
New file
@@ -0,0 +1,56 @@
//
//  NSUserDefaults+RACSupport.m
//  ReactiveCocoa
//
//  Created by Matt Diephouse on 12/19/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "NSUserDefaults+RACSupport.h"
#import "RACEXTScope.h"
#import "NSNotificationCenter+RACSupport.h"
#import "NSObject+RACDeallocating.h"
#import "RACChannel.h"
#import "RACScheduler.h"
#import "RACSignal+Operations.h"
@implementation NSUserDefaults (RACSupport)
- (RACChannelTerminal *)rac_channelTerminalForKey:(NSString *)key {
    RACChannel *channel = [RACChannel new];
    RACScheduler *scheduler = [RACScheduler scheduler];
    __block BOOL ignoreNextValue = NO;
    @weakify(self);
    [[[[[[[NSNotificationCenter.defaultCenter
        rac_addObserverForName:NSUserDefaultsDidChangeNotification object:self]
        map:^(id _) {
            @strongify(self);
            return [self objectForKey:key];
        }]
        startWith:[self objectForKey:key]]
        // Don't send values that were set on the other side of the terminal.
        filter:^ BOOL (id _) {
            if (RACScheduler.currentScheduler == scheduler && ignoreNextValue) {
                ignoreNextValue = NO;
                return NO;
            }
            return YES;
        }]
        distinctUntilChanged]
        takeUntil:self.rac_willDeallocSignal]
        subscribe:channel.leadingTerminal];
    [[channel.leadingTerminal
        deliverOn:scheduler]
        subscribeNext:^(id value) {
            @strongify(self);
            ignoreNextValue = YES;
            [self setObject:value forKey:key];
        }];
    return channel.followingTerminal;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACArraySequence.h
New file
@@ -0,0 +1,18 @@
//
//  RACArraySequence.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "RACSequence.h"
// Private class that adapts an array to the RACSequence interface.
@interface RACArraySequence : RACSequence
// Returns a sequence for enumerating over the given array, starting from the
// given offset. The array will be copied to prevent mutation.
+ (instancetype)sequenceWithArray:(NSArray *)array offset:(NSUInteger)offset;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACArraySequence.m
New file
@@ -0,0 +1,125 @@
//
//  RACArraySequence.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "RACArraySequence.h"
@interface RACArraySequence ()
// Redeclared from the superclass and marked deprecated to prevent using `array`
// where `backingArray` is intended.
@property (nonatomic, copy, readonly) NSArray *array __attribute__((deprecated));
// The array being sequenced.
@property (nonatomic, copy, readonly) NSArray *backingArray;
// The index in the array from which the sequence starts.
@property (nonatomic, assign, readonly) NSUInteger offset;
@end
@implementation RACArraySequence
#pragma mark Lifecycle
+ (instancetype)sequenceWithArray:(NSArray *)array offset:(NSUInteger)offset {
    NSCParameterAssert(offset <= array.count);
    if (offset == array.count) return self.empty;
    RACArraySequence *seq = [[self alloc] init];
    seq->_backingArray = [array copy];
    seq->_offset = offset;
    return seq;
}
#pragma mark RACSequence
- (id)head {
    return self.backingArray[self.offset];
}
- (RACSequence *)tail {
    RACSequence *sequence = [self.class sequenceWithArray:self.backingArray offset:self.offset + 1];
    sequence.name = self.name;
    return sequence;
}
#pragma mark NSFastEnumeration
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id[])stackbuf count:(NSUInteger)len {
    NSCParameterAssert(len > 0);
    if (state->state >= self.backingArray.count) {
        // Enumeration has completed.
        return 0;
    }
    if (state->state == 0) {
        state->state = self.offset;
        // Since a sequence doesn't mutate, this just needs to be set to
        // something non-NULL.
        state->mutationsPtr = state->extra;
    }
    state->itemsPtr = stackbuf;
    NSUInteger startIndex = state->state;
    NSUInteger index = 0;
    for (id value in self.backingArray) {
        // Constructing an index set for -enumerateObjectsAtIndexes: can actually be
        // slower than just skipping the items we don't care about.
        if (index < startIndex) {
            ++index;
            continue;
        }
        stackbuf[index - startIndex] = value;
        ++index;
        if (index - startIndex >= len) break;
    }
    NSCAssert(index > startIndex, @"Final index (%lu) should be greater than start index (%lu)", (unsigned long)index, (unsigned long)startIndex);
    state->state = index;
    return index - startIndex;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
- (NSArray *)array {
    return [self.backingArray subarrayWithRange:NSMakeRange(self.offset, self.backingArray.count - self.offset)];
}
#pragma clang diagnostic pop
#pragma mark NSCoding
- (id)initWithCoder:(NSCoder *)coder {
    self = [super initWithCoder:coder];
    if (self == nil) return nil;
    _backingArray = [coder decodeObjectForKey:@"array"];
    _offset = 0;
    return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
    // Encoding is handled in RACSequence.
    [super encodeWithCoder:coder];
}
#pragma mark NSObject
- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: %p>{ name = %@, array = %@ }", self.class, self, self.name, self.backingArray];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACBehaviorSubject.h
New file
@@ -0,0 +1,18 @@
//
//  RACBehaviorSubject.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/16/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACSubject.h"
/// A behavior subject sends the last value it received when it is subscribed to.
@interface RACBehaviorSubject : RACSubject
/// Creates a new behavior subject with a default value. If it hasn't received
/// any values when it gets subscribed to, it sends the default value.
+ (instancetype)behaviorSubjectWithDefaultValue:(id)value;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACBehaviorSubject.m
New file
@@ -0,0 +1,56 @@
//
//  RACBehaviorSubject.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/16/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACBehaviorSubject.h"
#import "RACDisposable.h"
#import "RACScheduler+Private.h"
@interface RACBehaviorSubject ()
// This property should only be used while synchronized on self.
@property (nonatomic, strong) id currentValue;
@end
@implementation RACBehaviorSubject
#pragma mark Lifecycle
+ (instancetype)behaviorSubjectWithDefaultValue:(id)value {
    RACBehaviorSubject *subject = [self subject];
    subject.currentValue = value;
    return subject;
}
#pragma mark RACSignal
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    RACDisposable *subscriptionDisposable = [super subscribe:subscriber];
    RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
        @synchronized (self) {
            [subscriber sendNext:self.currentValue];
        }
    }];
    return [RACDisposable disposableWithBlock:^{
        [subscriptionDisposable dispose];
        [schedulingDisposable dispose];
    }];
}
#pragma mark RACSubscriber
- (void)sendNext:(id)value {
    @synchronized (self) {
        self.currentValue = value;
        [super sendNext:value];
    }
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACBlockTrampoline.h
New file
@@ -0,0 +1,30 @@
//
//  RACBlockTrampoline.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 10/21/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACTuple;
// A private class that allows a limited type of dynamic block invocation.
@interface RACBlockTrampoline : NSObject
// Invokes the given block with the given arguments. All of the block's
// argument types must be objects and it must be typed to return an object.
//
// At this time, it only supports blocks that take up to 15 arguments. Any more
// is just cray.
//
// block     - The block to invoke. Must accept as many arguments as are given in
//             the arguments array. Cannot be nil.
// arguments - The arguments with which to invoke the block. `RACTupleNil`s will
//             be passed as nils.
//
// Returns the return value of invoking the block.
+ (id)invokeBlock:(id)block withArguments:(RACTuple *)arguments;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACBlockTrampoline.m
New file
@@ -0,0 +1,156 @@
//
//  RACBlockTrampoline.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 10/21/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACBlockTrampoline.h"
#import "RACTuple.h"
@interface RACBlockTrampoline ()
@property (nonatomic, readonly, copy) id block;
@end
@implementation RACBlockTrampoline
#pragma mark API
- (id)initWithBlock:(id)block {
    self = [super init];
    if (self == nil) return nil;
    _block = [block copy];
    return self;
}
+ (id)invokeBlock:(id)block withArguments:(RACTuple *)arguments {
    NSCParameterAssert(block != NULL);
    RACBlockTrampoline *trampoline = [[self alloc] initWithBlock:block];
    return [trampoline invokeWithArguments:arguments];
}
- (id)invokeWithArguments:(RACTuple *)arguments {
    SEL selector = [self selectorForArgumentCount:arguments.count];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:selector]];
    invocation.selector = selector;
    invocation.target = self;
    for (NSUInteger i = 0; i < arguments.count; i++) {
        id arg = arguments[i];
        NSInteger argIndex = (NSInteger)(i + 2);
        [invocation setArgument:&arg atIndex:argIndex];
    }
    [invocation invoke];
    __unsafe_unretained id returnVal;
    [invocation getReturnValue:&returnVal];
    return returnVal;
}
- (SEL)selectorForArgumentCount:(NSUInteger)count {
    NSCParameterAssert(count > 0);
    switch (count) {
        case 0: return NULL;
        case 1: return @selector(performWith:);
        case 2: return @selector(performWith::);
        case 3: return @selector(performWith:::);
        case 4: return @selector(performWith::::);
        case 5: return @selector(performWith:::::);
        case 6: return @selector(performWith::::::);
        case 7: return @selector(performWith:::::::);
        case 8: return @selector(performWith::::::::);
        case 9: return @selector(performWith:::::::::);
        case 10: return @selector(performWith::::::::::);
        case 11: return @selector(performWith:::::::::::);
        case 12: return @selector(performWith::::::::::::);
        case 13: return @selector(performWith:::::::::::::);
        case 14: return @selector(performWith::::::::::::::);
        case 15: return @selector(performWith:::::::::::::::);
    }
    NSCAssert(NO, @"The argument count is too damn high! Only blocks of up to 15 arguments are currently supported.");
    return NULL;
}
- (id)performWith:(id)obj1 {
    id (^block)(id) = self.block;
    return block(obj1);
}
- (id)performWith:(id)obj1 :(id)obj2 {
    id (^block)(id, id) = self.block;
    return block(obj1, obj2);
}
- (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 {
    id (^block)(id, id, id) = self.block;
    return block(obj1, obj2, obj3);
}
- (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 {
    id (^block)(id, id, id, id) = self.block;
    return block(obj1, obj2, obj3, obj4);
}
- (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 {
    id (^block)(id, id, id, id, id) = self.block;
    return block(obj1, obj2, obj3, obj4, obj5);
}
- (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 {
    id (^block)(id, id, id, id, id, id) = self.block;
    return block(obj1, obj2, obj3, obj4, obj5, obj6);
}
- (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 {
    id (^block)(id, id, id, id, id, id, id) = self.block;
    return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7);
}
- (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 {
    id (^block)(id, id, id, id, id, id, id, id) = self.block;
    return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8);
}
- (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 {
    id (^block)(id, id, id, id, id, id, id, id, id) = self.block;
    return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9);
}
- (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 :(id)obj10 {
    id (^block)(id, id, id, id, id, id, id, id, id, id) = self.block;
    return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10);
}
- (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 :(id)obj10 :(id)obj11 {
    id (^block)(id, id, id, id, id, id, id, id, id, id, id) = self.block;
    return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11);
}
- (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 :(id)obj10 :(id)obj11 :(id)obj12 {
    id (^block)(id, id, id, id, id, id, id, id, id, id, id, id) = self.block;
    return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12);
}
- (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 :(id)obj10 :(id)obj11 :(id)obj12 :(id)obj13 {
    id (^block)(id, id, id, id, id, id, id, id, id, id, id, id, id) = self.block;
    return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13);
}
- (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 :(id)obj10 :(id)obj11 :(id)obj12 :(id)obj13 :(id)obj14 {
    id (^block)(id, id, id, id, id, id, id, id, id, id, id, id, id, id) = self.block;
    return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13, obj14);
}
- (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 :(id)obj10 :(id)obj11 :(id)obj12 :(id)obj13 :(id)obj14 :(id)obj15 {
    id (^block)(id, id, id, id, id, id, id, id, id, id, id, id, id, id, id) = self.block;
    return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13, obj14, obj15);
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACChannel.h
New file
@@ -0,0 +1,70 @@
//
//  RACChannel.h
//  ReactiveCocoa
//
//  Created by Uri Baghin on 01/01/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACSignal.h"
#import "RACSubscriber.h"
@class RACChannelTerminal;
/// A two-way channel.
///
/// Conceptually, RACChannel can be thought of as a bidirectional connection,
/// composed of two controllable signals that work in parallel.
///
/// For example, when connecting between a view and a model:
///
///        Model                      View
///  `leadingTerminal` ------> `followingTerminal`
///  `leadingTerminal` <------ `followingTerminal`
///
/// The initial value of the model and all future changes to it are _sent on_ the
/// `leadingTerminal`, and _received by_ subscribers of the `followingTerminal`.
///
/// Likewise, whenever the user changes the value of the view, that value is sent
/// on the `followingTerminal`, and received in the model from the
/// `leadingTerminal`. However, the initial value of the view is not received
/// from the `leadingTerminal` (only future changes).
@interface RACChannel : NSObject
/// The terminal which "leads" the channel, by sending its latest value
/// immediately to new subscribers of the `followingTerminal`.
///
/// New subscribers to this terminal will not receive a starting value, but will
/// receive all future values that are sent to the `followingTerminal`.
@property (nonatomic, strong, readonly) RACChannelTerminal *leadingTerminal;
/// The terminal which "follows" the lead of the other terminal, only sending
/// _future_ values to the subscribers of the `leadingTerminal`.
///
/// The latest value sent to the `leadingTerminal` (if any) will be sent
/// immediately to new subscribers of this terminal, and then all future values
/// as well.
@property (nonatomic, strong, readonly) RACChannelTerminal *followingTerminal;
@end
/// Represents one end of a RACChannel.
///
/// An terminal is similar to a socket or pipe -- it represents one end of
/// a connection (the RACChannel, in this case). Values sent to this terminal
/// will _not_ be received by its subscribers. Instead, the values will be sent
/// to the subscribers of the RACChannel's _other_ terminal.
///
/// For example, when using the `followingTerminal`, _sent_ values can only be
/// _received_ from the `leadingTerminal`, and vice versa.
///
/// To make it easy to terminate a RACChannel, `error` and `completed` events
/// sent to either terminal will be received by the subscribers of _both_
/// terminals.
///
/// Do not instantiate this class directly. Create a RACChannel instead.
@interface RACChannelTerminal : RACSignal <RACSubscriber>
- (id)init __attribute__((unavailable("Instantiate a RACChannel instead")));
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACChannel.m
New file
@@ -0,0 +1,90 @@
//
//  RACChannel.m
//  ReactiveCocoa
//
//  Created by Uri Baghin on 01/01/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACChannel.h"
#import "RACDisposable.h"
#import "RACReplaySubject.h"
#import "RACSignal+Operations.h"
@interface RACChannelTerminal ()
// The values for this terminal.
@property (nonatomic, strong, readonly) RACSignal *values;
// A subscriber will will send values to the other terminal.
@property (nonatomic, strong, readonly) id<RACSubscriber> otherTerminal;
- (id)initWithValues:(RACSignal *)values otherTerminal:(id<RACSubscriber>)otherTerminal;
@end
@implementation RACChannel
- (id)init {
    self = [super init];
    if (self == nil) return nil;
    // We don't want any starting value from the leadingSubject, but we do want
    // error and completion to be replayed.
    RACReplaySubject *leadingSubject = [[RACReplaySubject replaySubjectWithCapacity:0] setNameWithFormat:@"leadingSubject"];
    RACReplaySubject *followingSubject = [[RACReplaySubject replaySubjectWithCapacity:1] setNameWithFormat:@"followingSubject"];
    // Propagate errors and completion to everything.
    [[leadingSubject ignoreValues] subscribe:followingSubject];
    [[followingSubject ignoreValues] subscribe:leadingSubject];
    _leadingTerminal = [[[RACChannelTerminal alloc] initWithValues:leadingSubject otherTerminal:followingSubject] setNameWithFormat:@"leadingTerminal"];
    _followingTerminal = [[[RACChannelTerminal alloc] initWithValues:followingSubject otherTerminal:leadingSubject] setNameWithFormat:@"followingTerminal"];
    return self;
}
@end
@implementation RACChannelTerminal
#pragma mark Lifecycle
- (id)initWithValues:(RACSignal *)values otherTerminal:(id<RACSubscriber>)otherTerminal {
    NSCParameterAssert(values != nil);
    NSCParameterAssert(otherTerminal != nil);
    self = [super init];
    if (self == nil) return nil;
    _values = values;
    _otherTerminal = otherTerminal;
    return self;
}
#pragma mark RACSignal
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    return [self.values subscribe:subscriber];
}
#pragma mark <RACSubscriber>
- (void)sendNext:(id)value {
    [self.otherTerminal sendNext:value];
}
- (void)sendError:(NSError *)error {
    [self.otherTerminal sendError:error];
}
- (void)sendCompleted {
    [self.otherTerminal sendCompleted];
}
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable {
    [self.otherTerminal didSubscribeWithDisposable:disposable];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACCommand.h
New file
@@ -0,0 +1,123 @@
//
//  RACCommand.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/3/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSignal;
/// The domain for errors originating within `RACCommand`.
extern NSString * const RACCommandErrorDomain;
/// -execute: was invoked while the command was disabled.
extern const NSInteger RACCommandErrorNotEnabled;
/// A `userInfo` key for an error, associated with the `RACCommand` that the
/// error originated from.
///
/// This is included only when the error code is `RACCommandErrorNotEnabled`.
extern NSString * const RACUnderlyingCommandErrorKey;
/// A command is a signal triggered in response to some action, typically
/// UI-related.
@interface RACCommand : NSObject
/// A signal of the signals returned by successful invocations of -execute:
/// (i.e., while the receiver is `enabled`).
///
/// Errors will be automatically caught upon the inner signals, and sent upon
/// `errors` instead. If you _want_ to receive inner errors, use -execute: or
/// -[RACSignal materialize].
///
/// Only executions that begin _after_ subscription will be sent upon this
/// signal. All inner signals will arrive upon the main thread.
@property (nonatomic, strong, readonly) RACSignal *executionSignals;
/// A signal of whether this command is currently executing.
///
/// This will send YES whenever -execute: is invoked and the created signal has
/// not yet terminated. Once all executions have terminated, `executing` will
/// send NO.
///
/// This signal will send its current value upon subscription, and then all
/// future values on the main thread.
@property (nonatomic, strong, readonly) RACSignal *executing;
/// A signal of whether this command is able to execute.
///
/// This will send NO if:
///
///  - The command was created with an `enabledSignal`, and NO is sent upon that
///    signal, or
///  - `allowsConcurrentExecution` is NO and the command has started executing.
///
/// Once the above conditions are no longer met, the signal will send YES.
///
/// This signal will send its current value upon subscription, and then all
/// future values on the main thread.
@property (nonatomic, strong, readonly) RACSignal *enabled;
/// Forwards any errors that occur within signals returned by -execute:.
///
/// When an error occurs on a signal returned from -execute:, this signal will
/// send the associated NSError value as a `next` event (since an `error` event
/// would terminate the stream).
///
/// After subscription, this signal will send all future errors on the main
/// thread.
@property (nonatomic, strong, readonly) RACSignal *errors;
/// Whether the command allows multiple executions to proceed concurrently.
///
/// The default value for this property is NO.
@property (atomic, assign) BOOL allowsConcurrentExecution;
/// Invokes -initWithEnabled:signalBlock: with a nil `enabledSignal`.
- (id)initWithSignalBlock:(RACSignal * (^)(id input))signalBlock;
/// Initializes a command that is conditionally enabled.
///
/// This is the designated initializer for this class.
///
/// enabledSignal - A signal of BOOLs which indicate whether the command should
///                 be enabled. `enabled` will be based on the latest value sent
///                 from this signal. Before any values are sent, `enabled` will
///                 default to YES. This argument may be nil.
/// signalBlock   - A block which will map each input value (passed to -execute:)
///                 to a signal of work. The returned signal will be multicasted
///                 to a replay subject, sent on `executionSignals`, then
///                 subscribed to synchronously. Neither the block nor the
///                 returned signal may be nil.
- (id)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal * (^)(id input))signalBlock;
/// If the receiver is enabled, this method will:
///
///  1. Invoke the `signalBlock` given at the time of initialization.
///  2. Multicast the returned signal to a RACReplaySubject.
///  3. Send the multicasted signal on `executionSignals`.
///  4. Subscribe (connect) to the original signal on the main thread.
///
/// input - The input value to pass to the receiver's `signalBlock`. This may be
///         nil.
///
/// Returns the multicasted signal, after subscription. If the receiver is not
/// enabled, returns a signal that will send an error with code
/// RACCommandErrorNotEnabled.
- (RACSignal *)execute:(id)input;
@end
@interface RACCommand (Unavailable)
@property (atomic, readonly) BOOL canExecute __attribute__((unavailable("Use the 'enabled' signal instead")));
+ (instancetype)command __attribute__((unavailable("Use -initWithSignalBlock: instead")));
+ (instancetype)commandWithCanExecuteSignal:(RACSignal *)canExecuteSignal __attribute__((unavailable("Use -initWithEnabled:signalBlock: instead")));
- (id)initWithCanExecuteSignal:(RACSignal *)canExecuteSignal __attribute__((unavailable("Use -initWithEnabled:signalBlock: instead")));
- (RACSignal *)addSignalBlock:(RACSignal * (^)(id value))signalBlock __attribute__((unavailable("Pass the signalBlock to -initWithSignalBlock: instead")));
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACCommand.m
New file
@@ -0,0 +1,267 @@
//
//  RACCommand.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/3/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACCommand.h"
#import "RACEXTScope.h"
#import "NSArray+RACSequenceAdditions.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACDescription.h"
#import "NSObject+RACPropertySubscribing.h"
#import "RACMulticastConnection.h"
#import "RACReplaySubject.h"
#import "RACScheduler.h"
#import "RACSequence.h"
#import "RACSignal+Operations.h"
#import <libkern/OSAtomic.h>
NSString * const RACCommandErrorDomain = @"RACCommandErrorDomain";
NSString * const RACUnderlyingCommandErrorKey = @"RACUnderlyingCommandErrorKey";
const NSInteger RACCommandErrorNotEnabled = 1;
@interface RACCommand () {
    // The mutable array backing `activeExecutionSignals`.
    //
    // This should only be used while synchronized on `self`.
    NSMutableArray *_activeExecutionSignals;
    // Atomic backing variable for `allowsConcurrentExecution`.
    volatile uint32_t _allowsConcurrentExecution;
}
// An array of signals representing in-flight executions, in the order they
// began.
//
// This property is KVO-compliant.
@property (atomic, copy, readonly) NSArray *activeExecutionSignals;
// `enabled`, but without a hop to the main thread.
//
// Values from this signal may arrive on any thread.
@property (nonatomic, strong, readonly) RACSignal *immediateEnabled;
// The signal block that the receiver was initialized with.
@property (nonatomic, copy, readonly) RACSignal * (^signalBlock)(id input);
// Adds a signal to `activeExecutionSignals` and generates a KVO notification.
- (void)addActiveExecutionSignal:(RACSignal *)signal;
// Removes a signal from `activeExecutionSignals` and generates a KVO
// notification.
- (void)removeActiveExecutionSignal:(RACSignal *)signal;
@end
@implementation RACCommand
#pragma mark Properties
- (BOOL)allowsConcurrentExecution {
    return _allowsConcurrentExecution != 0;
}
- (void)setAllowsConcurrentExecution:(BOOL)allowed {
    [self willChangeValueForKey:@keypath(self.allowsConcurrentExecution)];
    if (allowed) {
        OSAtomicOr32Barrier(1, &_allowsConcurrentExecution);
    } else {
        OSAtomicAnd32Barrier(0, &_allowsConcurrentExecution);
    }
    [self didChangeValueForKey:@keypath(self.allowsConcurrentExecution)];
}
- (NSArray *)activeExecutionSignals {
    @synchronized (self) {
        return [_activeExecutionSignals copy];
    }
}
- (void)addActiveExecutionSignal:(RACSignal *)signal {
    NSCParameterAssert([signal isKindOfClass:RACSignal.class]);
    @synchronized (self) {
        // The KVO notification has to be generated while synchronized, because
        // it depends on the index remaining consistent.
        NSIndexSet *indexes = [NSIndexSet indexSetWithIndex:_activeExecutionSignals.count];
        [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:@keypath(self.activeExecutionSignals)];
        [_activeExecutionSignals addObject:signal];
        [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:@keypath(self.activeExecutionSignals)];
    }
}
- (void)removeActiveExecutionSignal:(RACSignal *)signal {
    NSCParameterAssert([signal isKindOfClass:RACSignal.class]);
    @synchronized (self) {
        // The indexes have to be calculated and the notification generated
        // while synchronized, because they depend on the indexes remaining
        // consistent.
        NSIndexSet *indexes = [_activeExecutionSignals indexesOfObjectsPassingTest:^ BOOL (RACSignal *obj, NSUInteger index, BOOL *stop) {
            return obj == signal;
        }];
        if (indexes.count == 0) return;
        [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:@keypath(self.activeExecutionSignals)];
        [_activeExecutionSignals removeObjectsAtIndexes:indexes];
        [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:@keypath(self.activeExecutionSignals)];
    }
}
#pragma mark Lifecycle
- (id)init {
    NSCAssert(NO, @"Use -initWithSignalBlock: instead");
    return nil;
}
- (id)initWithSignalBlock:(RACSignal * (^)(id input))signalBlock {
    return [self initWithEnabled:nil signalBlock:signalBlock];
}
- (id)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal * (^)(id input))signalBlock {
    NSCParameterAssert(signalBlock != nil);
    self = [super init];
    if (self == nil) return nil;
    _activeExecutionSignals = [[NSMutableArray alloc] init];
    _signalBlock = [signalBlock copy];
    // A signal of additions to `activeExecutionSignals`.
    RACSignal *newActiveExecutionSignals = [[[[[self
        rac_valuesAndChangesForKeyPath:@keypath(self.activeExecutionSignals) options:NSKeyValueObservingOptionNew observer:nil]
        reduceEach:^(id _, NSDictionary *change) {
            NSArray *signals = change[NSKeyValueChangeNewKey];
            if (signals == nil) return [RACSignal empty];
            return [signals.rac_sequence signalWithScheduler:RACScheduler.immediateScheduler];
        }]
        concat]
        publish]
        autoconnect];
    _executionSignals = [[[newActiveExecutionSignals
        map:^(RACSignal *signal) {
            return [signal catchTo:[RACSignal empty]];
        }]
        deliverOn:RACScheduler.mainThreadScheduler]
        setNameWithFormat:@"%@ -executionSignals", self];
    // `errors` needs to be multicasted so that it picks up all
    // `activeExecutionSignals` that are added.
    //
    // In other words, if someone subscribes to `errors` _after_ an execution
    // has started, it should still receive any error from that execution.
    RACMulticastConnection *errorsConnection = [[[newActiveExecutionSignals
        flattenMap:^(RACSignal *signal) {
            return [[signal
                ignoreValues]
                catch:^(NSError *error) {
                    return [RACSignal return:error];
                }];
        }]
        deliverOn:RACScheduler.mainThreadScheduler]
        publish];
    _errors = [errorsConnection.signal setNameWithFormat:@"%@ -errors", self];
    [errorsConnection connect];
    RACSignal *immediateExecuting = [RACObserve(self, activeExecutionSignals) map:^(NSArray *activeSignals) {
        return @(activeSignals.count > 0);
    }];
    _executing = [[[[[immediateExecuting
        deliverOn:RACScheduler.mainThreadScheduler]
        // This is useful before the first value arrives on the main thread.
        startWith:@NO]
        distinctUntilChanged]
        replayLast]
        setNameWithFormat:@"%@ -executing", self];
    RACSignal *moreExecutionsAllowed = [RACSignal
        if:RACObserve(self, allowsConcurrentExecution)
        then:[RACSignal return:@YES]
        else:[immediateExecuting not]];
    if (enabledSignal == nil) {
        enabledSignal = [RACSignal return:@YES];
    } else {
        enabledSignal = [[[enabledSignal
            startWith:@YES]
            takeUntil:self.rac_willDeallocSignal]
            replayLast];
    }
    _immediateEnabled = [[RACSignal
        combineLatest:@[ enabledSignal, moreExecutionsAllowed ]]
        and];
    _enabled = [[[[[self.immediateEnabled
        take:1]
        concat:[[self.immediateEnabled skip:1] deliverOn:RACScheduler.mainThreadScheduler]]
        distinctUntilChanged]
        replayLast]
        setNameWithFormat:@"%@ -enabled", self];
    return self;
}
#pragma mark Execution
- (RACSignal *)execute:(id)input {
    // `immediateEnabled` is guaranteed to send a value upon subscription, so
    // -first is acceptable here.
    BOOL enabled = [[self.immediateEnabled first] boolValue];
    if (!enabled) {
        NSError *error = [NSError errorWithDomain:RACCommandErrorDomain code:RACCommandErrorNotEnabled userInfo:@{
            NSLocalizedDescriptionKey: NSLocalizedString(@"The command is disabled and cannot be executed", nil),
            RACUnderlyingCommandErrorKey: self
        }];
        return [RACSignal error:error];
    }
    RACSignal *signal = self.signalBlock(input);
    NSCAssert(signal != nil, @"nil signal returned from signal block for value: %@", input);
    // We subscribe to the signal on the main thread so that it occurs _after_
    // -addActiveExecutionSignal: completes below.
    //
    // This means that `executing` and `enabled` will send updated values before
    // the signal actually starts performing work.
    RACMulticastConnection *connection = [[signal
        subscribeOn:RACScheduler.mainThreadScheduler]
        multicast:[RACReplaySubject subject]];
    @weakify(self);
    [self addActiveExecutionSignal:connection.signal];
    [connection.signal subscribeError:^(NSError *error) {
        @strongify(self);
        [self removeActiveExecutionSignal:connection.signal];
    } completed:^{
        @strongify(self);
        [self removeActiveExecutionSignal:connection.signal];
    }];
    [connection connect];
    return [connection.signal setNameWithFormat:@"%@ -execute: %@", self, [input rac_description]];
}
#pragma mark NSKeyValueObserving
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
    // Generate all KVO notifications manually to avoid the performance impact
    // of unnecessary swizzling.
    return NO;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACCompoundDisposable.h
New file
@@ -0,0 +1,48 @@
//
//  RACCompoundDisposable.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 11/30/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACDisposable.h"
/// A disposable of disposables. When it is disposed, it disposes of all its
/// contained disposables.
///
/// If -addDisposable: is called after the compound disposable has been disposed
/// of, the given disposable is immediately disposed. This allows a compound
/// disposable to act as a stand-in for a disposable that will be delivered
/// asynchronously.
@interface RACCompoundDisposable : RACDisposable
/// Creates and returns a new compound disposable.
+ (instancetype)compoundDisposable;
/// Creates and returns a new compound disposable containing the given
/// disposables.
+ (instancetype)compoundDisposableWithDisposables:(NSArray *)disposables;
/// Adds the given disposable. If the receiving disposable has already been
/// disposed of, the given disposable is disposed immediately.
///
/// This method is thread-safe.
///
/// disposable - The disposable to add. This may be nil, in which case nothing
///              happens.
- (void)addDisposable:(RACDisposable *)disposable;
/// Removes the specified disposable from the compound disposable (regardless of
/// its disposed status), or does nothing if it's not in the compound disposable.
///
/// This is mainly useful for limiting the memory usage of the compound
/// disposable for long-running operations.
///
/// This method is thread-safe.
///
/// disposable - The disposable to remove. This argument may be nil (to make the
///              use of weak references easier).
- (void)removeDisposable:(RACDisposable *)disposable;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACCompoundDisposable.m
New file
@@ -0,0 +1,239 @@
//
//  RACCompoundDisposable.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 11/30/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACCompoundDisposable.h"
#import "RACCompoundDisposableProvider.h"
#import <libkern/OSAtomic.h>
// The number of child disposables for which space will be reserved directly in
// `RACCompoundDisposable`.
//
// This number has been empirically determined to provide a good tradeoff
// between performance, memory usage, and `RACCompoundDisposable` instance size
// in a moderately complex GUI application.
//
// Profile any change!
#define RACCompoundDisposableInlineCount 2
static CFMutableArrayRef RACCreateDisposablesArray(void) {
    // Compare values using only pointer equality.
    CFArrayCallBacks callbacks = kCFTypeArrayCallBacks;
    callbacks.equal = NULL;
    return CFArrayCreateMutable(NULL, 0, &callbacks);
}
@interface RACCompoundDisposable () {
    // Used for synchronization.
    OSSpinLock _spinLock;
    #if RACCompoundDisposableInlineCount
    // A fast array to the first N of the receiver's disposables.
    //
    // Once this is full, `_disposables` will be created and used for additional
    // disposables.
    //
    // This array should only be manipulated while _spinLock is held.
    RACDisposable *_inlineDisposables[RACCompoundDisposableInlineCount];
    #endif
    // Contains the receiver's disposables.
    //
    // This array should only be manipulated while _spinLock is held. If
    // `_disposed` is YES, this may be NULL.
    CFMutableArrayRef _disposables;
    // Whether the receiver has already been disposed.
    //
    // This ivar should only be accessed while _spinLock is held.
    BOOL _disposed;
}
@end
@implementation RACCompoundDisposable
#pragma mark Properties
- (BOOL)isDisposed {
    OSSpinLockLock(&_spinLock);
    BOOL disposed = _disposed;
    OSSpinLockUnlock(&_spinLock);
    return disposed;
}
#pragma mark Lifecycle
+ (instancetype)compoundDisposable {
    return [[self alloc] initWithDisposables:nil];
}
+ (instancetype)compoundDisposableWithDisposables:(NSArray *)disposables {
    return [[self alloc] initWithDisposables:disposables];
}
- (id)initWithDisposables:(NSArray *)otherDisposables {
    self = [self init];
    if (self == nil) return nil;
    #if RACCompoundDisposableInlineCount
    [otherDisposables enumerateObjectsUsingBlock:^(RACDisposable *disposable, NSUInteger index, BOOL *stop) {
        _inlineDisposables[index] = disposable;
        // Stop after this iteration if we've reached the end of the inlined
        // array.
        if (index == RACCompoundDisposableInlineCount - 1) *stop = YES;
    }];
    #endif
    if (otherDisposables.count > RACCompoundDisposableInlineCount) {
        _disposables = RACCreateDisposablesArray();
        CFRange range = CFRangeMake(RACCompoundDisposableInlineCount, (CFIndex)otherDisposables.count - RACCompoundDisposableInlineCount);
        CFArrayAppendArray(_disposables, (__bridge CFArrayRef)otherDisposables, range);
    }
    return self;
}
- (id)initWithBlock:(void (^)(void))block {
    RACDisposable *disposable = [RACDisposable disposableWithBlock:block];
    return [self initWithDisposables:@[ disposable ]];
}
- (void)dealloc {
    #if RACCompoundDisposableInlineCount
    for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
        _inlineDisposables[i] = nil;
    }
    #endif
    if (_disposables != NULL) {
        CFRelease(_disposables);
        _disposables = NULL;
    }
}
#pragma mark Addition and Removal
- (void)addDisposable:(RACDisposable *)disposable {
    NSCParameterAssert(disposable != self);
    if (disposable == nil || disposable.disposed) return;
    BOOL shouldDispose = NO;
    OSSpinLockLock(&_spinLock);
    {
        if (_disposed) {
            shouldDispose = YES;
        } else {
            #if RACCompoundDisposableInlineCount
            for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
                if (_inlineDisposables[i] == nil) {
                    _inlineDisposables[i] = disposable;
                    goto foundSlot;
                }
            }
            #endif
            if (_disposables == NULL) _disposables = RACCreateDisposablesArray();
            CFArrayAppendValue(_disposables, (__bridge void *)disposable);
            if (RACCOMPOUNDDISPOSABLE_ADDED_ENABLED()) {
                RACCOMPOUNDDISPOSABLE_ADDED(self.description.UTF8String, disposable.description.UTF8String, CFArrayGetCount(_disposables) + RACCompoundDisposableInlineCount);
            }
        #if RACCompoundDisposableInlineCount
        foundSlot:;
        #endif
        }
    }
    OSSpinLockUnlock(&_spinLock);
    // Performed outside of the lock in case the compound disposable is used
    // recursively.
    if (shouldDispose) [disposable dispose];
}
- (void)removeDisposable:(RACDisposable *)disposable {
    if (disposable == nil) return;
    OSSpinLockLock(&_spinLock);
    {
        if (!_disposed) {
            #if RACCompoundDisposableInlineCount
            for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
                if (_inlineDisposables[i] == disposable) _inlineDisposables[i] = nil;
            }
            #endif
            if (_disposables != NULL) {
                CFIndex count = CFArrayGetCount(_disposables);
                for (CFIndex i = count - 1; i >= 0; i--) {
                    const void *item = CFArrayGetValueAtIndex(_disposables, i);
                    if (item == (__bridge void *)disposable) {
                        CFArrayRemoveValueAtIndex(_disposables, i);
                    }
                }
                if (RACCOMPOUNDDISPOSABLE_REMOVED_ENABLED()) {
                    RACCOMPOUNDDISPOSABLE_REMOVED(self.description.UTF8String, disposable.description.UTF8String, CFArrayGetCount(_disposables) + RACCompoundDisposableInlineCount);
                }
            }
        }
    }
    OSSpinLockUnlock(&_spinLock);
}
#pragma mark RACDisposable
static void disposeEach(const void *value, void *context) {
    RACDisposable *disposable = (__bridge id)value;
    [disposable dispose];
}
- (void)dispose {
    #if RACCompoundDisposableInlineCount
    RACDisposable *inlineCopy[RACCompoundDisposableInlineCount];
    #endif
    CFArrayRef remainingDisposables = NULL;
    OSSpinLockLock(&_spinLock);
    {
        _disposed = YES;
        #if RACCompoundDisposableInlineCount
        for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
            inlineCopy[i] = _inlineDisposables[i];
            _inlineDisposables[i] = nil;
        }
        #endif
        remainingDisposables = _disposables;
        _disposables = NULL;
    }
    OSSpinLockUnlock(&_spinLock);
    #if RACCompoundDisposableInlineCount
    // Dispose outside of the lock in case the compound disposable is used
    // recursively.
    for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
        [inlineCopy[i] dispose];
    }
    #endif
    if (remainingDisposables == NULL) return;
    CFIndex count = CFArrayGetCount(remainingDisposables);
    CFArrayApplyFunction(remainingDisposables, CFRangeMake(0, count), &disposeEach, NULL);
    CFRelease(remainingDisposables);
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACCompoundDisposableProvider.d
New file
@@ -0,0 +1,4 @@
provider RACCompoundDisposable {
    probe added(char *compoundDisposable, char *disposable, long newTotal);
    probe removed(char *compoundDisposable, char *disposable, long newTotal);
};
Pods/ReactiveCocoa/ReactiveCocoa/RACDelegateProxy.h
New file
@@ -0,0 +1,28 @@
//
//  RACDelegateProxy.h
//  ReactiveCocoa
//
//  Created by Cody Krieger on 5/19/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACSignal;
// A private delegate object suitable for using
// -rac_signalForSelector:fromProtocol: upon.
@interface RACDelegateProxy : NSObject
// The delegate to which messages should be forwarded if not handled by
// any -signalForSelector: applications.
@property (nonatomic, unsafe_unretained) id rac_proxiedDelegate;
// Creates a delegate proxy capable of responding to selectors from `protocol`.
- (instancetype)initWithProtocol:(Protocol *)protocol;
// Calls -rac_signalForSelector:fromProtocol: using the `protocol` specified
// during initialization.
- (RACSignal *)signalForSelector:(SEL)selector;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACDelegateProxy.m
New file
@@ -0,0 +1,76 @@
//
//  RACDelegateProxy.m
//  ReactiveCocoa
//
//  Created by Cody Krieger on 5/19/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACDelegateProxy.h"
#import "NSObject+RACSelectorSignal.h"
#import <objc/runtime.h>
@interface RACDelegateProxy () {
    // Declared as an ivar to avoid method naming conflicts.
    Protocol *_protocol;
}
@end
@implementation RACDelegateProxy
#pragma mark Lifecycle
- (instancetype)initWithProtocol:(Protocol *)protocol {
    NSCParameterAssert(protocol != NULL);
    self = [super init];
    if (self == nil) return nil;
    class_addProtocol(self.class, protocol);
    _protocol = protocol;
    return self;
}
#pragma mark API
- (RACSignal *)signalForSelector:(SEL)selector {
    return [self rac_signalForSelector:selector fromProtocol:_protocol];
}
#pragma mark NSObject
- (BOOL)isProxy {
    return YES;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
    [invocation invokeWithTarget:self.rac_proxiedDelegate];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
    // Look for the selector as an optional instance method.
    struct objc_method_description methodDescription = protocol_getMethodDescription(_protocol, selector, NO, YES);
    if (methodDescription.name == NULL) {
        // Then fall back to looking for a required instance
        // method.
        methodDescription = protocol_getMethodDescription(_protocol, selector, YES, YES);
        if (methodDescription.name == NULL) return [super methodSignatureForSelector:selector];
    }
    return [NSMethodSignature signatureWithObjCTypes:methodDescription.types];
}
- (BOOL)respondsToSelector:(SEL)selector {
    // Add the delegate to the autorelease pool, so it doesn't get deallocated
    // between this method call and -forwardInvocation:.
    __autoreleasing id delegate = self.rac_proxiedDelegate;
    if ([delegate respondsToSelector:selector]) return YES;
    return [super respondsToSelector:selector];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACDisposable.h
New file
@@ -0,0 +1,35 @@
//
//  RACDisposable.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/16/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACScopedDisposable;
/// A disposable encapsulates the work necessary to tear down and cleanup a
/// subscription.
@interface RACDisposable : NSObject
/// Whether the receiver has been disposed.
///
/// Use of this property is discouraged, since it may be set to `YES`
/// concurrently at any time.
///
/// This property is not KVO-compliant.
@property (atomic, assign, getter = isDisposed, readonly) BOOL disposed;
+ (instancetype)disposableWithBlock:(void (^)(void))block;
/// Performs the disposal work. Can be called multiple times, though subsequent
/// calls won't do anything.
- (void)dispose;
/// Returns a new disposable which will dispose of this disposable when it gets
/// dealloc'd.
- (RACScopedDisposable *)asScopedDisposable;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACDisposable.m
New file
@@ -0,0 +1,92 @@
//
//  RACDisposable.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/16/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACDisposable.h"
#import "RACScopedDisposable.h"
#import <libkern/OSAtomic.h>
@interface RACDisposable () {
    // A copied block of type void (^)(void) containing the logic for disposal,
    // a pointer to `self` if no logic should be performed upon disposal, or
    // NULL if the receiver is already disposed.
    //
    // This should only be used atomically.
    void * volatile _disposeBlock;
}
@end
@implementation RACDisposable
#pragma mark Properties
- (BOOL)isDisposed {
    return _disposeBlock == NULL;
}
#pragma mark Lifecycle
- (id)init {
    self = [super init];
    if (self == nil) return nil;
    _disposeBlock = (__bridge void *)self;
    OSMemoryBarrier();
    return self;
}
- (id)initWithBlock:(void (^)(void))block {
    NSCParameterAssert(block != nil);
    self = [super init];
    if (self == nil) return nil;
    _disposeBlock = (void *)CFBridgingRetain([block copy]);
    OSMemoryBarrier();
    return self;
}
+ (instancetype)disposableWithBlock:(void (^)(void))block {
    return [[self alloc] initWithBlock:block];
}
- (void)dealloc {
    if (_disposeBlock == NULL || _disposeBlock == (__bridge void *)self) return;
    CFRelease(_disposeBlock);
    _disposeBlock = NULL;
}
#pragma mark Disposal
- (void)dispose {
    void (^disposeBlock)(void) = NULL;
    while (YES) {
        void *blockPtr = _disposeBlock;
        if (OSAtomicCompareAndSwapPtrBarrier(blockPtr, NULL, &_disposeBlock)) {
            if (blockPtr != (__bridge void *)self) {
                disposeBlock = CFBridgingRelease(blockPtr);
            }
            break;
        }
    }
    if (disposeBlock != nil) disposeBlock();
}
#pragma mark Scoped Disposables
- (RACScopedDisposable *)asScopedDisposable {
    return [RACScopedDisposable scopedDisposableWithDisposable:self];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACDynamicSequence.h
New file
@@ -0,0 +1,20 @@
//
//  RACDynamicSequence.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "RACSequence.h"
// Private class that implements a sequence dynamically using blocks.
@interface RACDynamicSequence : RACSequence
// Returns a sequence which evaluates `dependencyBlock` only once, the first
// time either `headBlock` or `tailBlock` is evaluated. The result of
// `dependencyBlock` will be passed into `headBlock` and `tailBlock` when
// invoked.
+ (RACSequence *)sequenceWithLazyDependency:(id (^)(void))dependencyBlock headBlock:(id (^)(id dependency))headBlock tailBlock:(RACSequence *(^)(id dependency))tailBlock;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACDynamicSequence.m
New file
@@ -0,0 +1,197 @@
//
//  RACDynamicSequence.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "RACDynamicSequence.h"
#import <libkern/OSAtomic.h>
// Determines how RACDynamicSequences will be deallocated before the next one is
// shifted onto the autorelease pool.
//
// This avoids stack overflows when deallocating long chains of dynamic
// sequences.
#define DEALLOC_OVERFLOW_GUARD 100
@interface RACDynamicSequence () {
    // The value for the "head" property, if it's been evaluated already.
    //
    // Because it's legal for head to be nil, this ivar is valid any time
    // headBlock is nil.
    //
    // This ivar should only be accessed while synchronized on self.
    id _head;
    // The value for the "tail" property, if it's been evaluated already.
    //
    // Because it's legal for tail to be nil, this ivar is valid any time
    // tailBlock is nil.
    //
    // This ivar should only be accessed while synchronized on self.
    RACSequence *_tail;
    // The result of an evaluated `dependencyBlock`.
    //
    // This ivar is valid any time `hasDependency` is YES and `dependencyBlock`
    // is nil.
    //
    // This ivar should only be accessed while synchronized on self.
    id _dependency;
}
// A block used to evaluate head. This should be set to nil after `_head` has been
// initialized.
//
// This is marked `strong` instead of `copy` because of some bizarre block
// copying bug. See https://github.com/ReactiveCocoa/ReactiveCocoa/pull/506.
//
// The signature of this block varies based on the value of `hasDependency`:
//
//  - If YES, this block is of type `id (^)(id)`.
//  - If NO, this block is of type `id (^)(void)`.
//
// This property should only be accessed while synchronized on self.
@property (nonatomic, strong) id headBlock;
// A block used to evaluate tail. This should be set to nil after `_tail` has been
// initialized.
//
// This is marked `strong` instead of `copy` because of some bizarre block
// copying bug. See https://github.com/ReactiveCocoa/ReactiveCocoa/pull/506.
//
// The signature of this block varies based on the value of `hasDependency`:
//
//  - If YES, this block is of type `RACSequence * (^)(id)`.
//  - If NO, this block is of type `RACSequence * (^)(void)`.
//
// This property should only be accessed while synchronized on self.
@property (nonatomic, strong) id tailBlock;
// Whether the receiver was initialized with a `dependencyBlock`.
//
// This property should only be accessed while synchronized on self.
@property (nonatomic, assign) BOOL hasDependency;
// A dependency which must be evaluated before `headBlock` and `tailBlock`. This
// should be set to nil after `_dependency` and `dependencyBlockExecuted` have
// been set.
//
// This is marked `strong` instead of `copy` because of some bizarre block
// copying bug. See https://github.com/ReactiveCocoa/ReactiveCocoa/pull/506.
//
// This property should only be accessed while synchronized on self.
@property (nonatomic, strong) id (^dependencyBlock)(void);
@end
@implementation RACDynamicSequence
#pragma mark Lifecycle
+ (RACSequence *)sequenceWithHeadBlock:(id (^)(void))headBlock tailBlock:(RACSequence *(^)(void))tailBlock {
    NSCParameterAssert(headBlock != nil);
    RACDynamicSequence *seq = [[RACDynamicSequence alloc] init];
    seq.headBlock = [headBlock copy];
    seq.tailBlock = [tailBlock copy];
    seq.hasDependency = NO;
    return seq;
}
+ (RACSequence *)sequenceWithLazyDependency:(id (^)(void))dependencyBlock headBlock:(id (^)(id dependency))headBlock tailBlock:(RACSequence *(^)(id dependency))tailBlock {
    NSCParameterAssert(dependencyBlock != nil);
    NSCParameterAssert(headBlock != nil);
    RACDynamicSequence *seq = [[RACDynamicSequence alloc] init];
    seq.headBlock = [headBlock copy];
    seq.tailBlock = [tailBlock copy];
    seq.dependencyBlock = [dependencyBlock copy];
    seq.hasDependency = YES;
    return seq;
}
- (void)dealloc {
    static volatile int32_t directDeallocCount = 0;
    if (OSAtomicIncrement32(&directDeallocCount) >= DEALLOC_OVERFLOW_GUARD) {
        OSAtomicAdd32(-DEALLOC_OVERFLOW_GUARD, &directDeallocCount);
        // Put this sequence's tail onto the autorelease pool so we stop
        // recursing.
        __autoreleasing RACSequence *tail __attribute__((unused)) = _tail;
    }
    _tail = nil;
}
#pragma mark RACSequence
- (id)head {
    @synchronized (self) {
        id untypedHeadBlock = self.headBlock;
        if (untypedHeadBlock == nil) return _head;
        if (self.hasDependency) {
            if (self.dependencyBlock != nil) {
                _dependency = self.dependencyBlock();
                self.dependencyBlock = nil;
            }
            id (^headBlock)(id) = untypedHeadBlock;
            _head = headBlock(_dependency);
        } else {
            id (^headBlock)(void) = untypedHeadBlock;
            _head = headBlock();
        }
        self.headBlock = nil;
        return _head;
    }
}
- (RACSequence *)tail {
    @synchronized (self) {
        id untypedTailBlock = self.tailBlock;
        if (untypedTailBlock == nil) return _tail;
        if (self.hasDependency) {
            if (self.dependencyBlock != nil) {
                _dependency = self.dependencyBlock();
                self.dependencyBlock = nil;
            }
            RACSequence * (^tailBlock)(id) = untypedTailBlock;
            _tail = tailBlock(_dependency);
        } else {
            RACSequence * (^tailBlock)(void) = untypedTailBlock;
            _tail = tailBlock();
        }
        if (_tail.name == nil) _tail.name = self.name;
        self.tailBlock = nil;
        return _tail;
    }
}
#pragma mark NSObject
- (NSString *)description {
    id head = @"(unresolved)";
    id tail = @"(unresolved)";
    @synchronized (self) {
        if (self.headBlock == nil) head = _head;
        if (self.tailBlock == nil) {
            tail = _tail;
            if (tail == self) tail = @"(self)";
        }
    }
    return [NSString stringWithFormat:@"<%@: %p>{ name = %@, head = %@, tail = %@ }", self.class, self, self.name, head, tail];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACDynamicSignal.h
New file
@@ -0,0 +1,17 @@
//
//  RACDynamicSignal.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-10-10.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACSignal.h"
// A private `RACSignal` subclasses that implements its subscription behavior
// using a block.
@interface RACDynamicSignal : RACSignal
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACDynamicSignal.m
New file
@@ -0,0 +1,54 @@
//
//  RACDynamicSignal.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-10-10.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACDynamicSignal.h"
#import "RACEXTScope.h"
#import "RACCompoundDisposable.h"
#import "RACPassthroughSubscriber.h"
#import "RACScheduler+Private.h"
#import "RACSubscriber.h"
#import <libkern/OSAtomic.h>
@interface RACDynamicSignal ()
// The block to invoke for each subscriber.
@property (nonatomic, copy, readonly) RACDisposable * (^didSubscribe)(id<RACSubscriber> subscriber);
@end
@implementation RACDynamicSignal
#pragma mark Lifecycle
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    RACDynamicSignal *signal = [[self alloc] init];
    signal->_didSubscribe = [didSubscribe copy];
    return [signal setNameWithFormat:@"+createSignal:"];
}
#pragma mark Managing Subscribers
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCParameterAssert(subscriber != nil);
    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
    if (self.didSubscribe != NULL) {
        RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
            RACDisposable *innerDisposable = self.didSubscribe(subscriber);
            [disposable addDisposable:innerDisposable];
        }];
        [disposable addDisposable:schedulingDisposable];
    }
    return disposable;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACEagerSequence.h
New file
@@ -0,0 +1,14 @@
//
//  RACEagerSequence.h
//  ReactiveCocoa
//
//  Created by Uri Baghin on 02/01/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACArraySequence.h"
// Private class that implements an eager sequence.
@interface RACEagerSequence : RACArraySequence
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACEagerSequence.m
New file
@@ -0,0 +1,66 @@
//
//  RACEagerSequence.m
//  ReactiveCocoa
//
//  Created by Uri Baghin on 02/01/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACEagerSequence.h"
#import "NSObject+RACDescription.h"
#import "RACArraySequence.h"
@implementation RACEagerSequence
#pragma mark RACStream
+ (instancetype)return:(id)value {
    return [[self sequenceWithArray:@[ value ] offset:0] setNameWithFormat:@"+return: %@", [value rac_description]];
}
- (instancetype)bind:(RACStreamBindBlock (^)(void))block {
    NSCParameterAssert(block != nil);
    RACStreamBindBlock bindBlock = block();
    NSArray *currentArray = self.array;
    NSMutableArray *resultArray = [NSMutableArray arrayWithCapacity:currentArray.count];
    for (id value in currentArray) {
        BOOL stop = NO;
        RACSequence *boundValue = (id)bindBlock(value, &stop);
        if (boundValue == nil) break;
        for (id x in boundValue) {
            [resultArray addObject:x];
        }
        if (stop) break;
    }
    return [[self.class sequenceWithArray:resultArray offset:0] setNameWithFormat:@"[%@] -bind:", self.name];
}
- (instancetype)concat:(RACSequence *)sequence {
    NSCParameterAssert(sequence != nil);
    NSCParameterAssert([sequence isKindOfClass:RACSequence.class]);
    NSArray *array = [self.array arrayByAddingObjectsFromArray:sequence.array];
    return [[self.class sequenceWithArray:array offset:0] setNameWithFormat:@"[%@] -concat: %@", self.name, sequence];
}
#pragma mark Extended methods
- (RACSequence *)eagerSequence {
    return self;
}
- (RACSequence *)lazySequence {
    return [RACArraySequence sequenceWithArray:self.array offset:0];
}
- (id)foldRightWithStart:(id)start reduce:(id (^)(id, RACSequence *rest))reduce {
    return [super foldRightWithStart:start reduce:^(id first, RACSequence *rest) {
        return reduce(first, rest.eagerSequence);
    }];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACEmptySequence.h
New file
@@ -0,0 +1,14 @@
//
//  RACEmptySequence.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "RACSequence.h"
// Private class representing an empty sequence.
@interface RACEmptySequence : RACSequence
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACEmptySequence.m
New file
@@ -0,0 +1,71 @@
//
//  RACEmptySequence.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "RACEmptySequence.h"
@implementation RACEmptySequence
#pragma mark Lifecycle
+ (instancetype)empty {
    static id singleton;
    static dispatch_once_t pred;
    dispatch_once(&pred, ^{
        singleton = [[self alloc] init];
    });
    return singleton;
}
#pragma mark RACSequence
- (id)head {
    return nil;
}
- (RACSequence *)tail {
    return nil;
}
- (RACSequence *)bind:(RACStreamBindBlock)bindBlock passingThroughValuesFromSequence:(RACSequence *)passthroughSequence {
    return passthroughSequence ?: self;
}
#pragma mark NSCoding
- (Class)classForCoder {
    // Empty sequences should be encoded as themselves, not array sequences.
    return self.class;
}
- (id)initWithCoder:(NSCoder *)coder {
    // Return the singleton.
    return self.class.empty;
}
- (void)encodeWithCoder:(NSCoder *)coder {
}
#pragma mark NSObject
- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: %p>{ name = %@ }", self.class, self, self.name];
}
- (NSUInteger)hash {
    // This hash isn't ideal, but it's better than -[RACSequence hash], which
    // would just be zero because we have no head.
    return (NSUInteger)(__bridge void *)self;
}
- (BOOL)isEqual:(RACSequence *)seq {
    return (self == seq);
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACEmptySignal.h
New file
@@ -0,0 +1,17 @@
//
//  RACEmptySignal.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-10-10.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACSignal.h"
// A private `RACSignal` subclasses that synchronously sends completed to any
// subscribers.
@interface RACEmptySignal : RACSignal
+ (RACSignal *)empty;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACEmptySignal.m
New file
@@ -0,0 +1,62 @@
//
//  RACEmptySignal.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-10-10.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACEmptySignal.h"
#import "RACScheduler+Private.h"
#import "RACSubscriber.h"
@implementation RACEmptySignal
#pragma mark Properties
// Only allow this signal's name to be customized in DEBUG, since it's
// a singleton in release builds (see +empty).
- (void)setName:(NSString *)name {
#ifdef DEBUG
    [super setName:name];
#endif
}
- (NSString *)name {
#ifdef DEBUG
    return super.name;
#else
    return @"+empty";
#endif
}
#pragma mark Lifecycle
+ (RACSignal *)empty {
#ifdef DEBUG
    // Create multiple instances of this class in DEBUG so users can set custom
    // names on each.
    return [[[self alloc] init] setNameWithFormat:@"+empty"];
#else
    static id singleton;
    static dispatch_once_t pred;
    dispatch_once(&pred, ^{
        singleton = [[self alloc] init];
    });
    return singleton;
#endif
}
#pragma mark Subscription
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCParameterAssert(subscriber != nil);
    return [RACScheduler.subscriptionScheduler schedule:^{
        [subscriber sendCompleted];
    }];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACErrorSignal.h
New file
@@ -0,0 +1,17 @@
//
//  RACErrorSignal.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-10-10.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACSignal.h"
// A private `RACSignal` subclasses that synchronously sends an error to any
// subscribers.
@interface RACErrorSignal : RACSignal
+ (RACSignal *)error:(NSError *)error;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACErrorSignal.m
New file
@@ -0,0 +1,47 @@
//
//  RACErrorSignal.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-10-10.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACErrorSignal.h"
#import "RACScheduler+Private.h"
#import "RACSubscriber.h"
@interface RACErrorSignal ()
// The error to send upon subscription.
@property (nonatomic, strong, readonly) NSError *error;
@end
@implementation RACErrorSignal
#pragma mark Lifecycle
+ (RACSignal *)error:(NSError *)error {
    RACErrorSignal *signal = [[self alloc] init];
    signal->_error = error;
#ifdef DEBUG
    [signal setNameWithFormat:@"+error: %@", error];
#else
    signal.name = @"+error:";
#endif
    return signal;
}
#pragma mark Subscription
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCParameterAssert(subscriber != nil);
    return [RACScheduler.subscriptionScheduler schedule:^{
        [subscriber sendError:self.error];
    }];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACEvent.h
New file
@@ -0,0 +1,51 @@
//
//  RACEvent.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-01-07.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
/// Describes the type of a RACEvent.
///
/// RACEventTypeCompleted - A `completed` event.
/// RACEventTypeError     - An `error` event.
/// RACEventTypeNext      - A `next` event.
typedef enum : NSUInteger {
    RACEventTypeCompleted,
    RACEventTypeError,
    RACEventTypeNext
} RACEventType;
/// Represents an event sent by a RACSignal.
///
/// This corresponds to the `Notification` class in Rx.
@interface RACEvent : NSObject <NSCopying>
/// Returns a singleton RACEvent representing the `completed` event.
+ (instancetype)completedEvent;
/// Returns a new event of type RACEventTypeError, containing the given error.
+ (instancetype)eventWithError:(NSError *)error;
/// Returns a new event of type RACEventTypeNext, containing the given value.
+ (instancetype)eventWithValue:(id)value;
/// The type of event represented by the receiver.
@property (nonatomic, assign, readonly) RACEventType eventType;
/// Returns whether the receiver is of type RACEventTypeCompleted or
/// RACEventTypeError.
@property (nonatomic, getter = isFinished, assign, readonly) BOOL finished;
/// The error associated with an event of type RACEventTypeError. This will be
/// nil for all other event types.
@property (nonatomic, strong, readonly) NSError *error;
/// The value associated with an event of type RACEventTypeNext. This will be
/// nil for all other event types.
@property (nonatomic, strong, readonly) id value;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACEvent.m
New file
@@ -0,0 +1,113 @@
//
//  RACEvent.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-01-07.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACEvent.h"
@interface RACEvent ()
// An object associated with this event. This will be used for the error and
// value properties.
@property (nonatomic, strong, readonly) id object;
// Initializes the receiver with the given type and object.
- (id)initWithEventType:(RACEventType)type object:(id)object;
@end
@implementation RACEvent
#pragma mark Properties
- (BOOL)isFinished {
    return self.eventType == RACEventTypeCompleted || self.eventType == RACEventTypeError;
}
- (NSError *)error {
    return (self.eventType == RACEventTypeError ? self.object : nil);
}
- (id)value {
    return (self.eventType == RACEventTypeNext ? self.object : nil);
}
#pragma mark Lifecycle
+ (instancetype)completedEvent {
    static dispatch_once_t pred;
    static id singleton;
    dispatch_once(&pred, ^{
        singleton = [[self alloc] initWithEventType:RACEventTypeCompleted object:nil];
    });
    return singleton;
}
+ (instancetype)eventWithError:(NSError *)error {
    return [[self alloc] initWithEventType:RACEventTypeError object:error];
}
+ (instancetype)eventWithValue:(id)value {
    return [[self alloc] initWithEventType:RACEventTypeNext object:value];
}
- (id)initWithEventType:(RACEventType)type object:(id)object {
    self = [super init];
    if (self == nil) return nil;
    _eventType = type;
    _object = object;
    return self;
}
#pragma mark NSCopying
- (id)copyWithZone:(NSZone *)zone {
    return self;
}
#pragma mark NSObject
- (NSString *)description {
    NSString *eventDescription = nil;
    switch (self.eventType) {
        case RACEventTypeCompleted:
            eventDescription = @"completed";
            break;
        case RACEventTypeError:
            eventDescription = [NSString stringWithFormat:@"error = %@", self.object];
            break;
        case RACEventTypeNext:
            eventDescription = [NSString stringWithFormat:@"next = %@", self.object];
            break;
        default:
            NSCAssert(NO, @"Unrecognized event type: %i", (int)self.eventType);
    }
    return [NSString stringWithFormat:@"<%@: %p>{ %@ }", self.class, self, eventDescription];
}
- (NSUInteger)hash {
    return self.eventType ^ [self.object hash];
}
- (BOOL)isEqual:(id)event {
    if (event == self) return YES;
    if (![event isKindOfClass:RACEvent.class]) return NO;
    if (self.eventType != [event eventType]) return NO;
    // Catches the nil case too.
    return self.object == [event object] || [self.object isEqual:[event object]];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACGroupedSignal.h
New file
@@ -0,0 +1,19 @@
//
//  RACGroupedSignal.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 5/2/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACSubject.h"
/// A grouped signal is used by -[RACSignal groupBy:transform:].
@interface RACGroupedSignal : RACSubject
/// The key shared by the group.
@property (nonatomic, readonly, copy) id<NSCopying> key;
+ (instancetype)signalWithKey:(id<NSCopying>)key;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACGroupedSignal.m
New file
@@ -0,0 +1,25 @@
//
//  RACGroupedSignal.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 5/2/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACGroupedSignal.h"
@interface RACGroupedSignal ()
@property (nonatomic, copy) id<NSCopying> key;
@end
@implementation RACGroupedSignal
#pragma mark API
+ (instancetype)signalWithKey:(id<NSCopying>)key {
    RACGroupedSignal *subject = [self subject];
    subject.key = key;
    return subject;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACImmediateScheduler.h
New file
@@ -0,0 +1,14 @@
//
//  RACImmediateScheduler.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 11/30/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACScheduler.h"
// A private scheduler which immediately executes its scheduled blocks.
@interface RACImmediateScheduler : RACScheduler
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACImmediateScheduler.m
New file
@@ -0,0 +1,54 @@
//
//  RACImmediateScheduler.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 11/30/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACImmediateScheduler.h"
#import "RACScheduler+Private.h"
@implementation RACImmediateScheduler
#pragma mark Lifecycle
- (id)init {
    return [super initWithName:@"com.ReactiveCocoa.RACScheduler.immediateScheduler"];
}
#pragma mark RACScheduler
- (RACDisposable *)schedule:(void (^)(void))block {
    NSCParameterAssert(block != NULL);
    block();
    return nil;
}
- (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block {
    NSCParameterAssert(date != nil);
    NSCParameterAssert(block != NULL);
    [NSThread sleepUntilDate:date];
    block();
    return nil;
}
- (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block {
    NSCAssert(NO, @"+[RACScheduler immediateScheduler] does not support %@.", NSStringFromSelector(_cmd));
    return nil;
}
- (RACDisposable *)scheduleRecursiveBlock:(RACSchedulerRecursiveBlock)recursiveBlock {
    for (__block NSUInteger remaining = 1; remaining > 0; remaining--) {
        recursiveBlock(^{
            remaining++;
        });
    }
    return nil;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACIndexSetSequence.h
New file
@@ -0,0 +1,16 @@
//
//  RACIndexSetSequence.h
//  ReactiveCocoa
//
//  Created by Sergey Gavrilyuk on 12/18/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACSequence.h"
// Private class that adapts an array to the RACSequence interface.
@interface RACIndexSetSequence : RACSequence
+ (instancetype)sequenceWithIndexSet:(NSIndexSet *)indexSet;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACIndexSetSequence.m
New file
@@ -0,0 +1,111 @@
//
//  RACIndexSetSequence.m
//  ReactiveCocoa
//
//  Created by Sergey Gavrilyuk on 12/18/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACIndexSetSequence.h"
@interface RACIndexSetSequence ()
// A buffer holding the `NSUInteger` values to enumerate over.
//
// This is mostly used for memory management. Most access should go through
// `indexes` instead.
@property (nonatomic, strong, readonly) NSData *data;
// The indexes that this sequence should enumerate.
@property (nonatomic, readonly) const NSUInteger *indexes;
// The number of indexes to enumerate.
@property (nonatomic, readonly) NSUInteger count;
@end
@implementation RACIndexSetSequence
#pragma mark Lifecycle
+ (instancetype)sequenceWithIndexSet:(NSIndexSet *)indexSet {
    NSUInteger count = indexSet.count;
    if (count == 0) return self.empty;
    NSUInteger sizeInBytes = sizeof(NSUInteger) * count;
    NSMutableData *data = [[NSMutableData alloc] initWithCapacity:sizeInBytes];
    [indexSet getIndexes:data.mutableBytes maxCount:count inIndexRange:NULL];
    RACIndexSetSequence *seq = [[self alloc] init];
    seq->_data = data;
    seq->_indexes = data.bytes;
    seq->_count = count;
    return seq;
}
+ (instancetype)sequenceWithIndexSetSequence:(RACIndexSetSequence *)indexSetSequence offset:(NSUInteger)offset {
    NSCParameterAssert(offset < indexSetSequence.count);
    RACIndexSetSequence *seq = [[self alloc] init];
    seq->_data = indexSetSequence.data;
    seq->_indexes = indexSetSequence.indexes + offset;
    seq->_count = indexSetSequence.count - offset;
    return seq;
}
#pragma mark RACSequence
- (id)head {
    return @(self.indexes[0]);
}
- (RACSequence *)tail {
    if (self.count <= 1) return [RACSequence empty];
    return [self.class sequenceWithIndexSetSequence:self offset:1];
}
#pragma mark NSFastEnumeration
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id[])stackbuf count:(NSUInteger)len {
    NSCParameterAssert(len > 0);
    if (state->state >= self.count) {
        // Enumeration has completed.
        return 0;
    }
    if (state->state == 0) {
        // Enumeration begun, mark the mutation flag.
        state->mutationsPtr = state->extra;
    }
    state->itemsPtr = stackbuf;
    unsigned long index = 0;
    while (index < MIN(self.count - state->state, len)) {
        stackbuf[index] = @(self.indexes[index + state->state]);
        ++index;
    }
    state->state += index;
    return index;
}
#pragma mark NSObject
- (NSString *)description {
    NSMutableString *indexesStr = [NSMutableString string];
    for (unsigned int i = 0; i < self.count; ++i) {
        if (i > 0) [indexesStr appendString:@", "];
        [indexesStr appendFormat:@"%lu", (unsigned long)self.indexes[i]];
    }
    return [NSString stringWithFormat:@"<%@: %p>{ name = %@, indexes = %@ }", self.class, self, self.name, indexesStr];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACKVOChannel.h
New file
@@ -0,0 +1,97 @@
//
//  RACKVOChannel.h
//  ReactiveCocoa
//
//  Created by Uri Baghin on 27/12/2012.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACChannel.h"
#import "RACEXTKeyPathCoding.h"
#import "RACmetamacros.h"
/// Creates a RACKVOChannel to the given key path. When the targeted object
/// deallocates, the channel will complete.
///
/// If RACChannelTo() is used as an expression, it returns a RACChannelTerminal that
/// can be used to watch the specified property for changes, and set new values
/// for it. The terminal will start with the property's current value upon
/// subscription.
///
/// If RACChannelTo() is used on the left-hand side of an assignment, there must a
/// RACChannelTerminal on the right-hand side of the assignment. The two will be
/// subscribed to one another: the property's value is immediately set to the
/// value of the channel terminal on the right-hand side, and subsequent changes
/// to either terminal will be reflected on the other.
///
/// There are two different versions of this macro:
///
///  - RACChannelTo(TARGET, KEYPATH, NILVALUE) will create a channel to the `KEYPATH`
///    of `TARGET`. If the terminal is ever sent a `nil` value, the property will
///    be set to `NILVALUE` instead. `NILVALUE` may itself be `nil` for object
///    properties, but an NSValue should be used for primitive properties, to
///    avoid an exception if `nil` is sent (which might occur if an intermediate
///    object is set to `nil`).
///  - RACChannelTo(TARGET, KEYPATH) is the same as the above, but `NILVALUE` defaults to
///    `nil`.
///
/// Examples
///
///  RACChannelTerminal *integerChannel = RACChannelTo(self, integerProperty, @42);
///
///  // Sets self.integerProperty to 5.
///  [integerChannel sendNext:@5];
///
///  // Logs the current value of self.integerProperty, and all future changes.
///  [integerChannel subscribeNext:^(id value) {
///      NSLog(@"value: %@", value);
///  }];
///
///  // Binds properties to each other, taking the initial value from the right
///  side.
///  RACChannelTo(view, objectProperty) = RACChannelTo(model, objectProperty);
///  RACChannelTo(view, integerProperty, @2) = RACChannelTo(model, integerProperty, @10);
#define RACChannelTo(TARGET, ...) \
    metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \
        (RACChannelTo_(TARGET, __VA_ARGS__, nil)) \
        (RACChannelTo_(TARGET, __VA_ARGS__))
/// Do not use this directly. Use the RACChannelTo macro above.
#define RACChannelTo_(TARGET, KEYPATH, NILVALUE) \
    [[RACKVOChannel alloc] initWithTarget:(TARGET) keyPath:@keypath(TARGET, KEYPATH) nilValue:(NILVALUE)][@keypath(RACKVOChannel.new, followingTerminal)]
/// A RACChannel that observes a KVO-compliant key path for changes.
@interface RACKVOChannel : RACChannel
/// Initializes a channel that will observe the given object and key path.
///
/// The current value of the key path, and future KVO notifications for the given
/// key path, will be sent to subscribers of the channel's `followingTerminal`.
/// Values sent to the `followingTerminal` will be set at the given key path using
/// key-value coding.
///
/// When the target object deallocates, the channel will complete. Signal errors
/// are considered undefined behavior.
///
/// This is the designated initializer for this class.
///
/// target   - The object to bind to.
/// keyPath  - The key path to observe and set the value of.
/// nilValue - The value to set at the key path whenever a `nil` value is
///            received. This may be nil when connecting to object properties, but
///            an NSValue should be used for primitive properties, to avoid an
///            exception if `nil` is received (which might occur if an intermediate
///            object is set to `nil`).
- (id)initWithTarget:(__weak NSObject *)target keyPath:(NSString *)keyPath nilValue:(id)nilValue;
- (id)init __attribute__((unavailable("Use -initWithTarget:keyPath:nilValue: instead")));
@end
/// Methods needed for the convenience macro. Do not call explicitly.
@interface RACKVOChannel (RACChannelTo)
- (RACChannelTerminal *)objectForKeyedSubscript:(NSString *)key;
- (void)setObject:(RACChannelTerminal *)otherTerminal forKeyedSubscript:(NSString *)key;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACKVOChannel.m
New file
@@ -0,0 +1,208 @@
//
//  RACKVOChannel.m
//  ReactiveCocoa
//
//  Created by Uri Baghin on 27/12/2012.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACKVOChannel.h"
#import "RACEXTScope.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACKVOWrapper.h"
#import "NSString+RACKeyPathUtilities.h"
#import "RACChannel.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACSignal+Operations.h"
// Key for the array of RACKVOChannel's additional thread local
// data in the thread dictionary.
static NSString * const RACKVOChannelDataDictionaryKey = @"RACKVOChannelKey";
// Wrapper class for additional thread local data.
@interface RACKVOChannelData : NSObject
// The flag used to ignore updates the channel itself has triggered.
@property (nonatomic, assign) BOOL ignoreNextUpdate;
// A pointer to the owner of the data. Only use this for pointer comparison,
// never as an object reference.
@property (nonatomic, assign) void *owner;
+ (instancetype)dataForChannel:(RACKVOChannel *)channel;
@end
@interface RACKVOChannel ()
// The object whose key path the channel is wrapping.
@property (atomic, weak) NSObject *target;
// The key path the channel is wrapping.
@property (nonatomic, copy, readonly) NSString *keyPath;
// Returns the existing thread local data container or nil if none exists.
@property (nonatomic, strong, readonly) RACKVOChannelData *currentThreadData;
// Creates the thread local data container for the channel.
- (void)createCurrentThreadData;
// Destroy the thread local data container for the channel.
- (void)destroyCurrentThreadData;
@end
@implementation RACKVOChannel
#pragma mark Properties
- (RACKVOChannelData *)currentThreadData {
    NSMutableArray *dataArray = NSThread.currentThread.threadDictionary[RACKVOChannelDataDictionaryKey];
    for (RACKVOChannelData *data in dataArray) {
        if (data.owner == (__bridge void *)self) return data;
    }
    return nil;
}
#pragma mark Lifecycle
- (id)initWithTarget:(__weak NSObject *)target keyPath:(NSString *)keyPath nilValue:(id)nilValue {
    NSCParameterAssert(keyPath.rac_keyPathComponents.count > 0);
    NSObject *strongTarget = target;
    self = [super init];
    if (self == nil) return nil;
    _target = target;
    _keyPath = [keyPath copy];
    [self.leadingTerminal setNameWithFormat:@"[-initWithTarget: %@ keyPath: %@ nilValue: %@] -leadingTerminal", target, keyPath, nilValue];
    [self.followingTerminal setNameWithFormat:@"[-initWithTarget: %@ keyPath: %@ nilValue: %@] -followingTerminal", target, keyPath, nilValue];
    if (strongTarget == nil) {
        [self.leadingTerminal sendCompleted];
        return self;
    }
    // Observe the key path on target for changes and forward the changes to the
    // terminal.
    //
    // Intentionally capturing `self` strongly in the blocks below, so the
    // channel object stays alive while observing.
    RACDisposable *observationDisposable = [strongTarget rac_observeKeyPath:keyPath options:NSKeyValueObservingOptionInitial observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
        // If the change wasn't triggered by deallocation, only affects the last
        // path component, and ignoreNextUpdate is set, then it was triggered by
        // this channel and should not be forwarded.
        if (!causedByDealloc && affectedOnlyLastComponent && self.currentThreadData.ignoreNextUpdate) {
            [self destroyCurrentThreadData];
            return;
        }
        [self.leadingTerminal sendNext:value];
    }];
    NSString *keyPathByDeletingLastKeyPathComponent = keyPath.rac_keyPathByDeletingLastKeyPathComponent;
    NSArray *keyPathComponents = keyPath.rac_keyPathComponents;
    NSUInteger keyPathComponentsCount = keyPathComponents.count;
    NSString *lastKeyPathComponent = keyPathComponents.lastObject;
    // Update the value of the property with the values received.
    [[self.leadingTerminal
        finally:^{
            [observationDisposable dispose];
        }]
        subscribeNext:^(id x) {
            // Check the value of the second to last key path component. Since the
            // channel can only update the value of a property on an object, and not
            // update intermediate objects, it can only update the value of the whole
            // key path if this object is not nil.
            NSObject *object = (keyPathComponentsCount > 1 ? [self.target valueForKeyPath:keyPathByDeletingLastKeyPathComponent] : self.target);
            if (object == nil) return;
            // Set the ignoreNextUpdate flag before setting the value so this channel
            // ignores the value in the subsequent -didChangeValueForKey: callback.
            [self createCurrentThreadData];
            self.currentThreadData.ignoreNextUpdate = YES;
            [object setValue:x ?: nilValue forKey:lastKeyPathComponent];
        } error:^(NSError *error) {
            NSCAssert(NO, @"Received error in %@: %@", self, error);
            // Log the error if we're running with assertions disabled.
            NSLog(@"Received error in %@: %@", self, error);
        }];
    // Capture `self` weakly for the target's deallocation disposable, so we can
    // freely deallocate if we complete before then.
    @weakify(self);
    [strongTarget.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
        @strongify(self);
        [self.leadingTerminal sendCompleted];
        self.target = nil;
    }]];
    return self;
}
- (void)createCurrentThreadData {
    NSMutableArray *dataArray = NSThread.currentThread.threadDictionary[RACKVOChannelDataDictionaryKey];
    if (dataArray == nil) {
        dataArray = [NSMutableArray array];
        NSThread.currentThread.threadDictionary[RACKVOChannelDataDictionaryKey] = dataArray;
        [dataArray addObject:[RACKVOChannelData dataForChannel:self]];
        return;
    }
    for (RACKVOChannelData *data in dataArray) {
        if (data.owner == (__bridge void *)self) return;
    }
    [dataArray addObject:[RACKVOChannelData dataForChannel:self]];
}
- (void)destroyCurrentThreadData {
    NSMutableArray *dataArray = NSThread.currentThread.threadDictionary[RACKVOChannelDataDictionaryKey];
    NSUInteger index = [dataArray indexOfObjectPassingTest:^ BOOL (RACKVOChannelData *data, NSUInteger idx, BOOL *stop) {
        return data.owner == (__bridge void *)self;
    }];
    if (index != NSNotFound) [dataArray removeObjectAtIndex:index];
}
@end
@implementation RACKVOChannel (RACChannelTo)
- (RACChannelTerminal *)objectForKeyedSubscript:(NSString *)key {
    NSCParameterAssert(key != nil);
    RACChannelTerminal *terminal = [self valueForKey:key];
    NSCAssert([terminal isKindOfClass:RACChannelTerminal.class], @"Key \"%@\" does not identify a channel terminal", key);
    return terminal;
}
- (void)setObject:(RACChannelTerminal *)otherTerminal forKeyedSubscript:(NSString *)key {
    NSCParameterAssert(otherTerminal != nil);
    RACChannelTerminal *selfTerminal = [self objectForKeyedSubscript:key];
    [otherTerminal subscribe:selfTerminal];
    [[selfTerminal skip:1] subscribe:otherTerminal];
}
@end
@implementation RACKVOChannelData
+ (instancetype)dataForChannel:(RACKVOChannel *)channel {
    RACKVOChannelData *data = [[self alloc] init];
    data->_owner = (__bridge void *)channel;
    return data;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACKVOProxy.h
New file
@@ -0,0 +1,34 @@
//
//  RACKVOProxy.h
//  ReactiveCocoa
//
//  Created by Richard Speyer on 4/10/14.
//  Copyright (c) 2014 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
/// A singleton that can act as a proxy between a KVO observation and a RAC
/// subscriber, in order to protect against KVO lifetime issues.
@interface RACKVOProxy : NSObject
/// Returns the singleton KVO proxy object.
+ (instancetype)sharedProxy;
/// Registers an observer with the proxy, such that when the proxy receives a
/// KVO change with the given context, it forwards it to the observer.
///
/// observer - True observer of the KVO change. Must not be nil.
/// context  - Arbitrary context object used to differentiate multiple
///            observations of the same keypath. Must be unique, cannot be nil.
- (void)addObserver:(__weak NSObject *)observer forContext:(void *)context;
/// Removes an observer from the proxy. Parameters must match those passed to
/// addObserver:forContext:.
///
/// observer - True observer of the KVO change. Must not be nil.
/// context  - Arbitrary context object used to differentiate multiple
///            observations of the same keypath. Must be unique, cannot be nil.
- (void)removeObserver:(NSObject *)observer forContext:(void *)context;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACKVOProxy.m
New file
@@ -0,0 +1,70 @@
//
//  RACKVOProxy.m
//  ReactiveCocoa
//
//  Created by Richard Speyer on 4/10/14.
//  Copyright (c) 2014 GitHub, Inc. All rights reserved.
//
#import "RACKVOProxy.h"
@interface RACKVOProxy()
@property (strong, nonatomic, readonly) NSMapTable *trampolines;
@property (strong, nonatomic, readonly) dispatch_queue_t queue;
@end
@implementation RACKVOProxy
+ (instancetype)sharedProxy {
    static RACKVOProxy *proxy;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        proxy = [[self alloc] init];
    });
    return proxy;
}
- (instancetype)init {
    self = [super init];
    if (self == nil) return nil;
    _queue = dispatch_queue_create("org.reactivecocoa.ReactiveCocoa.RACKVOProxy", DISPATCH_QUEUE_SERIAL);
    _trampolines = [NSMapTable strongToWeakObjectsMapTable];
    return self;
}
- (void)addObserver:(__weak NSObject *)observer forContext:(void *)context {
    NSValue *valueContext = [NSValue valueWithPointer:context];
    dispatch_sync(self.queue, ^{
        [self.trampolines setObject:observer forKey:valueContext];
    });
}
- (void)removeObserver:(NSObject *)observer forContext:(void *)context {
    NSValue *valueContext = [NSValue valueWithPointer:context];
    dispatch_sync(self.queue, ^{
        [self.trampolines removeObjectForKey:valueContext];
    });
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    NSValue *valueContext = [NSValue valueWithPointer:context];
    __block NSObject *trueObserver;
    dispatch_sync(self.queue, ^{
        trueObserver = [self.trampolines objectForKey:valueContext];
    });
    if (trueObserver != nil) {
        [trueObserver observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACKVOTrampoline.h
New file
@@ -0,0 +1,31 @@
//
//  RACKVOTrampoline.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 1/15/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "NSObject+RACKVOWrapper.h"
#import "RACDisposable.h"
// A private trampoline object that represents a KVO observation.
//
// Disposing of the trampoline will stop observation.
@interface RACKVOTrampoline : RACDisposable
// Initializes the receiver with the given parameters.
//
// target   - The object whose key path should be observed. Cannot be nil.
// observer - The object that gets notified when the value at the key path
//            changes. Can be nil.
// keyPath  - The key path on `target` to observe. Cannot be nil.
// options  - Any key value observing options to use in the observation.
// block    - The block to call when the value at the observed key path changes.
//            Cannot be nil.
//
// Returns the initialized object.
- (id)initWithTarget:(__weak NSObject *)target observer:(__weak NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACKVOTrampoline.m
New file
@@ -0,0 +1,110 @@
//
//  RACKVOTrampoline.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 1/15/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACKVOTrampoline.h"
#import "NSObject+RACDeallocating.h"
#import "RACCompoundDisposable.h"
#import "RACKVOProxy.h"
@interface RACKVOTrampoline ()
// The keypath which the trampoline is observing.
@property (nonatomic, readonly, copy) NSString *keyPath;
// These properties should only be manipulated while synchronized on the
// receiver.
@property (nonatomic, readonly, copy) RACKVOBlock block;
@property (nonatomic, readonly, unsafe_unretained) NSObject *unsafeTarget;
@property (nonatomic, readonly, weak) NSObject *weakTarget;
@property (nonatomic, readonly, weak) NSObject *observer;
@end
@implementation RACKVOTrampoline
#pragma mark Lifecycle
- (id)initWithTarget:(__weak NSObject *)target observer:(__weak NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block {
    NSCParameterAssert(keyPath != nil);
    NSCParameterAssert(block != nil);
    NSObject *strongTarget = target;
    if (strongTarget == nil) return nil;
    self = [super init];
    if (self == nil) return nil;
    _keyPath = [keyPath copy];
    _block = [block copy];
    _weakTarget = target;
    _unsafeTarget = strongTarget;
    _observer = observer;
    [RACKVOProxy.sharedProxy addObserver:self forContext:(__bridge void *)self];
    [strongTarget addObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath options:options context:(__bridge void *)self];
    [strongTarget.rac_deallocDisposable addDisposable:self];
    [self.observer.rac_deallocDisposable addDisposable:self];
    return self;
}
- (void)dealloc {
    [self dispose];
}
#pragma mark Observation
- (void)dispose {
    NSObject *target;
    NSObject *observer;
    @synchronized (self) {
        _block = nil;
        // The target should still exist at this point, because we still need to
        // tear down its KVO observation. Therefore, we can use the unsafe
        // reference (and need to, because the weak one will have been zeroed by
        // now).
        target = self.unsafeTarget;
        observer = self.observer;
        _unsafeTarget = nil;
        _observer = nil;
    }
    [target.rac_deallocDisposable removeDisposable:self];
    [observer.rac_deallocDisposable removeDisposable:self];
    [target removeObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath context:(__bridge void *)self];
    [RACKVOProxy.sharedProxy removeObserver:self forContext:(__bridge void *)self];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (context != (__bridge void *)self) {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        return;
    }
    RACKVOBlock block;
    id observer;
    id target;
    @synchronized (self) {
        block = self.block;
        observer = self.observer;
        target = self.weakTarget;
    }
    if (block == nil || target == nil) return;
    block(target, observer, change);
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACMulticastConnection+Private.h
New file
@@ -0,0 +1,17 @@
//
//  RACMulticastConnection+Private.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 4/11/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACMulticastConnection.h"
@class RACSubject;
@interface RACMulticastConnection ()
- (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACMulticastConnection.h
New file
@@ -0,0 +1,48 @@
//
//  RACMulticastConnection.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 4/11/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACDisposable;
@class RACSignal;
/// A multicast connection encapsulates the idea of sharing one subscription to a
/// signal to many subscribers. This is most often needed if the subscription to
/// the underlying signal involves side-effects or shouldn't be called more than
/// once.
///
/// The multicasted signal is only subscribed to when
/// -[RACMulticastConnection connect] is called. Until that happens, no values
/// will be sent on `signal`. See -[RACMulticastConnection autoconnect] for how
/// -[RACMulticastConnection connect] can be called automatically.
///
/// Note that you shouldn't create RACMulticastConnection manually. Instead use
/// -[RACSignal publish] or -[RACSignal multicast:].
@interface RACMulticastConnection : NSObject
/// The multicasted signal.
@property (nonatomic, strong, readonly) RACSignal *signal;
/// Connect to the underlying signal by subscribing to it. Calling this multiple
/// times does nothing but return the existing connection's disposable.
///
/// Returns the disposable for the subscription to the multicasted signal.
- (RACDisposable *)connect;
/// Connects to the underlying signal when the returned signal is first
/// subscribed to, and disposes of the subscription to the multicasted signal
/// when the returned signal has no subscribers.
///
/// If new subscribers show up after being disposed, they'll subscribe and then
/// be immediately disposed of. The returned signal will never re-connect to the
/// multicasted signal.
///
/// Returns the autoconnecting signal.
- (RACSignal *)autoconnect;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACMulticastConnection.m
New file
@@ -0,0 +1,85 @@
//
//  RACMulticastConnection.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 4/11/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACMulticastConnection.h"
#import "RACMulticastConnection+Private.h"
#import "RACDisposable.h"
#import "RACSerialDisposable.h"
#import "RACSubject.h"
#import <libkern/OSAtomic.h>
@interface RACMulticastConnection () {
    RACSubject *_signal;
    // When connecting, a caller should attempt to atomically swap the value of this
    // from `0` to `1`.
    //
    // If the swap is successful the caller is resposible for subscribing `_signal`
    // to `sourceSignal` and storing the returned disposable in `serialDisposable`.
    //
    // If the swap is unsuccessful it means that `_sourceSignal` has already been
    // connected and the caller has no action to take.
    int32_t volatile _hasConnected;
}
@property (nonatomic, readonly, strong) RACSignal *sourceSignal;
@property (strong) RACSerialDisposable *serialDisposable;
@end
@implementation RACMulticastConnection
#pragma mark Lifecycle
- (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject {
    NSCParameterAssert(source != nil);
    NSCParameterAssert(subject != nil);
    self = [super init];
    if (self == nil) return nil;
    _sourceSignal = source;
    _serialDisposable = [[RACSerialDisposable alloc] init];
    _signal = subject;
    return self;
}
#pragma mark Connecting
- (RACDisposable *)connect {
    BOOL shouldConnect = OSAtomicCompareAndSwap32Barrier(0, 1, &_hasConnected);
    if (shouldConnect) {
        self.serialDisposable.disposable = [self.sourceSignal subscribe:_signal];
    }
    return self.serialDisposable;
}
- (RACSignal *)autoconnect {
    __block volatile int32_t subscriberCount = 0;
    return [[RACSignal
        createSignal:^(id<RACSubscriber> subscriber) {
            OSAtomicIncrement32Barrier(&subscriberCount);
            RACDisposable *subscriptionDisposable = [self.signal subscribe:subscriber];
            RACDisposable *connectionDisposable = [self connect];
            return [RACDisposable disposableWithBlock:^{
                [subscriptionDisposable dispose];
                if (OSAtomicDecrement32Barrier(&subscriberCount) == 0) {
                    [connectionDisposable dispose];
                }
            }];
        }]
        setNameWithFormat:@"[%@] -autoconnect", self.signal.name];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACObjCRuntime.h
New file
@@ -0,0 +1,17 @@
//
//  RACObjCRuntime.h
//  ReactiveCocoa
//
//  Created by Cody Krieger on 5/19/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
// A private class containing wrappers to runtime functions.
@interface RACObjCRuntime : NSObject
// Invokes objc_allocateClassPair(). Can be called from ARC code.
+ (Class)createClass:(const char *)className inheritingFromClass:(Class)superclass;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACObjCRuntime.m
New file
@@ -0,0 +1,22 @@
//
//  RACObjCRuntime.m
//  ReactiveCocoa
//
//  Created by Cody Krieger on 5/19/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACObjCRuntime.h"
#import <objc/runtime.h>
#if __has_feature(objc_arc)
#error "This file must be compiled without ARC."
#endif
@implementation RACObjCRuntime
+ (Class)createClass:(const char *)className inheritingFromClass:(Class)superclass {
    return objc_allocateClassPair(superclass, className, 0);
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACPassthroughSubscriber.h
New file
@@ -0,0 +1,29 @@
//
//  RACPassthroughSubscriber.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-06-13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RACSubscriber.h"
@class RACCompoundDisposable;
@class RACSignal;
// A private subscriber that passes through all events to another subscriber
// while not disposed.
@interface RACPassthroughSubscriber : NSObject <RACSubscriber>
// Initializes the receiver to pass through events until disposed.
//
// subscriber - The subscriber to forward events to. This must not be nil.
// signal     - The signal that will be sending events to the receiver.
// disposable - When this disposable is disposed, no more events will be
//              forwarded. This must not be nil.
//
// Returns an initialized passthrough subscriber.
- (instancetype)initWithSubscriber:(id<RACSubscriber>)subscriber signal:(RACSignal *)signal disposable:(RACCompoundDisposable *)disposable;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACPassthroughSubscriber.m
New file
@@ -0,0 +1,103 @@
//
//  RACPassthroughSubscriber.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-06-13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACPassthroughSubscriber.h"
#import "RACCompoundDisposable.h"
#import "RACSignal.h"
#import "RACSignalProvider.h"
static const char *cleanedDTraceString(NSString *original) {
    return [original stringByReplacingOccurrencesOfString:@"\\s+" withString:@" " options:NSRegularExpressionSearch range:NSMakeRange(0, original.length)].UTF8String;
}
static const char *cleanedSignalDescription(RACSignal *signal) {
    NSString *desc = signal.description;
    NSRange range = [desc rangeOfString:@" name:"];
    if (range.location != NSNotFound) {
        desc = [desc stringByReplacingCharactersInRange:range withString:@""];
    }
    return cleanedDTraceString(desc);
}
@interface RACPassthroughSubscriber ()
// The subscriber to which events should be forwarded.
@property (nonatomic, strong, readonly) id<RACSubscriber> innerSubscriber;
// The signal sending events to this subscriber.
//
// This property isn't `weak` because it's only used for DTrace probes, so
// a zeroing weak reference would incur an unnecessary performance penalty in
// normal usage.
@property (nonatomic, unsafe_unretained, readonly) RACSignal *signal;
// A disposable representing the subscription. When disposed, no further events
// should be sent to the `innerSubscriber`.
@property (nonatomic, strong, readonly) RACCompoundDisposable *disposable;
@end
@implementation RACPassthroughSubscriber
#pragma mark Lifecycle
- (instancetype)initWithSubscriber:(id<RACSubscriber>)subscriber signal:(RACSignal *)signal disposable:(RACCompoundDisposable *)disposable {
    NSCParameterAssert(subscriber != nil);
    self = [super init];
    if (self == nil) return nil;
    _innerSubscriber = subscriber;
    _signal = signal;
    _disposable = disposable;
    [self.innerSubscriber didSubscribeWithDisposable:self.disposable];
    return self;
}
#pragma mark RACSubscriber
- (void)sendNext:(id)value {
    if (self.disposable.disposed) return;
    if (RACSIGNAL_NEXT_ENABLED()) {
        RACSIGNAL_NEXT(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description), cleanedDTraceString([value description]));
    }
    [self.innerSubscriber sendNext:value];
}
- (void)sendError:(NSError *)error {
    if (self.disposable.disposed) return;
    if (RACSIGNAL_ERROR_ENABLED()) {
        RACSIGNAL_ERROR(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description), cleanedDTraceString(error.description));
    }
    [self.innerSubscriber sendError:error];
}
- (void)sendCompleted {
    if (self.disposable.disposed) return;
    if (RACSIGNAL_COMPLETED_ENABLED()) {
        RACSIGNAL_COMPLETED(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description));
    }
    [self.innerSubscriber sendCompleted];
}
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable {
    if (disposable != self.disposable) {
        [self.disposable addDisposable:disposable];
    }
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACQueueScheduler+Subclass.h
New file
@@ -0,0 +1,40 @@
//
//  RACQueueScheduler+Subclass.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 6/6/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACQueueScheduler.h"
#import "RACScheduler+Subclass.h"
/// An interface for use by GCD queue-based subclasses.
///
/// See RACScheduler+Subclass.h for subclassing notes.
@interface RACQueueScheduler ()
/// The queue on which blocks are enqueued.
#if OS_OBJECT_HAVE_OBJC_SUPPORT
@property (nonatomic, strong, readonly) dispatch_queue_t queue;
#else
// Swift builds with OS_OBJECT_HAVE_OBJC_SUPPORT=0 for Playgrounds and LLDB :(
@property (nonatomic, assign, readonly) dispatch_queue_t queue;
#endif
/// Initializes the receiver with the name of the scheduler and the queue which
/// the scheduler should use.
///
/// name  - The name of the scheduler. If nil, a default name will be used.
/// queue - The queue upon which the receiver should enqueue scheduled blocks.
///         This argument must not be NULL.
///
/// Returns the initialized object.
- (id)initWithName:(NSString *)name queue:(dispatch_queue_t)queue;
/// Converts a date into a GCD time using dispatch_walltime().
///
/// date - The date to convert. This must not be nil.
+ (dispatch_time_t)wallTimeWithDate:(NSDate *)date;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACQueueScheduler.h
New file
@@ -0,0 +1,18 @@
//
//  RACQueueScheduler.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 11/30/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACScheduler.h"
/// An abstract scheduler which asynchronously enqueues all its work to a Grand
/// Central Dispatch queue.
///
/// Because RACQueueScheduler is abstract, it should not be instantiated
/// directly. Create a subclass using the `RACQueueScheduler+Subclass.h`
/// interface and use that instead.
@interface RACQueueScheduler : RACScheduler
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACQueueScheduler.m
New file
@@ -0,0 +1,107 @@
//
//  RACQueueScheduler.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 11/30/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACQueueScheduler.h"
#import "RACDisposable.h"
#import "RACQueueScheduler+Subclass.h"
#import "RACScheduler+Private.h"
@implementation RACQueueScheduler
#pragma mark Lifecycle
- (id)initWithName:(NSString *)name queue:(dispatch_queue_t)queue {
    NSCParameterAssert(queue != NULL);
    self = [super initWithName:name];
    if (self == nil) return nil;
    _queue = queue;
#if !OS_OBJECT_HAVE_OBJC_SUPPORT
    dispatch_retain(_queue);
#endif
    return self;
}
#if !OS_OBJECT_HAVE_OBJC_SUPPORT
- (void)dealloc {
    if (_queue != NULL) {
        dispatch_release(_queue);
        _queue = NULL;
    }
}
#endif
#pragma mark Date Conversions
+ (dispatch_time_t)wallTimeWithDate:(NSDate *)date {
    NSCParameterAssert(date != nil);
    double seconds = 0;
    double frac = modf(date.timeIntervalSince1970, &seconds);
    struct timespec walltime = {
        .tv_sec = (time_t)fmin(fmax(seconds, LONG_MIN), LONG_MAX),
        .tv_nsec = (long)fmin(fmax(frac * NSEC_PER_SEC, LONG_MIN), LONG_MAX)
    };
    return dispatch_walltime(&walltime, 0);
}
#pragma mark RACScheduler
- (RACDisposable *)schedule:(void (^)(void))block {
    NSCParameterAssert(block != NULL);
    RACDisposable *disposable = [[RACDisposable alloc] init];
    dispatch_async(self.queue, ^{
        if (disposable.disposed) return;
        [self performAsCurrentScheduler:block];
    });
    return disposable;
}
- (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block {
    NSCParameterAssert(date != nil);
    NSCParameterAssert(block != NULL);
    RACDisposable *disposable = [[RACDisposable alloc] init];
    dispatch_after([self.class wallTimeWithDate:date], self.queue, ^{
        if (disposable.disposed) return;
        [self performAsCurrentScheduler:block];
    });
    return disposable;
}
- (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block {
    NSCParameterAssert(date != nil);
    NSCParameterAssert(interval > 0.0 && interval < INT64_MAX / NSEC_PER_SEC);
    NSCParameterAssert(leeway >= 0.0 && leeway < INT64_MAX / NSEC_PER_SEC);
    NSCParameterAssert(block != NULL);
    uint64_t intervalInNanoSecs = (uint64_t)(interval * NSEC_PER_SEC);
    uint64_t leewayInNanoSecs = (uint64_t)(leeway * NSEC_PER_SEC);
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue);
    dispatch_source_set_timer(timer, [self.class wallTimeWithDate:date], intervalInNanoSecs, leewayInNanoSecs);
    dispatch_source_set_event_handler(timer, block);
    dispatch_resume(timer);
    return [RACDisposable disposableWithBlock:^{
        dispatch_source_cancel(timer);
    }];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACReplaySubject.h
New file
@@ -0,0 +1,22 @@
//
//  RACReplaySubject.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/14/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACSubject.h"
extern const NSUInteger RACReplaySubjectUnlimitedCapacity;
/// A replay subject saves the values it is sent (up to its defined capacity)
/// and resends those to new subscribers. It will also replay an error or
/// completion.
@interface RACReplaySubject : RACSubject
/// Creates a new replay subject with the given capacity. A capacity of
/// RACReplaySubjectUnlimitedCapacity means values are never trimmed.
+ (instancetype)replaySubjectWithCapacity:(NSUInteger)capacity;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACReplaySubject.m
New file
@@ -0,0 +1,112 @@
//
//  RACReplaySubject.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/14/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACReplaySubject.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACScheduler+Private.h"
#import "RACSubscriber.h"
#import "RACTuple.h"
const NSUInteger RACReplaySubjectUnlimitedCapacity = NSUIntegerMax;
@interface RACReplaySubject ()
@property (nonatomic, assign, readonly) NSUInteger capacity;
// These properties should only be modified while synchronized on self.
@property (nonatomic, strong, readonly) NSMutableArray *valuesReceived;
@property (nonatomic, assign) BOOL hasCompleted;
@property (nonatomic, assign) BOOL hasError;
@property (nonatomic, strong) NSError *error;
@end
@implementation RACReplaySubject
#pragma mark Lifecycle
+ (instancetype)replaySubjectWithCapacity:(NSUInteger)capacity {
    return [(RACReplaySubject *)[self alloc] initWithCapacity:capacity];
}
- (instancetype)init {
    return [self initWithCapacity:RACReplaySubjectUnlimitedCapacity];
}
- (instancetype)initWithCapacity:(NSUInteger)capacity {
    self = [super init];
    if (self == nil) return nil;
    _capacity = capacity;
    _valuesReceived = (capacity == RACReplaySubjectUnlimitedCapacity ? [NSMutableArray array] : [NSMutableArray arrayWithCapacity:capacity]);
    return self;
}
#pragma mark RACSignal
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable];
    RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
        @synchronized (self) {
            for (id value in self.valuesReceived) {
                if (compoundDisposable.disposed) return;
                [subscriber sendNext:(value == RACTupleNil.tupleNil ? nil : value)];
            }
            if (compoundDisposable.disposed) return;
            if (self.hasCompleted) {
                [subscriber sendCompleted];
            } else if (self.hasError) {
                [subscriber sendError:self.error];
            } else {
                RACDisposable *subscriptionDisposable = [super subscribe:subscriber];
                [compoundDisposable addDisposable:subscriptionDisposable];
            }
        }
    }];
    [compoundDisposable addDisposable:schedulingDisposable];
    return compoundDisposable;
}
#pragma mark RACSubscriber
- (void)sendNext:(id)value {
    @synchronized (self) {
        [self.valuesReceived addObject:value ?: RACTupleNil.tupleNil];
        [super sendNext:value];
        if (self.capacity != RACReplaySubjectUnlimitedCapacity && self.valuesReceived.count > self.capacity) {
            [self.valuesReceived removeObjectsInRange:NSMakeRange(0, self.valuesReceived.count - self.capacity)];
        }
    }
}
- (void)sendCompleted {
    @synchronized (self) {
        self.hasCompleted = YES;
        [super sendCompleted];
    }
}
- (void)sendError:(NSError *)e {
    @synchronized (self) {
        self.hasError = YES;
        self.error = e;
        [super sendError:e];
    }
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACReturnSignal.h
New file
@@ -0,0 +1,17 @@
//
//  RACReturnSignal.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-10-10.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACSignal.h"
// A private `RACSignal` subclasses that synchronously sends a value to any
// subscribers, then completes.
@interface RACReturnSignal : RACSignal
+ (RACSignal *)return:(id)value;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACReturnSignal.m
New file
@@ -0,0 +1,90 @@
//
//  RACReturnSignal.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-10-10.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACReturnSignal.h"
#import "RACScheduler+Private.h"
#import "RACSubscriber.h"
#import "RACUnit.h"
@interface RACReturnSignal ()
// The value to send upon subscription.
@property (nonatomic, strong, readonly) id value;
@end
@implementation RACReturnSignal
#pragma mark Properties
// Only allow this signal's name to be customized in DEBUG, since it's
// potentially a singleton in release builds (see +return:).
- (void)setName:(NSString *)name {
#ifdef DEBUG
    [super setName:name];
#endif
}
- (NSString *)name {
#ifdef DEBUG
    return super.name;
#else
    return @"+return:";
#endif
}
#pragma mark Lifecycle
+ (RACSignal *)return:(id)value {
#ifndef DEBUG
    // In release builds, use singletons for two very common cases.
    if (value == RACUnit.defaultUnit) {
        static RACReturnSignal *unitSingleton;
        static dispatch_once_t unitPred;
        dispatch_once(&unitPred, ^{
            unitSingleton = [[self alloc] init];
            unitSingleton->_value = RACUnit.defaultUnit;
        });
        return unitSingleton;
    } else if (value == nil) {
        static RACReturnSignal *nilSingleton;
        static dispatch_once_t nilPred;
        dispatch_once(&nilPred, ^{
            nilSingleton = [[self alloc] init];
            nilSingleton->_value = nil;
        });
        return nilSingleton;
    }
#endif
    RACReturnSignal *signal = [[self alloc] init];
    signal->_value = value;
#ifdef DEBUG
    [signal setNameWithFormat:@"+return: %@", value];
#endif
    return signal;
}
#pragma mark Subscription
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCParameterAssert(subscriber != nil);
    return [RACScheduler.subscriptionScheduler schedule:^{
        [subscriber sendNext:self.value];
        [subscriber sendCompleted];
    }];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACScheduler+Private.h
New file
@@ -0,0 +1,34 @@
//
//  RACScheduler+Private.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 11/29/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACScheduler.h"
// The thread-specific current scheduler key.
extern NSString * const RACSchedulerCurrentSchedulerKey;
// A private interface for internal RAC use only.
@interface RACScheduler ()
// A dedicated scheduler that fills two requirements:
//
//   1. By the time subscription happens, we need a valid +currentScheduler.
//   2. Subscription should happen as soon as possible.
//
// To fulfill those two, if we already have a valid +currentScheduler, it
// immediately executes scheduled blocks. If we don't, it will execute scheduled
// blocks with a private background scheduler.
+ (instancetype)subscriptionScheduler;
// Initializes the receiver with the given name.
//
// name - The name of the scheduler. If nil, a default name will be used.
//
// Returns the initialized object.
- (id)initWithName:(NSString *)name;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACScheduler+Subclass.h
New file
@@ -0,0 +1,29 @@
//
//  RACScheduler.m
//  ReactiveCocoa
//
//  Created by MiÄ·elis Vindavs on 5/27/14.
//  Copyright (c) 2014 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RACScheduler.h"
/// An interface for use by subclasses.
///
/// Subclasses should use `-performAsCurrentScheduler:` to do the actual block
/// invocation so that +[RACScheduler currentScheduler] behaves as expected.
///
/// **Note that RACSchedulers are expected to be serial**. Subclasses must honor
/// that contract. See `RACTargetQueueScheduler` for a queue-based scheduler
/// which will enforce the serialization guarantee.
@interface RACScheduler ()
/// Performs the given block with the receiver as the current scheduler for
/// its thread. This should only be called by subclasses to perform their
/// scheduled blocks.
///
/// block - The block to execute. Cannot be NULL.
- (void)performAsCurrentScheduler:(void (^)(void))block;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACScheduler.h
New file
@@ -0,0 +1,148 @@
//
//  RACScheduler.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 4/16/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
/// The priority for the scheduler.
///
/// RACSchedulerPriorityHigh       - High priority.
/// RACSchedulerPriorityDefault    - Default priority.
/// RACSchedulerPriorityLow        - Low priority.
/// RACSchedulerPriorityBackground - Background priority.
typedef enum : long {
    RACSchedulerPriorityHigh = DISPATCH_QUEUE_PRIORITY_HIGH,
    RACSchedulerPriorityDefault = DISPATCH_QUEUE_PRIORITY_DEFAULT,
    RACSchedulerPriorityLow = DISPATCH_QUEUE_PRIORITY_LOW,
    RACSchedulerPriorityBackground = DISPATCH_QUEUE_PRIORITY_BACKGROUND,
} RACSchedulerPriority;
/// Scheduled with -scheduleRecursiveBlock:, this type of block is passed a block
/// with which it can call itself recursively.
typedef void (^RACSchedulerRecursiveBlock)(void (^reschedule)(void));
@class RACDisposable;
/// Schedulers are used to control when and where work is performed.
@interface RACScheduler : NSObject
/// A singleton scheduler that immediately executes the blocks it is given.
///
/// **Note:** Unlike most other schedulers, this does not set the current
/// scheduler. There may still be a valid +currentScheduler if this is used
/// within a block scheduled on a different scheduler.
+ (RACScheduler *)immediateScheduler;
/// A singleton scheduler that executes blocks in the main thread.
+ (RACScheduler *)mainThreadScheduler;
/// Creates and returns a new background scheduler with the given priority and
/// name. The name is for debug and instrumentation purposes only.
///
/// Scheduler creation is cheap. It's unnecessary to save the result of this
/// method call unless you want to serialize some actions on the same background
/// scheduler.
+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority name:(NSString *)name;
/// Invokes +schedulerWithPriority:name: with a default name.
+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority;
/// Invokes +schedulerWithPriority: with RACSchedulerPriorityDefault.
+ (RACScheduler *)scheduler;
/// The current scheduler. This will only be valid when used from within a
/// -[RACScheduler schedule:] block or when on the main thread.
+ (RACScheduler *)currentScheduler;
/// Schedule the given block for execution on the scheduler.
///
/// Scheduled blocks will be executed in the order in which they were scheduled.
///
/// block - The block to schedule for execution. Cannot be nil.
///
/// Returns a disposable which can be used to cancel the scheduled block before
/// it begins executing, or nil if cancellation is not supported.
- (RACDisposable *)schedule:(void (^)(void))block;
/// Schedule the given block for execution on the scheduler at or after
/// a specific time.
///
/// Note that blocks scheduled for a certain time will not preempt any other
/// scheduled work that is executing at the time.
///
/// When invoked on the +immediateScheduler, the calling thread **will block**
/// until the specified time.
///
/// date  - The earliest time at which `block` should begin executing. The block
///         may not execute immediately at this time, whether due to system load
///         or another block on the scheduler currently being run. Cannot be nil.
/// block - The block to schedule for execution. Cannot be nil.
///
/// Returns a disposable which can be used to cancel the scheduled block before
/// it begins executing, or nil if cancellation is not supported.
- (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block;
/// Schedule the given block for execution on the scheduler after the delay.
///
/// Converts the delay into an NSDate, then invokes `-after:schedule:`.
- (RACDisposable *)afterDelay:(NSTimeInterval)delay schedule:(void (^)(void))block;
/// Reschedule the given block at a particular interval, starting at a specific
/// time, and with a given leeway for deferral.
///
/// Note that blocks scheduled for a certain time will not preempt any other
/// scheduled work that is executing at the time.
///
/// Regardless of the value of `leeway`, the given block may not execute exactly
/// at `when` or exactly on successive intervals, whether due to system load or
/// because another block is currently being run on the scheduler.
///
/// It is considered undefined behavior to invoke this method on the
/// +immediateScheduler.
///
/// date     - The earliest time at which `block` should begin executing. The
///            block may not execute immediately at this time, whether due to
///            system load or another block on the scheduler currently being
///            run. Cannot be nil.
/// interval - The interval at which the block should be rescheduled, starting
///            from `date`. This will use the system wall clock, to avoid
///            skew when the computer goes to sleep.
/// leeway   - A hint to the system indicating the number of seconds that each
///            scheduling can be deferred. Note that this is just a hint, and
///            there may be some additional latency no matter what.
/// block    - The block to repeatedly schedule for execution. Cannot be nil.
///
/// Returns a disposable which can be used to cancel the automatic scheduling and
/// rescheduling, or nil if cancellation is not supported.
- (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block;
/// Schedule the given recursive block for execution on the scheduler. The
/// scheduler will automatically flatten any recursive scheduling into iteration
/// instead, so this can be used without issue for blocks that may keep invoking
/// themselves forever.
///
/// Scheduled blocks will be executed in the order in which they were scheduled.
///
/// recursiveBlock - The block to schedule for execution. When invoked, the
///                  recursive block will be passed a `void (^)(void)` block
///                  which will reschedule the recursive block at the end of the
///                  receiver's queue. This passed-in block will automatically
///                  skip scheduling if the scheduling of the `recursiveBlock`
///                  was disposed in the meantime.
///
/// Returns a disposable which can be used to cancel the scheduled block before
/// it begins executing, or to stop it from rescheduling if it's already begun
/// execution.
- (RACDisposable *)scheduleRecursiveBlock:(RACSchedulerRecursiveBlock)recursiveBlock;
@end
@interface RACScheduler (Deprecated)
+ (RACScheduler *)schedulerWithQueue:(dispatch_queue_t)queue name:(NSString *)name __attribute__((deprecated("Use -[RACTargetQueueScheduler initWithName:targetQueue:] instead.")));
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACScheduler.m
New file
@@ -0,0 +1,227 @@
//
//  RACScheduler.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 4/16/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACScheduler.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACImmediateScheduler.h"
#import "RACScheduler+Private.h"
#import "RACSubscriptionScheduler.h"
#import "RACTargetQueueScheduler.h"
// The key for the thread-specific current scheduler.
NSString * const RACSchedulerCurrentSchedulerKey = @"RACSchedulerCurrentSchedulerKey";
@interface RACScheduler ()
@property (nonatomic, readonly, copy) NSString *name;
@end
@implementation RACScheduler
#pragma mark NSObject
- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: %p> %@", self.class, self, self.name];
}
#pragma mark Initializers
- (id)initWithName:(NSString *)name {
    self = [super init];
    if (self == nil) return nil;
    if (name == nil) {
        _name = [NSString stringWithFormat:@"com.ReactiveCocoa.%@.anonymousScheduler", self.class];
    } else {
        _name = [name copy];
    }
    return self;
}
#pragma mark Schedulers
+ (instancetype)immediateScheduler {
    static dispatch_once_t onceToken;
    static RACScheduler *immediateScheduler;
    dispatch_once(&onceToken, ^{
        immediateScheduler = [[RACImmediateScheduler alloc] init];
    });
    return immediateScheduler;
}
+ (instancetype)mainThreadScheduler {
    static dispatch_once_t onceToken;
    static RACScheduler *mainThreadScheduler;
    dispatch_once(&onceToken, ^{
        mainThreadScheduler = [[RACTargetQueueScheduler alloc] initWithName:@"com.ReactiveCocoa.RACScheduler.mainThreadScheduler" targetQueue:dispatch_get_main_queue()];
    });
    return mainThreadScheduler;
}
+ (instancetype)schedulerWithPriority:(RACSchedulerPriority)priority name:(NSString *)name {
    return [[RACTargetQueueScheduler alloc] initWithName:name targetQueue:dispatch_get_global_queue(priority, 0)];
}
+ (instancetype)schedulerWithPriority:(RACSchedulerPriority)priority {
    return [self schedulerWithPriority:priority name:@"com.ReactiveCocoa.RACScheduler.backgroundScheduler"];
}
+ (instancetype)scheduler {
    return [self schedulerWithPriority:RACSchedulerPriorityDefault];
}
+ (instancetype)subscriptionScheduler {
    static dispatch_once_t onceToken;
    static RACScheduler *subscriptionScheduler;
    dispatch_once(&onceToken, ^{
        subscriptionScheduler = [[RACSubscriptionScheduler alloc] init];
    });
    return subscriptionScheduler;
}
+ (BOOL)isOnMainThread {
    return [NSOperationQueue.currentQueue isEqual:NSOperationQueue.mainQueue] || [NSThread isMainThread];
}
+ (instancetype)currentScheduler {
    RACScheduler *scheduler = NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey];
    if (scheduler != nil) return scheduler;
    if ([self.class isOnMainThread]) return RACScheduler.mainThreadScheduler;
    return nil;
}
#pragma mark Scheduling
- (RACDisposable *)schedule:(void (^)(void))block {
    NSCAssert(NO, @"%@ must be implemented by subclasses.", NSStringFromSelector(_cmd));
    return nil;
}
- (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block {
    NSCAssert(NO, @"%@ must be implemented by subclasses.", NSStringFromSelector(_cmd));
    return nil;
}
- (RACDisposable *)afterDelay:(NSTimeInterval)delay schedule:(void (^)(void))block {
    return [self after:[NSDate dateWithTimeIntervalSinceNow:delay] schedule:block];
}
- (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block {
    NSCAssert(NO, @"%@ must be implemented by subclasses.", NSStringFromSelector(_cmd));
    return nil;
}
- (RACDisposable *)scheduleRecursiveBlock:(RACSchedulerRecursiveBlock)recursiveBlock {
    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    [self scheduleRecursiveBlock:[recursiveBlock copy] addingToDisposable:disposable];
    return disposable;
}
- (void)scheduleRecursiveBlock:(RACSchedulerRecursiveBlock)recursiveBlock addingToDisposable:(RACCompoundDisposable *)disposable {
    @autoreleasepool {
        RACCompoundDisposable *selfDisposable = [RACCompoundDisposable compoundDisposable];
        [disposable addDisposable:selfDisposable];
        __weak RACDisposable *weakSelfDisposable = selfDisposable;
        RACDisposable *schedulingDisposable = [self schedule:^{
            @autoreleasepool {
                // At this point, we've been invoked, so our disposable is now useless.
                [disposable removeDisposable:weakSelfDisposable];
            }
            if (disposable.disposed) return;
            void (^reallyReschedule)(void) = ^{
                if (disposable.disposed) return;
                [self scheduleRecursiveBlock:recursiveBlock addingToDisposable:disposable];
            };
            // Protects the variables below.
            //
            // This doesn't actually need to be __block qualified, but Clang
            // complains otherwise. :C
            __block NSLock *lock = [[NSLock alloc] init];
            lock.name = [NSString stringWithFormat:@"%@ %s", self, sel_getName(_cmd)];
            __block NSUInteger rescheduleCount = 0;
            // Set to YES once synchronous execution has finished. Further
            // rescheduling should occur immediately (rather than being
            // flattened).
            __block BOOL rescheduleImmediately = NO;
            @autoreleasepool {
                recursiveBlock(^{
                    [lock lock];
                    BOOL immediate = rescheduleImmediately;
                    if (!immediate) ++rescheduleCount;
                    [lock unlock];
                    if (immediate) reallyReschedule();
                });
            }
            [lock lock];
            NSUInteger synchronousCount = rescheduleCount;
            rescheduleImmediately = YES;
            [lock unlock];
            for (NSUInteger i = 0; i < synchronousCount; i++) {
                reallyReschedule();
            }
        }];
        [selfDisposable addDisposable:schedulingDisposable];
    }
}
- (void)performAsCurrentScheduler:(void (^)(void))block {
    NSCParameterAssert(block != NULL);
    // If we're using a concurrent queue, we could end up in here concurrently,
    // in which case we *don't* want to clear the current scheduler immediately
    // after our block is done executing, but only *after* all our concurrent
    // invocations are done.
    RACScheduler *previousScheduler = RACScheduler.currentScheduler;
    NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = self;
    @autoreleasepool {
        block();
    }
    if (previousScheduler != nil) {
        NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = previousScheduler;
    } else {
        [NSThread.currentThread.threadDictionary removeObjectForKey:RACSchedulerCurrentSchedulerKey];
    }
}
@end
@implementation RACScheduler (Deprecated)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
+ (instancetype)schedulerWithQueue:(dispatch_queue_t)queue name:(NSString *)name {
    NSCParameterAssert(queue != NULL);
    return [[RACTargetQueueScheduler alloc] initWithName:name targetQueue:queue];
}
#pragma clang diagnostic pop
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACScopedDisposable.h
New file
@@ -0,0 +1,18 @@
//
//  RACScopedDisposable.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/28/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACDisposable.h"
/// A disposable that calls its own -dispose when it is dealloc'd.
@interface RACScopedDisposable : RACDisposable
/// Creates a new scoped disposable that will also dispose of the given
/// disposable when it is dealloc'd.
+ (instancetype)scopedDisposableWithDisposable:(RACDisposable *)disposable;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACScopedDisposable.m
New file
@@ -0,0 +1,32 @@
//
//  RACScopedDisposable.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/28/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACScopedDisposable.h"
@implementation RACScopedDisposable
#pragma mark Lifecycle
+ (instancetype)scopedDisposableWithDisposable:(RACDisposable *)disposable {
    return [self disposableWithBlock:^{
        [disposable dispose];
    }];
}
- (void)dealloc {
    [self dispose];
}
#pragma mark RACDisposable
- (RACScopedDisposable *)asScopedDisposable {
    // totally already are
    return self;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSequence.h
New file
@@ -0,0 +1,154 @@
//
//  RACSequence.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RACStream.h"
@class RACScheduler;
@class RACSignal;
/// Represents an immutable sequence of values. Unless otherwise specified, the
/// sequences' values are evaluated lazily on demand. Like Cocoa collections,
/// sequences cannot contain nil.
///
/// Most inherited RACStream methods that accept a block will execute the block
/// _at most_ once for each value that is evaluated in the returned sequence.
/// Side effects are subject to the behavior described in
/// +sequenceWithHeadBlock:tailBlock:.
///
/// Implemented as a class cluster. A minimal implementation for a subclass
/// consists simply of -head and -tail.
@interface RACSequence : RACStream <NSCoding, NSCopying, NSFastEnumeration>
/// The first object in the sequence, or nil if the sequence is empty.
///
/// Subclasses must provide an implementation of this method.
@property (nonatomic, strong, readonly) id head;
/// All but the first object in the sequence, or nil if the sequence is empty.
///
/// Subclasses must provide an implementation of this method.
@property (nonatomic, strong, readonly) RACSequence *tail;
/// Evaluates the full sequence to produce an equivalently-sized array.
@property (nonatomic, copy, readonly) NSArray *array;
/// Returns an enumerator of all objects in the sequence.
@property (nonatomic, copy, readonly) NSEnumerator *objectEnumerator;
/// Converts a sequence into an eager sequence.
///
/// An eager sequence fully evaluates all of its values immediately. Sequences
/// derived from an eager sequence will also be eager.
///
/// Returns a new eager sequence, or the receiver if the sequence is already
/// eager.
@property (nonatomic, copy, readonly) RACSequence *eagerSequence;
/// Converts a sequence into a lazy sequence.
///
/// A lazy sequence evaluates its values on demand, as they are accessed.
/// Sequences derived from a lazy sequence will also be lazy.
///
/// Returns a new lazy sequence, or the receiver if the sequence is already lazy.
@property (nonatomic, copy, readonly) RACSequence *lazySequence;
/// Invokes -signalWithScheduler: with a new RACScheduler.
- (RACSignal *)signal;
/// Evaluates the full sequence on the given scheduler.
///
/// Each item is evaluated in its own scheduled block, such that control of the
/// scheduler is yielded between each value.
///
/// Returns a signal which sends the receiver's values on the given scheduler as
/// they're evaluated.
- (RACSignal *)signalWithScheduler:(RACScheduler *)scheduler;
/// Applies a left fold to the sequence.
///
/// This is the same as iterating the sequence along with a provided start value.
/// This uses a constant amount of memory. A left fold is left-associative so in
/// the sequence [1,2,3] the block would applied in the following order:
///  reduce(reduce(reduce(start, 1), 2), 3)
///
/// start  - The starting value for the fold. Used as `accumulator` for the
///          first fold.
/// reduce - The block used to combine the accumulated value and the next value.
///          Cannot be nil.
///
/// Returns a reduced value.
- (id)foldLeftWithStart:(id)start reduce:(id (^)(id accumulator, id value))reduce;
/// Applies a right fold to the sequence.
///
/// A right fold is equivalent to recursion on the list. The block is evaluated
/// from the right to the left in list. It is right associative so it's applied
/// to the rightmost elements first. For example, in the sequence [1,2,3] the
/// block is applied in the order:
///   reduce(1, reduce(2, reduce(3, start)))
///
/// start  - The starting value for the fold.
/// reduce - The block used to combine the accumulated value and the next head.
///          The block is given the accumulated value and the value of the rest
///          of the computation (result of the recursion). This is computed when
///          you retrieve its value using `rest.head`. This allows you to
///          prevent unnecessary computation by not accessing `rest.head` if you
///          don't need to.
///
/// Returns a reduced value.
- (id)foldRightWithStart:(id)start reduce:(id (^)(id first, RACSequence *rest))reduce;
/// Check if any value in sequence passes the block.
///
/// block - The block predicate used to check each item. Cannot be nil.
///
/// Returns a boolean indiciating if any value in the sequence passed.
- (BOOL)any:(BOOL (^)(id value))block;
/// Check if all values in the sequence pass the block.
///
/// block - The block predicate used to check each item. Cannot be nil.
///
/// Returns a boolean indicating if all values in the sequence passed.
- (BOOL)all:(BOOL (^)(id value))block;
/// Returns the first object that passes the block.
///
/// block - The block predicate used to check each item. Cannot be nil.
///
/// Returns an object that passes the block or nil if no objects passed.
- (id)objectPassingTest:(BOOL (^)(id value))block;
/// Creates a sequence that dynamically generates its values.
///
/// headBlock - Invoked the first time -head is accessed.
/// tailBlock - Invoked the first time -tail is accessed.
///
/// The results from each block are memoized, so each block will be invoked at
/// most once, no matter how many times the head and tail properties of the
/// sequence are accessed.
///
/// Any side effects in `headBlock` or `tailBlock` should be thread-safe, since
/// the sequence may be evaluated at any time from any thread. Not only that, but
/// -tail may be accessed before -head, or both may be accessed simultaneously.
/// As noted above, side effects will only be triggered the _first_ time -head or
/// -tail is invoked.
///
/// Returns a sequence that lazily invokes the given blocks to provide head and
/// tail. `headBlock` must not be nil.
+ (RACSequence *)sequenceWithHeadBlock:(id (^)(void))headBlock tailBlock:(RACSequence *(^)(void))tailBlock;
@end
@interface RACSequence (Deprecated)
- (id)foldLeftWithStart:(id)start combine:(id (^)(id accumulator, id value))combine __attribute__((deprecated("Renamed to -foldLeftWithStart:reduce:")));
- (id)foldRightWithStart:(id)start combine:(id (^)(id first, RACSequence *rest))combine __attribute__((deprecated("Renamed to -foldRightWithStart:reduce:")));
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSequence.m
New file
@@ -0,0 +1,384 @@
//
//  RACSequence.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "RACSequence.h"
#import "RACArraySequence.h"
#import "RACDynamicSequence.h"
#import "RACEagerSequence.h"
#import "RACEmptySequence.h"
#import "RACScheduler.h"
#import "RACSignal.h"
#import "RACSubscriber.h"
#import "RACTuple.h"
#import "RACUnarySequence.h"
// An enumerator over sequences.
@interface RACSequenceEnumerator : NSEnumerator
// The sequence the enumerator is enumerating.
//
// This will change as the enumerator is exhausted. This property should only be
// accessed while synchronized on self.
@property (nonatomic, strong) RACSequence *sequence;
@end
@interface RACSequence ()
// Performs one iteration of lazy binding, passing through values from `current`
// until the sequence is exhausted, then recursively binding the remaining
// values in the receiver.
//
// Returns a new sequence which contains `current`, followed by the combined
// result of all applications of `block` to the remaining values in the receiver.
- (instancetype)bind:(RACStreamBindBlock)block passingThroughValuesFromSequence:(RACSequence *)current;
@end
@implementation RACSequenceEnumerator
- (id)nextObject {
    id object = nil;
    @synchronized (self) {
        object = self.sequence.head;
        self.sequence = self.sequence.tail;
    }
    return object;
}
@end
@implementation RACSequence
#pragma mark Lifecycle
+ (RACSequence *)sequenceWithHeadBlock:(id (^)(void))headBlock tailBlock:(RACSequence *(^)(void))tailBlock {
    return [[RACDynamicSequence sequenceWithHeadBlock:headBlock tailBlock:tailBlock] setNameWithFormat:@"+sequenceWithHeadBlock:tailBlock:"];
}
#pragma mark Class cluster primitives
- (id)head {
    NSCAssert(NO, @"%s must be overridden by subclasses", __func__);
    return nil;
}
- (RACSequence *)tail {
    NSCAssert(NO, @"%s must be overridden by subclasses", __func__);
    return nil;
}
#pragma mark RACStream
+ (instancetype)empty {
    return RACEmptySequence.empty;
}
+ (instancetype)return:(id)value {
    return [RACUnarySequence return:value];
}
- (instancetype)bind:(RACStreamBindBlock (^)(void))block {
    RACStreamBindBlock bindBlock = block();
    return [[self bind:bindBlock passingThroughValuesFromSequence:nil] setNameWithFormat:@"[%@] -bind:", self.name];
}
- (instancetype)bind:(RACStreamBindBlock)bindBlock passingThroughValuesFromSequence:(RACSequence *)passthroughSequence {
    // Store values calculated in the dependency here instead, avoiding any kind
    // of temporary collection and boxing.
    //
    // This relies on the implementation of RACDynamicSequence synchronizing
    // access to its head, tail, and dependency, and we're only doing it because
    // we really need the performance.
    __block RACSequence *valuesSeq = self;
    __block RACSequence *current = passthroughSequence;
    __block BOOL stop = NO;
    RACSequence *sequence = [RACDynamicSequence sequenceWithLazyDependency:^ id {
        while (current.head == nil) {
            if (stop) return nil;
            // We've exhausted the current sequence, create a sequence from the
            // next value.
            id value = valuesSeq.head;
            if (value == nil) {
                // We've exhausted all the sequences.
                stop = YES;
                return nil;
            }
            current = (id)bindBlock(value, &stop);
            if (current == nil) {
                stop = YES;
                return nil;
            }
            valuesSeq = valuesSeq.tail;
        }
        NSCAssert([current isKindOfClass:RACSequence.class], @"-bind: block returned an object that is not a sequence: %@", current);
        return nil;
    } headBlock:^(id _) {
        return current.head;
    } tailBlock:^ id (id _) {
        if (stop) return nil;
        return [valuesSeq bind:bindBlock passingThroughValuesFromSequence:current.tail];
    }];
    sequence.name = self.name;
    return sequence;
}
- (instancetype)concat:(RACStream *)stream {
    NSCParameterAssert(stream != nil);
    return [[[RACArraySequence sequenceWithArray:@[ self, stream ] offset:0]
        flatten]
        setNameWithFormat:@"[%@] -concat: %@", self.name, stream];
}
- (instancetype)zipWith:(RACSequence *)sequence {
    NSCParameterAssert(sequence != nil);
    return [[RACSequence
        sequenceWithHeadBlock:^ id {
            if (self.head == nil || sequence.head == nil) return nil;
            return RACTuplePack(self.head, sequence.head);
        } tailBlock:^ id {
            if (self.tail == nil || [[RACSequence empty] isEqual:self.tail]) return nil;
            if (sequence.tail == nil || [[RACSequence empty] isEqual:sequence.tail]) return nil;
            return [self.tail zipWith:sequence.tail];
        }]
        setNameWithFormat:@"[%@] -zipWith: %@", self.name, sequence];
}
#pragma mark Extended methods
- (NSArray *)array {
    NSMutableArray *array = [NSMutableArray array];
    for (id obj in self) {
        [array addObject:obj];
    }
    return [array copy];
}
- (NSEnumerator *)objectEnumerator {
    RACSequenceEnumerator *enumerator = [[RACSequenceEnumerator alloc] init];
    enumerator.sequence = self;
    return enumerator;
}
- (RACSignal *)signal {
    return [[self signalWithScheduler:[RACScheduler scheduler]] setNameWithFormat:@"[%@] -signal", self.name];
}
- (RACSignal *)signalWithScheduler:(RACScheduler *)scheduler {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        __block RACSequence *sequence = self;
        return [scheduler scheduleRecursiveBlock:^(void (^reschedule)(void)) {
            if (sequence.head == nil) {
                [subscriber sendCompleted];
                return;
            }
            [subscriber sendNext:sequence.head];
            sequence = sequence.tail;
            reschedule();
        }];
    }] setNameWithFormat:@"[%@] -signalWithScheduler: %@", self.name, scheduler];
}
- (id)foldLeftWithStart:(id)start reduce:(id (^)(id, id))reduce {
    NSCParameterAssert(reduce != NULL);
    if (self.head == nil) return start;
    for (id value in self) {
        start = reduce(start, value);
    }
    return start;
}
- (id)foldRightWithStart:(id)start reduce:(id (^)(id, RACSequence *))reduce {
    NSCParameterAssert(reduce != NULL);
    if (self.head == nil) return start;
    RACSequence *rest = [RACSequence sequenceWithHeadBlock:^{
        return [self.tail foldRightWithStart:start reduce:reduce];
    } tailBlock:nil];
    return reduce(self.head, rest);
}
- (BOOL)any:(BOOL (^)(id))block {
    NSCParameterAssert(block != NULL);
    return [self objectPassingTest:block] != nil;
}
- (BOOL)all:(BOOL (^)(id))block {
    NSCParameterAssert(block != NULL);
    NSNumber *result = [self foldLeftWithStart:@YES reduce:^(NSNumber *accumulator, id value) {
        return @(accumulator.boolValue && block(value));
    }];
    return result.boolValue;
}
- (id)objectPassingTest:(BOOL (^)(id))block {
    NSCParameterAssert(block != NULL);
    return [self filter:block].head;
}
- (RACSequence *)eagerSequence {
    return [RACEagerSequence sequenceWithArray:self.array offset:0];
}
- (RACSequence *)lazySequence {
    return self;
}
#pragma mark NSCopying
- (id)copyWithZone:(NSZone *)zone {
    return self;
}
#pragma mark NSCoding
- (Class)classForCoder {
    // Most sequences should be archived as RACArraySequences.
    return RACArraySequence.class;
}
- (id)initWithCoder:(NSCoder *)coder {
    if (![self isKindOfClass:RACArraySequence.class]) return [[RACArraySequence alloc] initWithCoder:coder];
    // Decoding is handled in RACArraySequence.
    return [super init];
}
- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.array forKey:@"array"];
}
#pragma mark NSFastEnumeration
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id *)stackbuf count:(NSUInteger)len {
    if (state->state == ULONG_MAX) {
        // Enumeration has completed.
        return 0;
    }
    // We need to traverse the sequence itself on repeated calls to this
    // method, so use the 'state' field to track the current head.
    RACSequence *(^getSequence)(void) = ^{
        return (__bridge RACSequence *)(void *)state->state;
    };
    void (^setSequence)(RACSequence *) = ^(RACSequence *sequence) {
        // Release the old sequence and retain the new one.
        CFBridgingRelease((void *)state->state);
        state->state = (unsigned long)CFBridgingRetain(sequence);
    };
    void (^complete)(void) = ^{
        // Release any stored sequence.
        setSequence(nil);
        state->state = ULONG_MAX;
    };
    if (state->state == 0) {
        // Since a sequence doesn't mutate, this just needs to be set to
        // something non-NULL.
        state->mutationsPtr = state->extra;
        setSequence(self);
    }
    state->itemsPtr = stackbuf;
    NSUInteger enumeratedCount = 0;
    while (enumeratedCount < len) {
        RACSequence *seq = getSequence();
        // Because the objects in a sequence may be generated lazily, we want to
        // prevent them from being released until the enumerator's used them.
        __autoreleasing id obj = seq.head;
        if (obj == nil) {
            complete();
            break;
        }
        stackbuf[enumeratedCount++] = obj;
        if (seq.tail == nil) {
            complete();
            break;
        }
        setSequence(seq.tail);
    }
    return enumeratedCount;
}
#pragma mark NSObject
- (NSUInteger)hash {
    return [self.head hash];
}
- (BOOL)isEqual:(RACSequence *)seq {
    if (self == seq) return YES;
    if (![seq isKindOfClass:RACSequence.class]) return NO;
    for (id<NSObject> selfObj in self) {
        id<NSObject> seqObj = seq.head;
        // Handles the nil case too.
        if (![seqObj isEqual:selfObj]) return NO;
        seq = seq.tail;
    }
    // self is now depleted -- the argument should be too.
    return (seq.head == nil);
}
@end
@implementation RACSequence (Deprecated)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
- (id)foldLeftWithStart:(id)start combine:(id (^)(id accumulator, id value))combine {
    return [self foldLeftWithStart:start reduce:combine];
}
- (id)foldRightWithStart:(id)start combine:(id (^)(id first, RACSequence *rest))combine {
    return [self foldRightWithStart:start reduce:combine];
}
#pragma clang diagnostic pop
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSerialDisposable.h
New file
@@ -0,0 +1,43 @@
//
//  RACSerialDisposable.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-07-22.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACDisposable.h"
/// A disposable that contains exactly one other disposable and allows it to be
/// swapped out atomically.
@interface RACSerialDisposable : RACDisposable
/// The inner disposable managed by the serial disposable.
///
/// This property is thread-safe for reading and writing. However, if you want to
/// read the current value _and_ write a new one atomically, use
/// -swapInDisposable: instead.
///
/// Disposing of the receiver will also dispose of the current disposable set for
/// this property, then set the property to nil. If any new disposable is set
/// after the receiver is disposed, it will be disposed immediately and this
/// property will remain set to nil.
@property (atomic, strong) RACDisposable *disposable;
/// Creates a serial disposable which will wrap the given disposable.
///
/// disposable - The value to set for `disposable`. This may be nil.
///
/// Returns a RACSerialDisposable, or nil if an error occurs.
+ (instancetype)serialDisposableWithDisposable:(RACDisposable *)disposable;
/// Atomically swaps the receiver's `disposable` for `newDisposable`.
///
/// newDisposable - The new value for `disposable`. If the receiver has already
///                 been disposed, this disposable will be too, and `disposable`
///                 will remain set to nil. This argument may be nil.
///
/// Returns the previous value for the `disposable` property.
- (RACDisposable *)swapInDisposable:(RACDisposable *)newDisposable;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSerialDisposable.m
New file
@@ -0,0 +1,107 @@
//
//  RACSerialDisposable.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-07-22.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACSerialDisposable.h"
#import <libkern/OSAtomic.h>
@interface RACSerialDisposable () {
    // The receiver's `disposable`. This variable must only be referenced while
    // _spinLock is held.
    RACDisposable * _disposable;
    // YES if the receiver has been disposed. This variable must only be modified
    // while _spinLock is held.
    BOOL _disposed;
    // A spinlock to protect access to _disposable and _disposed.
    //
    // It must be used when _disposable is mutated or retained and when _disposed
    // is mutated.
    OSSpinLock _spinLock;
}
@end
@implementation RACSerialDisposable
#pragma mark Properties
- (BOOL)isDisposed {
    return _disposed;
}
- (RACDisposable *)disposable {
    RACDisposable *result;
    OSSpinLockLock(&_spinLock);
    result = _disposable;
    OSSpinLockUnlock(&_spinLock);
    return result;
}
- (void)setDisposable:(RACDisposable *)disposable {
    [self swapInDisposable:disposable];
}
#pragma mark Lifecycle
+ (instancetype)serialDisposableWithDisposable:(RACDisposable *)disposable {
    RACSerialDisposable *serialDisposable = [[self alloc] init];
    serialDisposable.disposable = disposable;
    return serialDisposable;
}
- (id)initWithBlock:(void (^)(void))block {
    self = [self init];
    if (self == nil) return nil;
    self.disposable = [RACDisposable disposableWithBlock:block];
    return self;
}
#pragma mark Inner Disposable
- (RACDisposable *)swapInDisposable:(RACDisposable *)newDisposable {
    RACDisposable *existingDisposable;
    BOOL alreadyDisposed;
    OSSpinLockLock(&_spinLock);
    alreadyDisposed = _disposed;
    if (!alreadyDisposed) {
        existingDisposable = _disposable;
        _disposable = newDisposable;
    }
    OSSpinLockUnlock(&_spinLock);
    if (alreadyDisposed) {
        [newDisposable dispose];
        return nil;
    }
    return existingDisposable;
}
#pragma mark Disposal
- (void)dispose {
    RACDisposable *existingDisposable;
    OSSpinLockLock(&_spinLock);
    if (!_disposed) {
        existingDisposable = _disposable;
        _disposed = YES;
        _disposable = nil;
    }
    OSSpinLockUnlock(&_spinLock);
    [existingDisposable dispose];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSignal+Operations.h
New file
@@ -0,0 +1,709 @@
//
//  RACSignal+Operations.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-09-06.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RACSignal.h"
/// The domain for errors originating in RACSignal operations.
extern NSString * const RACSignalErrorDomain;
/// The error code used with -timeout:.
extern const NSInteger RACSignalErrorTimedOut;
/// The error code used when a value passed into +switch:cases:default: does not
/// match any of the cases, and no default was given.
extern const NSInteger RACSignalErrorNoMatchingCase;
@class RACCommand;
@class RACDisposable;
@class RACMulticastConnection;
@class RACScheduler;
@class RACSequence;
@class RACSubject;
@class RACTuple;
@protocol RACSubscriber;
@interface RACSignal (Operations)
/// Do the given block on `next`. This should be used to inject side effects into
/// the signal.
- (RACSignal *)doNext:(void (^)(id x))block;
/// Do the given block on `error`. This should be used to inject side effects
/// into the signal.
- (RACSignal *)doError:(void (^)(NSError *error))block;
/// Do the given block on `completed`. This should be used to inject side effects
/// into the signal.
- (RACSignal *)doCompleted:(void (^)(void))block;
/// Sends `next`s only if we don't receive another `next` in `interval` seconds.
///
/// If a `next` is received, and then another `next` is received before
/// `interval` seconds have passed, the first value is discarded.
///
/// After `interval` seconds have passed since the most recent `next` was sent,
/// the most recent `next` is forwarded on the scheduler that the value was
/// originally received on. If +[RACScheduler currentScheduler] was nil at the
/// time, a private background scheduler is used.
///
/// Returns a signal which sends throttled and delayed `next` events. Completion
/// and errors are always forwarded immediately.
- (RACSignal *)throttle:(NSTimeInterval)interval;
/// Throttles `next`s for which `predicate` returns YES.
///
/// When `predicate` returns YES for a `next`:
///
///  1. If another `next` is received before `interval` seconds have passed, the
///     prior value is discarded. This happens regardless of whether the new
///     value will be throttled.
///  2. After `interval` seconds have passed since the value was originally
///     received, it will be forwarded on the scheduler that it was received
///     upon. If +[RACScheduler currentScheduler] was nil at the time, a private
///     background scheduler is used.
///
/// When `predicate` returns NO for a `next`, it is forwarded immediately,
/// without any throttling.
///
/// interval  - The number of seconds for which to buffer the latest value that
///             passes `predicate`.
/// predicate - Passed each `next` from the receiver, this block returns
///             whether the given value should be throttled. This argument must
///             not be nil.
///
/// Returns a signal which sends `next` events, throttled when `predicate`
/// returns YES. Completion and errors are always forwarded immediately.
- (RACSignal *)throttle:(NSTimeInterval)interval valuesPassingTest:(BOOL (^)(id next))predicate;
/// Forwards `next` and `completed` events after delaying for `interval` seconds
/// on the current scheduler (on which the events were delivered).
///
/// If +[RACScheduler currentScheduler] is nil when `next` or `completed` is
/// received, a private background scheduler is used.
///
/// Returns a signal which sends delayed `next` and `completed` events. Errors
/// are always forwarded immediately.
- (RACSignal *)delay:(NSTimeInterval)interval;
/// Resubscribes when the signal completes.
- (RACSignal *)repeat;
/// Executes the given block each time a subscription is created.
///
/// block - A block which defines the subscription side effects. Cannot be `nil`.
///
/// Example:
///
///   // Write new file, with backup.
///   [[[[fileManager
///       rac_createFileAtPath:path contents:data]
///       initially:^{
///           // 2. Second, backup current file
///           [fileManager moveItemAtPath:path toPath:backupPath error:nil];
///       }]
///       initially:^{
///           // 1. First, acquire write lock.
///           [writeLock lock];
///       }]
///       finally:^{
///           [writeLock unlock];
///       }];
///
/// Returns a signal that passes through all events of the receiver, plus
/// introduces side effects which occur prior to any subscription side effects
/// of the receiver.
- (RACSignal *)initially:(void (^)(void))block;
/// Executes the given block when the signal completes or errors.
- (RACSignal *)finally:(void (^)(void))block;
/// Divides the receiver's `next`s into buffers which deliver every `interval`
/// seconds.
///
/// interval  - The interval in which values are grouped into one buffer.
/// scheduler - The scheduler upon which the returned signal will deliver its
///             values. This must not be nil or +[RACScheduler
///             immediateScheduler].
///
/// Returns a signal which sends RACTuples of the buffered values at each
/// interval on `scheduler`. When the receiver completes, any currently-buffered
/// values will be sent immediately.
- (RACSignal *)bufferWithTime:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler;
/// Collects all receiver's `next`s into a NSArray. Nil values will be converted
/// to NSNull.
///
/// This corresponds to the `ToArray` method in Rx.
///
/// Returns a signal which sends a single NSArray when the receiver completes
/// successfully.
- (RACSignal *)collect;
/// Takes the last `count` `next`s after the receiving signal completes.
- (RACSignal *)takeLast:(NSUInteger)count;
/// Combines the latest values from the receiver and the given signal into
/// RACTuples, once both have sent at least one `next`.
///
/// Any additional `next`s will result in a new RACTuple with the latest values
/// from both signals.
///
/// signal - The signal to combine with. This argument must not be nil.
///
/// Returns a signal which sends RACTuples of the combined values, forwards any
/// `error` events, and completes when both input signals complete.
- (RACSignal *)combineLatestWith:(RACSignal *)signal;
/// Combines the latest values from the given signals into RACTuples, once all
/// the signals have sent at least one `next`.
///
/// Any additional `next`s will result in a new RACTuple with the latest values
/// from all signals.
///
/// signals - The signals to combine. If this collection is empty, the returned
///           signal will immediately complete upon subscription.
///
/// Returns a signal which sends RACTuples of the combined values, forwards any
/// `error` events, and completes when all input signals complete.
+ (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals;
/// Combines signals using +combineLatest:, then reduces the resulting tuples
/// into a single value using -reduceEach:.
///
/// signals     - The signals to combine. If this collection is empty, the
///               returned signal will immediately complete upon subscription.
/// reduceBlock - The block which reduces the latest values from all the
///               signals into one value. It must take as many arguments as the
///               number of signals given. Each argument will be an object
///               argument. The return value must be an object. This argument
///               must not be nil.
///
/// Example:
///
///   [RACSignal combineLatest:@[ stringSignal, intSignal ] reduce:^(NSString *string, NSNumber *number) {
///       return [NSString stringWithFormat:@"%@: %@", string, number];
///   }];
///
/// Returns a signal which sends the results from each invocation of
/// `reduceBlock`.
+ (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals reduce:(id (^)())reduceBlock;
/// Merges the receiver and the given signal with `+merge:` and returns the
/// resulting signal.
- (RACSignal *)merge:(RACSignal *)signal;
/// Sends the latest `next` from any of the signals.
///
/// Returns a signal that passes through values from each of the given signals,
/// and sends `completed` when all of them complete. If any signal sends an error,
/// the returned signal sends `error` immediately.
+ (RACSignal *)merge:(id<NSFastEnumeration>)signals;
/// Merges the signals sent by the receiver into a flattened signal, but only
/// subscribes to `maxConcurrent` number of signals at a time. New signals are
/// queued and subscribed to as other signals complete.
///
/// If an error occurs on any of the signals, it is sent on the returned signal.
/// It completes only after the receiver and all sent signals have completed.
///
/// This corresponds to `Merge<TSource>(IObservable<IObservable<TSource>>, Int32)`
/// in Rx.
///
/// maxConcurrent - the maximum number of signals to subscribe to at a
///                 time. If 0, it subscribes to an unlimited number of
///                 signals.
- (RACSignal *)flatten:(NSUInteger)maxConcurrent;
/// Ignores all `next`s from the receiver, waits for the receiver to complete,
/// then subscribes to a new signal.
///
/// block - A block which will create or obtain a new signal to subscribe to,
///         executed only after the receiver completes. This block must not be
///         nil, and it must not return a nil signal.
///
/// Returns a signal which will pass through the events of the signal created in
/// `block`. If the receiver errors out, the returned signal will error as well.
- (RACSignal *)then:(RACSignal * (^)(void))block;
/// Concats the inner signals of a signal of signals.
- (RACSignal *)concat;
/// Aggregates the `next` values of the receiver into a single combined value.
///
/// The algorithm proceeds as follows:
///
///  1. `start` is passed into the block as the `running` value, and the first
///     element of the receiver is passed into the block as the `next` value.
///  2. The result of the invocation (`running`) and the next element of the
///     receiver (`next`) is passed into `reduceBlock`.
///  3. Steps 2 and 3 are repeated until all values have been processed.
///  4. The last result of `reduceBlock` is sent on the returned signal.
///
/// This method is similar to -scanWithStart:reduce:, except that only the
/// final result is sent on the returned signal.
///
/// start       - The value to be combined with the first element of the
///               receiver. This value may be `nil`.
/// reduceBlock - The block that describes how to combine values of the
///               receiver. If the receiver is empty, this block will never be
///               invoked. Cannot be nil.
///
/// Returns a signal that will send the aggregated value when the receiver
/// completes, then itself complete. If the receiver never sends any values,
/// `start` will be sent instead.
- (RACSignal *)aggregateWithStart:(id)start reduce:(id (^)(id running, id next))reduceBlock;
/// Aggregates the `next` values of the receiver into a single combined value.
/// This is indexed version of -aggregateWithStart:reduce:.
///
/// start       - The value to be combined with the first element of the
///               receiver. This value may be `nil`.
/// reduceBlock - The block that describes how to combine values of the
///               receiver. This block takes zero-based index value as the last
///               parameter. If the receiver is empty, this block will never be
///               invoked. Cannot be nil.
///
/// Returns a signal that will send the aggregated value when the receiver
/// completes, then itself complete. If the receiver never sends any values,
/// `start` will be sent instead.
- (RACSignal *)aggregateWithStart:(id)start reduceWithIndex:(id (^)(id running, id next, NSUInteger index))reduceBlock;
/// Aggregates the `next` values of the receiver into a single combined value.
///
/// This invokes `startFactory` block on each subscription, then calls
/// -aggregateWithStart:reduce: with the return value of the block as start value.
///
/// startFactory - The block that returns start value which will be combined
///                with the first element of the receiver. Cannot be nil.
/// reduceBlock  - The block that describes how to combine values of the
///                receiver. If the receiver is empty, this block will never be
///                invoked. Cannot be nil.
///
/// Returns a signal that will send the aggregated value when the receiver
/// completes, then itself complete. If the receiver never sends any values,
/// the return value of `startFactory` will be sent instead.
- (RACSignal *)aggregateWithStartFactory:(id (^)(void))startFactory reduce:(id (^)(id running, id next))reduceBlock;
/// Invokes -setKeyPath:onObject:nilValue: with `nil` for the nil value.
///
/// WARNING: Under certain conditions, this method is known to be thread-unsafe.
///          See the description in -setKeyPath:onObject:nilValue:.
- (RACDisposable *)setKeyPath:(NSString *)keyPath onObject:(NSObject *)object;
/// Binds the receiver to an object, automatically setting the given key path on
/// every `next`. When the signal completes, the binding is automatically
/// disposed of.
///
/// WARNING: Under certain conditions, this method is known to be thread-unsafe.
///          A crash can result if `object` is deallocated concurrently on
///          another thread within a window of time between a value being sent
///          on this signal and immediately prior to the invocation of
///          -setValue:forKeyPath:, which sets the property. To prevent this,
///          ensure `object` is deallocated on the same thread the receiver
///          sends on, or ensure that the returned disposable is disposed of
///          before `object` deallocates.
///          See https://github.com/ReactiveCocoa/ReactiveCocoa/pull/1184
///
/// Sending an error on the signal is considered undefined behavior, and will
/// generate an assertion failure in Debug builds.
///
/// A given key on an object should only have one active signal bound to it at any
/// given time. Binding more than one signal to the same property is considered
/// undefined behavior.
///
/// keyPath  - The key path to update with `next`s from the receiver.
/// object   - The object that `keyPath` is relative to.
/// nilValue - The value to set at the key path whenever `nil` is sent by the
///            receiver. This may be nil when binding to object properties, but
///            an NSValue should be used for primitive properties, to avoid an
///            exception if `nil` is sent (which might occur if an intermediate
///            object is set to `nil`).
///
/// Returns a disposable which can be used to terminate the binding.
- (RACDisposable *)setKeyPath:(NSString *)keyPath onObject:(NSObject *)object nilValue:(id)nilValue;
/// Sends NSDate.date every `interval` seconds.
///
/// interval  - The time interval in seconds at which the current time is sent.
/// scheduler - The scheduler upon which the current NSDate should be sent. This
///             must not be nil or +[RACScheduler immediateScheduler].
///
/// Returns a signal that sends the current date/time every `interval` on
/// `scheduler`.
+ (RACSignal *)interval:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler;
/// Sends NSDate.date at intervals of at least `interval` seconds, up to
/// approximately `interval` + `leeway` seconds.
///
/// The created signal will defer sending each `next` for at least `interval`
/// seconds, and for an additional amount of time up to `leeway` seconds in the
/// interest of performance or power consumption. Note that some additional
/// latency is to be expected, even when specifying a `leeway` of 0.
///
/// interval  - The base interval between `next`s.
/// scheduler - The scheduler upon which the current NSDate should be sent. This
///             must not be nil or +[RACScheduler immediateScheduler].
/// leeway    - The maximum amount of additional time the `next` can be deferred.
///
/// Returns a signal that sends the current date/time at intervals of at least
/// `interval seconds` up to approximately `interval` + `leeway` seconds on
/// `scheduler`.
+ (RACSignal *)interval:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler withLeeway:(NSTimeInterval)leeway;
/// Takes `next`s until the `signalTrigger` sends `next` or `completed`.
///
/// Returns a signal which passes through all events from the receiver until
/// `signalTrigger` sends `next` or `completed`, at which point the returned signal
/// will send `completed`.
- (RACSignal *)takeUntil:(RACSignal *)signalTrigger;
/// Takes `next`s until the `replacement` sends an event.
///
/// replacement - The signal which replaces the receiver as soon as it sends an
///               event.
///
/// Returns a signal which passes through `next`s and `error` from the receiver
/// until `replacement` sends an event, at which point the returned signal will
/// send that event and switch to passing through events from `replacement`
/// instead, regardless of whether the receiver has sent events already.
- (RACSignal *)takeUntilReplacement:(RACSignal *)replacement;
/// Subscribes to the returned signal when an error occurs.
- (RACSignal *)catch:(RACSignal * (^)(NSError *error))catchBlock;
/// Subscribes to the given signal when an error occurs.
- (RACSignal *)catchTo:(RACSignal *)signal;
/// Runs `tryBlock` against each of the receiver's values, passing values
/// until `tryBlock` returns NO, or the receiver completes.
///
/// tryBlock - An action to run against each of the receiver's values.
///            The block should return YES to indicate that the action was
///            successful. This block must not be nil.
///
/// Example:
///
///   // The returned signal will send an error if data values cannot be
///   // written to `someFileURL`.
///   [signal try:^(NSData *data, NSError **errorPtr) {
///       return [data writeToURL:someFileURL options:NSDataWritingAtomic error:errorPtr];
///   }];
///
/// Returns a signal which passes through all the values of the receiver. If
/// `tryBlock` fails for any value, the returned signal will error using the
/// `NSError` passed out from the block.
- (RACSignal *)try:(BOOL (^)(id value, NSError **errorPtr))tryBlock;
/// Runs `mapBlock` against each of the receiver's values, mapping values until
/// `mapBlock` returns nil, or the receiver completes.
///
/// mapBlock - An action to map each of the receiver's values. The block should
///            return a non-nil value to indicate that the action was successful.
///            This block must not be nil.
///
/// Example:
///
///   // The returned signal will send an error if data cannot be read from
///   // `fileURL`.
///   [signal tryMap:^(NSURL *fileURL, NSError **errorPtr) {
///       return [NSData dataWithContentsOfURL:fileURL options:0 error:errorPtr];
///   }];
///
/// Returns a signal which transforms all the values of the receiver. If
/// `mapBlock` returns nil for any value, the returned signal will error using
/// the `NSError` passed out from the block.
- (RACSignal *)tryMap:(id (^)(id value, NSError **errorPtr))mapBlock;
/// Returns the first `next`. Note that this is a blocking call.
- (id)first;
/// Returns the first `next` or `defaultValue` if the signal completes or errors
/// without sending a `next`. Note that this is a blocking call.
- (id)firstOrDefault:(id)defaultValue;
/// Returns the first `next` or `defaultValue` if the signal completes or errors
/// without sending a `next`. If an error occurs success will be NO and error
/// will be populated. Note that this is a blocking call.
///
/// Both success and error may be NULL.
- (id)firstOrDefault:(id)defaultValue success:(BOOL *)success error:(NSError **)error;
/// Blocks the caller and waits for the signal to complete.
///
/// error - If not NULL, set to any error that occurs.
///
/// Returns whether the signal completed successfully. If NO, `error` will be set
/// to the error that occurred.
- (BOOL)waitUntilCompleted:(NSError **)error;
/// Defers creation of a signal until the signal's actually subscribed to.
///
/// This can be used to effectively turn a hot signal into a cold signal.
+ (RACSignal *)defer:(RACSignal * (^)(void))block;
/// Every time the receiver sends a new RACSignal, subscribes and sends `next`s and
/// `error`s only for that signal.
///
/// The receiver must be a signal of signals.
///
/// Returns a signal which passes through `next`s and `error`s from the latest
/// signal sent by the receiver, and sends `completed` when both the receiver and
/// the last sent signal complete.
- (RACSignal *)switchToLatest;
/// Switches between the signals in `cases` as well as `defaultSignal` based on
/// the latest value sent by `signal`.
///
/// signal        - A signal of objects used as keys in the `cases` dictionary.
///                 This argument must not be nil.
/// cases         - A dictionary that has signals as values. This argument must
///                 not be nil. A RACTupleNil key in this dictionary will match
///                 nil `next` events that are received on `signal`.
/// defaultSignal - The signal to pass through after `signal` sends a value for
///                 which `cases` does not contain a signal. If nil, any
///                 unmatched values will result in
///                 a RACSignalErrorNoMatchingCase error.
///
/// Returns a signal which passes through `next`s and `error`s from one of the
/// the signals in `cases` or `defaultSignal`, and sends `completed` when both
/// `signal` and the last used signal complete. If no `defaultSignal` is given,
/// an unmatched `next` will result in an error on the returned signal.
+ (RACSignal *)switch:(RACSignal *)signal cases:(NSDictionary *)cases default:(RACSignal *)defaultSignal;
/// Switches between `trueSignal` and `falseSignal` based on the latest value
/// sent by `boolSignal`.
///
/// boolSignal  - A signal of BOOLs determining whether `trueSignal` or
///               `falseSignal` should be active. This argument must not be nil.
/// trueSignal  - The signal to pass through after `boolSignal` has sent YES.
///               This argument must not be nil.
/// falseSignal - The signal to pass through after `boolSignal` has sent NO. This
///               argument must not be nil.
///
/// Returns a signal which passes through `next`s and `error`s from `trueSignal`
/// and/or `falseSignal`, and sends `completed` when both `boolSignal` and the
/// last switched signal complete.
+ (RACSignal *)if:(RACSignal *)boolSignal then:(RACSignal *)trueSignal else:(RACSignal *)falseSignal;
/// Adds every `next` to an array. Nils are represented by NSNulls. Note that
/// this is a blocking call.
///
/// **This is not the same as the `ToArray` method in Rx.** See -collect for
/// that behavior instead.
///
/// Returns the array of `next` values, or nil if an error occurs.
- (NSArray *)toArray;
/// Adds every `next` to a sequence. Nils are represented by NSNulls.
///
/// This corresponds to the `ToEnumerable` method in Rx.
///
/// Returns a sequence which provides values from the signal as they're sent.
/// Trying to retrieve a value from the sequence which has not yet been sent will
/// block.
@property (nonatomic, strong, readonly) RACSequence *sequence;
/// Creates and returns a multicast connection. This allows you to share a single
/// subscription to the underlying signal.
- (RACMulticastConnection *)publish;
/// Creates and returns a multicast connection that pushes values into the given
/// subject. This allows you to share a single subscription to the underlying
/// signal.
- (RACMulticastConnection *)multicast:(RACSubject *)subject;
/// Multicasts the signal to a RACReplaySubject of unlimited capacity, and
/// immediately connects to the resulting RACMulticastConnection.
///
/// Returns the connected, multicasted signal.
- (RACSignal *)replay;
/// Multicasts the signal to a RACReplaySubject of capacity 1, and immediately
/// connects to the resulting RACMulticastConnection.
///
/// Returns the connected, multicasted signal.
- (RACSignal *)replayLast;
/// Multicasts the signal to a RACReplaySubject of unlimited capacity, and
/// lazily connects to the resulting RACMulticastConnection.
///
/// This means the returned signal will subscribe to the multicasted signal only
/// when the former receives its first subscription.
///
/// Returns the lazily connected, multicasted signal.
- (RACSignal *)replayLazily;
/// Sends an error after `interval` seconds if the source doesn't complete
/// before then.
///
/// The error will be in the RACSignalErrorDomain and have a code of
/// RACSignalErrorTimedOut.
///
/// interval  - The number of seconds after which the signal should error out.
/// scheduler - The scheduler upon which any timeout error should be sent. This
///             must not be nil or +[RACScheduler immediateScheduler].
///
/// Returns a signal that passes through the receiver's events, until the stream
/// finishes or times out, at which point an error will be sent on `scheduler`.
- (RACSignal *)timeout:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler;
/// Creates and returns a signal that delivers its events on the given scheduler.
/// Any side effects of the receiver will still be performed on the original
/// thread.
///
/// This is ideal when the signal already performs its work on the desired
/// thread, but you want to handle its events elsewhere.
///
/// This corresponds to the `ObserveOn` method in Rx.
- (RACSignal *)deliverOn:(RACScheduler *)scheduler;
/// Creates and returns a signal that executes its side effects and delivers its
/// events on the given scheduler.
///
/// Use of this operator should be avoided whenever possible, because the
/// receiver's side effects may not be safe to run on another thread. If you just
/// want to receive the signal's events on `scheduler`, use -deliverOn: instead.
- (RACSignal *)subscribeOn:(RACScheduler *)scheduler;
/// Creates and returns a signal that delivers its events on the main thread.
/// If events are already being sent on the main thread, they may be passed on
/// without delay. An event will instead be queued for later delivery on the main
/// thread if sent on another thread, or if a previous event is already being
/// processed, or has been queued.
///
/// Any side effects of the receiver will still be performed on the original
/// thread.
///
/// This can be used when a signal will cause UI updates, to avoid potential
/// flicker caused by delayed delivery of events, such as the first event from
/// a RACObserve at view instantiation.
- (RACSignal *)deliverOnMainThread;
/// Groups each received object into a group, as determined by calling `keyBlock`
/// with that object. The object sent is transformed by calling `transformBlock`
/// with the object. If `transformBlock` is nil, it sends the original object.
///
/// The returned signal is a signal of RACGroupedSignal.
- (RACSignal *)groupBy:(id<NSCopying> (^)(id object))keyBlock transform:(id (^)(id object))transformBlock;
/// Calls -[RACSignal groupBy:keyBlock transform:nil].
- (RACSignal *)groupBy:(id<NSCopying> (^)(id object))keyBlock;
/// Sends an [NSNumber numberWithBool:YES] if the receiving signal sends any
/// objects.
- (RACSignal *)any;
/// Sends an [NSNumber numberWithBool:YES] if the receiving signal sends any
/// objects that pass `predicateBlock`.
///
/// predicateBlock - cannot be nil.
- (RACSignal *)any:(BOOL (^)(id object))predicateBlock;
/// Sends an [NSNumber numberWithBool:YES] if all the objects the receiving
/// signal sends pass `predicateBlock`.
///
/// predicateBlock - cannot be nil.
- (RACSignal *)all:(BOOL (^)(id object))predicateBlock;
/// Resubscribes to the receiving signal if an error occurs, up until it has
/// retried the given number of times.
///
/// retryCount - if 0, it keeps retrying until it completes.
- (RACSignal *)retry:(NSInteger)retryCount;
/// Resubscribes to the receiving signal if an error occurs.
- (RACSignal *)retry;
/// Sends the latest value from the receiver only when `sampler` sends a value.
/// The returned signal could repeat values if `sampler` fires more often than
/// the receiver. Values from `sampler` are ignored before the receiver sends
/// its first value.
///
/// sampler - The signal that controls when the latest value from the receiver
///           is sent. Cannot be nil.
- (RACSignal *)sample:(RACSignal *)sampler;
/// Ignores all `next`s from the receiver.
///
/// Returns a signal which only passes through `error` or `completed` events from
/// the receiver.
- (RACSignal *)ignoreValues;
/// Converts each of the receiver's events into a RACEvent object.
///
/// Returns a signal which sends the receiver's events as RACEvents, and
/// completes after the receiver sends `completed` or `error`.
- (RACSignal *)materialize;
/// Converts each RACEvent in the receiver back into "real" RACSignal events.
///
/// Returns a signal which sends `next` for each value RACEvent, `error` for each
/// error RACEvent, and `completed` for each completed RACEvent.
- (RACSignal *)dematerialize;
/// Inverts each NSNumber-wrapped BOOL sent by the receiver. It will assert if
/// the receiver sends anything other than NSNumbers.
///
/// Returns a signal of inverted NSNumber-wrapped BOOLs.
- (RACSignal *)not;
/// Performs a boolean AND on all of the RACTuple of NSNumbers in sent by the receiver.
///
/// Asserts if the receiver sends anything other than a RACTuple of one or more NSNumbers.
///
/// Returns a signal that applies AND to each NSNumber in the tuple.
- (RACSignal *)and;
/// Performs a boolean OR on all of the RACTuple of NSNumbers in sent by the receiver.
///
/// Asserts if the receiver sends anything other than a RACTuple of one or more NSNumbers.
///
/// Returns a signal that applies OR to each NSNumber in the tuple.
- (RACSignal *)or;
/// Sends the result of calling the block with arguments as packed in each RACTuple
/// sent by the receiver.
///
/// The receiver must send tuple values, where the first element of the tuple is
/// a block, taking a number of parameters equal to the count of the remaining
/// elements of the tuple, and returning an object. Each block must take at least
/// one argument, so each tuple must contain at least 2 elements.
///
/// Example:
///
///   RACSignal *adder = [RACSignal return:^(NSNumber *a, NSNumber *b) {
///       return @(a.intValue + b.intValue);
///   }];
///   RACSignal *sums = [[RACSignal
///       combineLatest:@[ adder, as, bs ]]
///       reduceApply];
///
/// Returns a signal of the result of applying the first element of each tuple
/// to the remaining elements.
- (RACSignal *)reduceApply;
@end
@interface RACSignal (OperationsDeprecated)
- (RACSignal *)windowWithStart:(RACSignal *)openSignal close:(RACSignal * (^)(RACSignal *start))closeBlock __attribute__((deprecated("See https://github.com/ReactiveCocoa/ReactiveCocoa/issues/587")));
- (RACSignal *)buffer:(NSUInteger)bufferCount __attribute__((deprecated("See https://github.com/ReactiveCocoa/ReactiveCocoa/issues/587")));
- (RACSignal *)let:(RACSignal * (^)(RACSignal *sharedSignal))letBlock __attribute__((deprecated("Use -publish instead")));
+ (RACSignal *)interval:(NSTimeInterval)interval __attribute__((deprecated("Use +interval:onScheduler: instead")));
+ (RACSignal *)interval:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway __attribute__((deprecated("Use +interval:onScheduler:withLeeway: instead")));
- (RACSignal *)bufferWithTime:(NSTimeInterval)interval __attribute__((deprecated("Use -bufferWithTime:onScheduler: instead")));
- (RACSignal *)timeout:(NSTimeInterval)interval __attribute__((deprecated("Use -timeout:onScheduler: instead")));
- (RACDisposable *)toProperty:(NSString *)keyPath onObject:(NSObject *)object __attribute__((deprecated("Renamed to -setKeyPath:onObject:")));
- (RACSignal *)ignoreElements __attribute__((deprecated("Renamed to -ignoreValues")));
- (RACSignal *)sequenceNext:(RACSignal * (^)(void))block __attribute__((deprecated("Renamed to -then:")));
- (RACSignal *)aggregateWithStart:(id)start combine:(id (^)(id running, id next))combineBlock __attribute__((deprecated("Renamed to -aggregateWithStart:reduce:")));
- (RACSignal *)aggregateWithStartFactory:(id (^)(void))startFactory combine:(id (^)(id running, id next))combineBlock __attribute__((deprecated("Renamed to -aggregateWithStartFactory:reduce:")));
- (RACDisposable *)executeCommand:(RACCommand *)command __attribute__((deprecated("Use -flattenMap: or -subscribeNext: instead")));
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSignal+Operations.m
New file
@@ -0,0 +1,1482 @@
//
//  RACSignal+Operations.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-09-06.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACSignal+Operations.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACDescription.h"
#import "RACBlockTrampoline.h"
#import "RACCommand.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACEvent.h"
#import "RACGroupedSignal.h"
#import "RACMulticastConnection+Private.h"
#import "RACReplaySubject.h"
#import "RACScheduler.h"
#import "RACSerialDisposable.h"
#import "RACSignalSequence.h"
#import "RACStream+Private.h"
#import "RACSubject.h"
#import "RACSubscriber+Private.h"
#import "RACSubscriber.h"
#import "RACTuple.h"
#import "RACUnit.h"
#import <libkern/OSAtomic.h>
#import <objc/runtime.h>
NSString * const RACSignalErrorDomain = @"RACSignalErrorDomain";
const NSInteger RACSignalErrorTimedOut = 1;
const NSInteger RACSignalErrorNoMatchingCase = 2;
// Subscribes to the given signal with the given blocks.
//
// If the signal errors or completes, the corresponding block is invoked. If the
// disposable passed to the block is _not_ disposed, then the signal is
// subscribed to again.
static RACDisposable *subscribeForever (RACSignal *signal, void (^next)(id), void (^error)(NSError *, RACDisposable *), void (^completed)(RACDisposable *)) {
    next = [next copy];
    error = [error copy];
    completed = [completed copy];
    RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable];
    RACSchedulerRecursiveBlock recursiveBlock = ^(void (^recurse)(void)) {
        RACCompoundDisposable *selfDisposable = [RACCompoundDisposable compoundDisposable];
        [compoundDisposable addDisposable:selfDisposable];
        __weak RACDisposable *weakSelfDisposable = selfDisposable;
        RACDisposable *subscriptionDisposable = [signal subscribeNext:next error:^(NSError *e) {
            @autoreleasepool {
                error(e, compoundDisposable);
                [compoundDisposable removeDisposable:weakSelfDisposable];
            }
            recurse();
        } completed:^{
            @autoreleasepool {
                completed(compoundDisposable);
                [compoundDisposable removeDisposable:weakSelfDisposable];
            }
            recurse();
        }];
        [selfDisposable addDisposable:subscriptionDisposable];
    };
    // Subscribe once immediately, and then use recursive scheduling for any
    // further resubscriptions.
    recursiveBlock(^{
        RACScheduler *recursiveScheduler = RACScheduler.currentScheduler ?: [RACScheduler scheduler];
        RACDisposable *schedulingDisposable = [recursiveScheduler scheduleRecursiveBlock:recursiveBlock];
        [compoundDisposable addDisposable:schedulingDisposable];
    });
    return compoundDisposable;
}
@implementation RACSignal (Operations)
- (RACSignal *)doNext:(void (^)(id x))block {
    NSCParameterAssert(block != NULL);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        return [self subscribeNext:^(id x) {
            block(x);
            [subscriber sendNext:x];
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            [subscriber sendCompleted];
        }];
    }] setNameWithFormat:@"[%@] -doNext:", self.name];
}
- (RACSignal *)doError:(void (^)(NSError *error))block {
    NSCParameterAssert(block != NULL);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        return [self subscribeNext:^(id x) {
            [subscriber sendNext:x];
        } error:^(NSError *error) {
            block(error);
            [subscriber sendError:error];
        } completed:^{
            [subscriber sendCompleted];
        }];
    }] setNameWithFormat:@"[%@] -doError:", self.name];
}
- (RACSignal *)doCompleted:(void (^)(void))block {
    NSCParameterAssert(block != NULL);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        return [self subscribeNext:^(id x) {
            [subscriber sendNext:x];
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            block();
            [subscriber sendCompleted];
        }];
    }] setNameWithFormat:@"[%@] -doCompleted:", self.name];
}
- (RACSignal *)throttle:(NSTimeInterval)interval {
    return [[self throttle:interval valuesPassingTest:^(id _) {
        return YES;
    }] setNameWithFormat:@"[%@] -throttle: %f", self.name, (double)interval];
}
- (RACSignal *)throttle:(NSTimeInterval)interval valuesPassingTest:(BOOL (^)(id next))predicate {
    NSCParameterAssert(interval >= 0);
    NSCParameterAssert(predicate != nil);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable];
        // We may never use this scheduler, but we need to set it up ahead of
        // time so that our scheduled blocks are run serially if we do.
        RACScheduler *scheduler = [RACScheduler scheduler];
        // Information about any currently-buffered `next` event.
        __block id nextValue = nil;
        __block BOOL hasNextValue = NO;
        RACSerialDisposable *nextDisposable = [[RACSerialDisposable alloc] init];
        void (^flushNext)(BOOL send) = ^(BOOL send) {
            @synchronized (compoundDisposable) {
                [nextDisposable.disposable dispose];
                if (!hasNextValue) return;
                if (send) [subscriber sendNext:nextValue];
                nextValue = nil;
                hasNextValue = NO;
            }
        };
        RACDisposable *subscriptionDisposable = [self subscribeNext:^(id x) {
            RACScheduler *delayScheduler = RACScheduler.currentScheduler ?: scheduler;
            BOOL shouldThrottle = predicate(x);
            @synchronized (compoundDisposable) {
                flushNext(NO);
                if (!shouldThrottle) {
                    [subscriber sendNext:x];
                    return;
                }
                nextValue = x;
                hasNextValue = YES;
                nextDisposable.disposable = [delayScheduler afterDelay:interval schedule:^{
                    flushNext(YES);
                }];
            }
        } error:^(NSError *error) {
            [compoundDisposable dispose];
            [subscriber sendError:error];
        } completed:^{
            flushNext(YES);
            [subscriber sendCompleted];
        }];
        [compoundDisposable addDisposable:subscriptionDisposable];
        return compoundDisposable;
    }] setNameWithFormat:@"[%@] -throttle: %f valuesPassingTest:", self.name, (double)interval];
}
- (RACSignal *)delay:(NSTimeInterval)interval {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
        // We may never use this scheduler, but we need to set it up ahead of
        // time so that our scheduled blocks are run serially if we do.
        RACScheduler *scheduler = [RACScheduler scheduler];
        void (^schedule)(dispatch_block_t) = ^(dispatch_block_t block) {
            RACScheduler *delayScheduler = RACScheduler.currentScheduler ?: scheduler;
            RACDisposable *schedulerDisposable = [delayScheduler afterDelay:interval schedule:block];
            [disposable addDisposable:schedulerDisposable];
        };
        RACDisposable *subscriptionDisposable = [self subscribeNext:^(id x) {
            schedule(^{
                [subscriber sendNext:x];
            });
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            schedule(^{
                [subscriber sendCompleted];
            });
        }];
        [disposable addDisposable:subscriptionDisposable];
        return disposable;
    }] setNameWithFormat:@"[%@] -delay: %f", self.name, (double)interval];
}
- (RACSignal *)repeat {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        return subscribeForever(self,
            ^(id x) {
                [subscriber sendNext:x];
            },
            ^(NSError *error, RACDisposable *disposable) {
                [disposable dispose];
                [subscriber sendError:error];
            },
            ^(RACDisposable *disposable) {
                // Resubscribe.
            });
    }] setNameWithFormat:@"[%@] -repeat", self.name];
}
- (RACSignal *)catch:(RACSignal * (^)(NSError *error))catchBlock {
    NSCParameterAssert(catchBlock != NULL);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACSerialDisposable *catchDisposable = [[RACSerialDisposable alloc] init];
        RACDisposable *subscriptionDisposable = [self subscribeNext:^(id x) {
            [subscriber sendNext:x];
        } error:^(NSError *error) {
            RACSignal *signal = catchBlock(error);
            NSCAssert(signal != nil, @"Expected non-nil signal from catch block on %@", self);
            catchDisposable.disposable = [signal subscribe:subscriber];
        } completed:^{
            [subscriber sendCompleted];
        }];
        return [RACDisposable disposableWithBlock:^{
            [catchDisposable dispose];
            [subscriptionDisposable dispose];
        }];
    }] setNameWithFormat:@"[%@] -catch:", self.name];
}
- (RACSignal *)catchTo:(RACSignal *)signal {
    return [[self catch:^(NSError *error) {
        return signal;
    }] setNameWithFormat:@"[%@] -catchTo: %@", self.name, signal];
}
- (RACSignal *)try:(BOOL (^)(id value, NSError **errorPtr))tryBlock {
    NSCParameterAssert(tryBlock != NULL);
    return [[self flattenMap:^(id value) {
        NSError *error = nil;
        BOOL passed = tryBlock(value, &error);
        return (passed ? [RACSignal return:value] : [RACSignal error:error]);
    }] setNameWithFormat:@"[%@] -try:", self.name];
}
- (RACSignal *)tryMap:(id (^)(id value, NSError **errorPtr))mapBlock {
    NSCParameterAssert(mapBlock != NULL);
    return [[self flattenMap:^(id value) {
        NSError *error = nil;
        id mappedValue = mapBlock(value, &error);
        return (mappedValue == nil ? [RACSignal error:error] : [RACSignal return:mappedValue]);
    }] setNameWithFormat:@"[%@] -tryMap:", self.name];
}
- (RACSignal *)initially:(void (^)(void))block {
    NSCParameterAssert(block != NULL);
    return [[RACSignal defer:^{
        block();
        return self;
    }] setNameWithFormat:@"[%@] -initially:", self.name];
}
- (RACSignal *)finally:(void (^)(void))block {
    NSCParameterAssert(block != NULL);
    return [[[self
        doError:^(NSError *error) {
            block();
        }]
        doCompleted:^{
            block();
        }]
        setNameWithFormat:@"[%@] -finally:", self.name];
}
- (RACSignal *)bufferWithTime:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler {
    NSCParameterAssert(scheduler != nil);
    NSCParameterAssert(scheduler != RACScheduler.immediateScheduler);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACSerialDisposable *timerDisposable = [[RACSerialDisposable alloc] init];
        NSMutableArray *values = [NSMutableArray array];
        void (^flushValues)() = ^{
            @synchronized (values) {
                [timerDisposable.disposable dispose];
                if (values.count == 0) return;
                RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:values];
                [values removeAllObjects];
                [subscriber sendNext:tuple];
            }
        };
        RACDisposable *selfDisposable = [self subscribeNext:^(id x) {
            @synchronized (values) {
                if (values.count == 0) {
                    timerDisposable.disposable = [scheduler afterDelay:interval schedule:flushValues];
                }
                [values addObject:x ?: RACTupleNil.tupleNil];
            }
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            flushValues();
            [subscriber sendCompleted];
        }];
        return [RACDisposable disposableWithBlock:^{
            [selfDisposable dispose];
            [timerDisposable dispose];
        }];
    }] setNameWithFormat:@"[%@] -bufferWithTime: %f onScheduler: %@", self.name, (double)interval, scheduler];
}
- (RACSignal *)collect {
    return [[self aggregateWithStartFactory:^{
        return [[NSMutableArray alloc] init];
    } reduce:^(NSMutableArray *collectedValues, id x) {
        [collectedValues addObject:(x ?: NSNull.null)];
        return collectedValues;
    }] setNameWithFormat:@"[%@] -collect", self.name];
}
- (RACSignal *)takeLast:(NSUInteger)count {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        NSMutableArray *valuesTaken = [NSMutableArray arrayWithCapacity:count];
        return [self subscribeNext:^(id x) {
            [valuesTaken addObject:x ? : RACTupleNil.tupleNil];
            while (valuesTaken.count > count) {
                [valuesTaken removeObjectAtIndex:0];
            }
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            for (id value in valuesTaken) {
                [subscriber sendNext:value == RACTupleNil.tupleNil ? nil : value];
            }
            [subscriber sendCompleted];
        }];
    }] setNameWithFormat:@"[%@] -takeLast: %lu", self.name, (unsigned long)count];
}
- (RACSignal *)combineLatestWith:(RACSignal *)signal {
    NSCParameterAssert(signal != nil);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
        __block id lastSelfValue = nil;
        __block BOOL selfCompleted = NO;
        __block id lastOtherValue = nil;
        __block BOOL otherCompleted = NO;
        void (^sendNext)(void) = ^{
            @synchronized (disposable) {
                if (lastSelfValue == nil || lastOtherValue == nil) return;
                [subscriber sendNext:RACTuplePack(lastSelfValue, lastOtherValue)];
            }
        };
        RACDisposable *selfDisposable = [self subscribeNext:^(id x) {
            @synchronized (disposable) {
                lastSelfValue = x ?: RACTupleNil.tupleNil;
                sendNext();
            }
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            @synchronized (disposable) {
                selfCompleted = YES;
                if (otherCompleted) [subscriber sendCompleted];
            }
        }];
        [disposable addDisposable:selfDisposable];
        RACDisposable *otherDisposable = [signal subscribeNext:^(id x) {
            @synchronized (disposable) {
                lastOtherValue = x ?: RACTupleNil.tupleNil;
                sendNext();
            }
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            @synchronized (disposable) {
                otherCompleted = YES;
                if (selfCompleted) [subscriber sendCompleted];
            }
        }];
        [disposable addDisposable:otherDisposable];
        return disposable;
    }] setNameWithFormat:@"[%@] -combineLatestWith: %@", self.name, signal];
}
+ (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals {
    return [[self join:signals block:^(RACSignal *left, RACSignal *right) {
        return [left combineLatestWith:right];
    }] setNameWithFormat:@"+combineLatest: %@", signals];
}
+ (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals reduce:(id (^)())reduceBlock {
    NSCParameterAssert(reduceBlock != nil);
    RACSignal *result = [self combineLatest:signals];
    // Although we assert this condition above, older versions of this method
    // supported this argument being nil. Avoid crashing Release builds of
    // apps that depended on that.
    if (reduceBlock != nil) result = [result reduceEach:reduceBlock];
    return [result setNameWithFormat:@"+combineLatest: %@ reduce:", signals];
}
- (RACSignal *)merge:(RACSignal *)signal {
    return [[RACSignal
        merge:@[ self, signal ]]
        setNameWithFormat:@"[%@] -merge: %@", self.name, signal];
}
+ (RACSignal *)merge:(id<NSFastEnumeration>)signals {
    NSMutableArray *copiedSignals = [[NSMutableArray alloc] init];
    for (RACSignal *signal in signals) {
        [copiedSignals addObject:signal];
    }
    return [[[RACSignal
        createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
            for (RACSignal *signal in copiedSignals) {
                [subscriber sendNext:signal];
            }
            [subscriber sendCompleted];
            return nil;
        }]
        flatten]
        setNameWithFormat:@"+merge: %@", copiedSignals];
}
- (RACSignal *)flatten:(NSUInteger)maxConcurrent {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACCompoundDisposable *compoundDisposable = [[RACCompoundDisposable alloc] init];
        // Contains disposables for the currently active subscriptions.
        //
        // This should only be used while synchronized on `subscriber`.
        NSMutableArray *activeDisposables = [[NSMutableArray alloc] initWithCapacity:maxConcurrent];
        // Whether the signal-of-signals has completed yet.
        //
        // This should only be used while synchronized on `subscriber`.
        __block BOOL selfCompleted = NO;
        // Subscribes to the given signal.
        __block void (^subscribeToSignal)(RACSignal *);
        // Weak reference to the above, to avoid a leak.
        __weak __block void (^recur)(RACSignal *);
        // Sends completed to the subscriber if all signals are finished.
        //
        // This should only be used while synchronized on `subscriber`.
        void (^completeIfAllowed)(void) = ^{
            if (selfCompleted && activeDisposables.count == 0) {
                [subscriber sendCompleted];
                // A strong reference is held to `subscribeToSignal` until completion,
                // preventing it from deallocating early.
                subscribeToSignal = nil;
            }
        };
        // The signals waiting to be started.
        //
        // This array should only be used while synchronized on `subscriber`.
        NSMutableArray *queuedSignals = [NSMutableArray array];
        recur = subscribeToSignal = ^(RACSignal *signal) {
            RACSerialDisposable *serialDisposable = [[RACSerialDisposable alloc] init];
            @synchronized (subscriber) {
                [compoundDisposable addDisposable:serialDisposable];
                [activeDisposables addObject:serialDisposable];
            }
            serialDisposable.disposable = [signal subscribeNext:^(id x) {
                [subscriber sendNext:x];
            } error:^(NSError *error) {
                [subscriber sendError:error];
            } completed:^{
                __strong void (^subscribeToSignal)(RACSignal *) = recur;
                RACSignal *nextSignal;
                @synchronized (subscriber) {
                    [compoundDisposable removeDisposable:serialDisposable];
                    [activeDisposables removeObjectIdenticalTo:serialDisposable];
                    if (queuedSignals.count == 0) {
                        completeIfAllowed();
                        return;
                    }
                    nextSignal = queuedSignals[0];
                    [queuedSignals removeObjectAtIndex:0];
                }
                subscribeToSignal(nextSignal);
            }];
        };
        [compoundDisposable addDisposable:[self subscribeNext:^(RACSignal *signal) {
            if (signal == nil) return;
            NSCAssert([signal isKindOfClass:RACSignal.class], @"Expected a RACSignal, got %@", signal);
            @synchronized (subscriber) {
                if (maxConcurrent > 0 && activeDisposables.count >= maxConcurrent) {
                    [queuedSignals addObject:signal];
                    // If we need to wait, skip subscribing to this
                    // signal.
                    return;
                }
            }
            subscribeToSignal(signal);
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            @synchronized (subscriber) {
                selfCompleted = YES;
                completeIfAllowed();
            }
        }]];
        return compoundDisposable;
    }] setNameWithFormat:@"[%@] -flatten: %lu", self.name, (unsigned long)maxConcurrent];
}
- (RACSignal *)then:(RACSignal * (^)(void))block {
    NSCParameterAssert(block != nil);
    return [[[self
        ignoreValues]
        concat:[RACSignal defer:block]]
        setNameWithFormat:@"[%@] -then:", self.name];
}
- (RACSignal *)concat {
    return [[self flatten:1] setNameWithFormat:@"[%@] -concat", self.name];
}
- (RACSignal *)aggregateWithStartFactory:(id (^)(void))startFactory reduce:(id (^)(id running, id next))reduceBlock {
    NSCParameterAssert(startFactory != NULL);
    NSCParameterAssert(reduceBlock != NULL);
    return [[RACSignal defer:^{
        return [self aggregateWithStart:startFactory() reduce:reduceBlock];
    }] setNameWithFormat:@"[%@] -aggregateWithStartFactory:reduce:", self.name];
}
- (RACSignal *)aggregateWithStart:(id)start reduce:(id (^)(id running, id next))reduceBlock {
    return [[self
        aggregateWithStart:start
        reduceWithIndex:^(id running, id next, NSUInteger index) {
            return reduceBlock(running, next);
        }]
        setNameWithFormat:@"[%@] -aggregateWithStart: %@ reduce:", self.name, [start rac_description]];
}
- (RACSignal *)aggregateWithStart:(id)start reduceWithIndex:(id (^)(id, id, NSUInteger))reduceBlock {
    return [[[[self
        scanWithStart:start reduceWithIndex:reduceBlock]
        startWith:start]
        takeLast:1]
        setNameWithFormat:@"[%@] -aggregateWithStart: %@ reduceWithIndex:", self.name, [start rac_description]];
}
- (RACDisposable *)setKeyPath:(NSString *)keyPath onObject:(NSObject *)object {
    return [self setKeyPath:keyPath onObject:object nilValue:nil];
}
- (RACDisposable *)setKeyPath:(NSString *)keyPath onObject:(NSObject *)object nilValue:(id)nilValue {
    NSCParameterAssert(keyPath != nil);
    NSCParameterAssert(object != nil);
    keyPath = [keyPath copy];
    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    // Purposely not retaining 'object', since we want to tear down the binding
    // when it deallocates normally.
    __block void * volatile objectPtr = (__bridge void *)object;
    RACDisposable *subscriptionDisposable = [self subscribeNext:^(id x) {
        // Possibly spec, possibly compiler bug, but this __bridge cast does not
        // result in a retain here, effectively an invisible __unsafe_unretained
        // qualifier. Using objc_precise_lifetime gives the __strong reference
        // desired. The explicit use of __strong is strictly defensive.
        __strong NSObject *object __attribute__((objc_precise_lifetime)) = (__bridge __strong id)objectPtr;
        [object setValue:x ?: nilValue forKeyPath:keyPath];
    } error:^(NSError *error) {
        __strong NSObject *object __attribute__((objc_precise_lifetime)) = (__bridge __strong id)objectPtr;
        NSCAssert(NO, @"Received error from %@ in binding for key path \"%@\" on %@: %@", self, keyPath, object, error);
        // Log the error if we're running with assertions disabled.
        NSLog(@"Received error from %@ in binding for key path \"%@\" on %@: %@", self, keyPath, object, error);
        [disposable dispose];
    } completed:^{
        [disposable dispose];
    }];
    [disposable addDisposable:subscriptionDisposable];
    #if DEBUG
    static void *bindingsKey = &bindingsKey;
    NSMutableDictionary *bindings;
    @synchronized (object) {
        bindings = objc_getAssociatedObject(object, bindingsKey);
        if (bindings == nil) {
            bindings = [NSMutableDictionary dictionary];
            objc_setAssociatedObject(object, bindingsKey, bindings, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        }
    }
    @synchronized (bindings) {
        NSCAssert(bindings[keyPath] == nil, @"Signal %@ is already bound to key path \"%@\" on object %@, adding signal %@ is undefined behavior", [bindings[keyPath] nonretainedObjectValue], keyPath, object, self);
        bindings[keyPath] = [NSValue valueWithNonretainedObject:self];
    }
    #endif
    RACDisposable *clearPointerDisposable = [RACDisposable disposableWithBlock:^{
        #if DEBUG
        @synchronized (bindings) {
            [bindings removeObjectForKey:keyPath];
        }
        #endif
        while (YES) {
            void *ptr = objectPtr;
            if (OSAtomicCompareAndSwapPtrBarrier(ptr, NULL, &objectPtr)) {
                break;
            }
        }
    }];
    [disposable addDisposable:clearPointerDisposable];
    [object.rac_deallocDisposable addDisposable:disposable];
    RACCompoundDisposable *objectDisposable = object.rac_deallocDisposable;
    return [RACDisposable disposableWithBlock:^{
        [objectDisposable removeDisposable:disposable];
        [disposable dispose];
    }];
}
+ (RACSignal *)interval:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler {
    return [[RACSignal interval:interval onScheduler:scheduler withLeeway:0.0] setNameWithFormat:@"+interval: %f onScheduler: %@", (double)interval, scheduler];
}
+ (RACSignal *)interval:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler withLeeway:(NSTimeInterval)leeway {
    NSCParameterAssert(scheduler != nil);
    NSCParameterAssert(scheduler != RACScheduler.immediateScheduler);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        return [scheduler after:[NSDate dateWithTimeIntervalSinceNow:interval] repeatingEvery:interval withLeeway:leeway schedule:^{
            [subscriber sendNext:[NSDate date]];
        }];
    }] setNameWithFormat:@"+interval: %f onScheduler: %@ withLeeway: %f", (double)interval, scheduler, (double)leeway];
}
- (RACSignal *)takeUntil:(RACSignal *)signalTrigger {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
        void (^triggerCompletion)(void) = ^{
            [disposable dispose];
            [subscriber sendCompleted];
        };
        RACDisposable *triggerDisposable = [signalTrigger subscribeNext:^(id _) {
            triggerCompletion();
        } completed:^{
            triggerCompletion();
        }];
        [disposable addDisposable:triggerDisposable];
        if (!disposable.disposed) {
            RACDisposable *selfDisposable = [self subscribeNext:^(id x) {
                [subscriber sendNext:x];
            } error:^(NSError *error) {
                [subscriber sendError:error];
            } completed:^{
                [disposable dispose];
                [subscriber sendCompleted];
            }];
            [disposable addDisposable:selfDisposable];
        }
        return disposable;
    }] setNameWithFormat:@"[%@] -takeUntil: %@", self.name, signalTrigger];
}
- (RACSignal *)takeUntilReplacement:(RACSignal *)replacement {
    return [RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACSerialDisposable *selfDisposable = [[RACSerialDisposable alloc] init];
        RACDisposable *replacementDisposable = [replacement subscribeNext:^(id x) {
            [selfDisposable dispose];
            [subscriber sendNext:x];
        } error:^(NSError *error) {
            [selfDisposable dispose];
            [subscriber sendError:error];
        } completed:^{
            [selfDisposable dispose];
            [subscriber sendCompleted];
        }];
        if (!selfDisposable.disposed) {
            selfDisposable.disposable = [[self
                concat:[RACSignal never]]
                subscribe:subscriber];
        }
        return [RACDisposable disposableWithBlock:^{
            [selfDisposable dispose];
            [replacementDisposable dispose];
        }];
    }];
}
- (RACSignal *)switchToLatest {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACMulticastConnection *connection = [self publish];
        RACDisposable *subscriptionDisposable = [[connection.signal
            flattenMap:^(RACSignal *x) {
                NSCAssert(x == nil || [x isKindOfClass:RACSignal.class], @"-switchToLatest requires that the source signal (%@) send signals. Instead we got: %@", self, x);
                // -concat:[RACSignal never] prevents completion of the receiver from
                // prematurely terminating the inner signal.
                return [x takeUntil:[connection.signal concat:[RACSignal never]]];
            }]
            subscribe:subscriber];
        RACDisposable *connectionDisposable = [connection connect];
        return [RACDisposable disposableWithBlock:^{
            [subscriptionDisposable dispose];
            [connectionDisposable dispose];
        }];
    }] setNameWithFormat:@"[%@] -switchToLatest", self.name];
}
+ (RACSignal *)switch:(RACSignal *)signal cases:(NSDictionary *)cases default:(RACSignal *)defaultSignal {
    NSCParameterAssert(signal != nil);
    NSCParameterAssert(cases != nil);
    for (id key in cases) {
        id value __attribute__((unused)) = cases[key];
        NSCAssert([value isKindOfClass:RACSignal.class], @"Expected all cases to be RACSignals, %@ isn't", value);
    }
    NSDictionary *copy = [cases copy];
    return [[[signal
        map:^(id key) {
            if (key == nil) key = RACTupleNil.tupleNil;
            RACSignal *signal = copy[key] ?: defaultSignal;
            if (signal == nil) {
                NSString *description = [NSString stringWithFormat:NSLocalizedString(@"No matching signal found for value %@", @""), key];
                return [RACSignal error:[NSError errorWithDomain:RACSignalErrorDomain code:RACSignalErrorNoMatchingCase userInfo:@{ NSLocalizedDescriptionKey: description }]];
            }
            return signal;
        }]
        switchToLatest]
        setNameWithFormat:@"+switch: %@ cases: %@ default: %@", signal, cases, defaultSignal];
}
+ (RACSignal *)if:(RACSignal *)boolSignal then:(RACSignal *)trueSignal else:(RACSignal *)falseSignal {
    NSCParameterAssert(boolSignal != nil);
    NSCParameterAssert(trueSignal != nil);
    NSCParameterAssert(falseSignal != nil);
    return [[[boolSignal
        map:^(NSNumber *value) {
            NSCAssert([value isKindOfClass:NSNumber.class], @"Expected %@ to send BOOLs, not %@", boolSignal, value);
            return (value.boolValue ? trueSignal : falseSignal);
        }]
        switchToLatest]
        setNameWithFormat:@"+if: %@ then: %@ else: %@", boolSignal, trueSignal, falseSignal];
}
- (id)first {
    return [self firstOrDefault:nil];
}
- (id)firstOrDefault:(id)defaultValue {
    return [self firstOrDefault:defaultValue success:NULL error:NULL];
}
- (id)firstOrDefault:(id)defaultValue success:(BOOL *)success error:(NSError **)error {
    NSCondition *condition = [[NSCondition alloc] init];
    condition.name = [NSString stringWithFormat:@"[%@] -firstOrDefault: %@ success:error:", self.name, defaultValue];
    __block id value = defaultValue;
    __block BOOL done = NO;
    // Ensures that we don't pass values across thread boundaries by reference.
    __block NSError *localError;
    __block BOOL localSuccess;
    [[self take:1] subscribeNext:^(id x) {
        [condition lock];
        value = x;
        localSuccess = YES;
        done = YES;
        [condition broadcast];
        [condition unlock];
    } error:^(NSError *e) {
        [condition lock];
        if (!done) {
            localSuccess = NO;
            localError = e;
            done = YES;
            [condition broadcast];
        }
        [condition unlock];
    } completed:^{
        [condition lock];
        localSuccess = YES;
        done = YES;
        [condition broadcast];
        [condition unlock];
    }];
    [condition lock];
    while (!done) {
        [condition wait];
    }
    if (success != NULL) *success = localSuccess;
    if (error != NULL) *error = localError;
    [condition unlock];
    return value;
}
- (BOOL)waitUntilCompleted:(NSError **)error {
    BOOL success = NO;
    [[[self
        ignoreValues]
        setNameWithFormat:@"[%@] -waitUntilCompleted:", self.name]
        firstOrDefault:nil success:&success error:error];
    return success;
}
+ (RACSignal *)defer:(RACSignal * (^)(void))block {
    NSCParameterAssert(block != NULL);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        return [block() subscribe:subscriber];
    }] setNameWithFormat:@"+defer:"];
}
- (NSArray *)toArray {
    return [[[self collect] first] copy];
}
- (RACSequence *)sequence {
    return [[RACSignalSequence sequenceWithSignal:self] setNameWithFormat:@"[%@] -sequence", self.name];
}
- (RACMulticastConnection *)publish {
    RACSubject *subject = [[RACSubject subject] setNameWithFormat:@"[%@] -publish", self.name];
    RACMulticastConnection *connection = [self multicast:subject];
    return connection;
}
- (RACMulticastConnection *)multicast:(RACSubject *)subject {
    [subject setNameWithFormat:@"[%@] -multicast: %@", self.name, subject.name];
    RACMulticastConnection *connection = [[RACMulticastConnection alloc] initWithSourceSignal:self subject:subject];
    return connection;
}
- (RACSignal *)replay {
    RACReplaySubject *subject = [[RACReplaySubject subject] setNameWithFormat:@"[%@] -replay", self.name];
    RACMulticastConnection *connection = [self multicast:subject];
    [connection connect];
    return connection.signal;
}
- (RACSignal *)replayLast {
    RACReplaySubject *subject = [[RACReplaySubject replaySubjectWithCapacity:1] setNameWithFormat:@"[%@] -replayLast", self.name];
    RACMulticastConnection *connection = [self multicast:subject];
    [connection connect];
    return connection.signal;
}
- (RACSignal *)replayLazily {
    RACMulticastConnection *connection = [self multicast:[RACReplaySubject subject]];
    return [[RACSignal
        defer:^{
            [connection connect];
            return connection.signal;
        }]
        setNameWithFormat:@"[%@] -replayLazily", self.name];
}
- (RACSignal *)timeout:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler {
    NSCParameterAssert(scheduler != nil);
    NSCParameterAssert(scheduler != RACScheduler.immediateScheduler);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
        RACDisposable *timeoutDisposable = [scheduler afterDelay:interval schedule:^{
            [disposable dispose];
            [subscriber sendError:[NSError errorWithDomain:RACSignalErrorDomain code:RACSignalErrorTimedOut userInfo:nil]];
        }];
        [disposable addDisposable:timeoutDisposable];
        RACDisposable *subscriptionDisposable = [self subscribeNext:^(id x) {
            [subscriber sendNext:x];
        } error:^(NSError *error) {
            [disposable dispose];
            [subscriber sendError:error];
        } completed:^{
            [disposable dispose];
            [subscriber sendCompleted];
        }];
        [disposable addDisposable:subscriptionDisposable];
        return disposable;
    }] setNameWithFormat:@"[%@] -timeout: %f onScheduler: %@", self.name, (double)interval, scheduler];
}
- (RACSignal *)deliverOn:(RACScheduler *)scheduler {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        return [self subscribeNext:^(id x) {
            [scheduler schedule:^{
                [subscriber sendNext:x];
            }];
        } error:^(NSError *error) {
            [scheduler schedule:^{
                [subscriber sendError:error];
            }];
        } completed:^{
            [scheduler schedule:^{
                [subscriber sendCompleted];
            }];
        }];
    }] setNameWithFormat:@"[%@] -deliverOn: %@", self.name, scheduler];
}
- (RACSignal *)subscribeOn:(RACScheduler *)scheduler {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
        RACDisposable *schedulingDisposable = [scheduler schedule:^{
            RACDisposable *subscriptionDisposable = [self subscribe:subscriber];
            [disposable addDisposable:subscriptionDisposable];
        }];
        [disposable addDisposable:schedulingDisposable];
        return disposable;
    }] setNameWithFormat:@"[%@] -subscribeOn: %@", self.name, scheduler];
}
- (RACSignal *)deliverOnMainThread {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        __block volatile int32_t queueLength = 0;
        void (^performOnMainThread)(dispatch_block_t) = ^(dispatch_block_t block) {
            int32_t queued = OSAtomicIncrement32(&queueLength);
            if (NSThread.isMainThread && queued == 1) {
                block();
                OSAtomicDecrement32(&queueLength);
            } else {
                dispatch_async(dispatch_get_main_queue(), ^{
                    block();
                    OSAtomicDecrement32(&queueLength);
                });
            }
        };
        return [self subscribeNext:^(id x) {
            performOnMainThread(^{
                [subscriber sendNext:x];
            });
        } error:^(NSError *error) {
            performOnMainThread(^{
                [subscriber sendError:error];
            });
        } completed:^{
            performOnMainThread(^{
                [subscriber sendCompleted];
            });
        }];
    }] setNameWithFormat:@"[%@] -deliverOnMainThread", self.name];
}
- (RACSignal *)groupBy:(id<NSCopying> (^)(id object))keyBlock transform:(id (^)(id object))transformBlock {
    NSCParameterAssert(keyBlock != NULL);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        NSMutableDictionary *groups = [NSMutableDictionary dictionary];
        NSMutableArray *orderedGroups = [NSMutableArray array];
        return [self subscribeNext:^(id x) {
            id<NSCopying> key = keyBlock(x);
            RACGroupedSignal *groupSubject = nil;
            @synchronized(groups) {
                groupSubject = groups[key];
                if (groupSubject == nil) {
                    groupSubject = [RACGroupedSignal signalWithKey:key];
                    groups[key] = groupSubject;
                    [orderedGroups addObject:groupSubject];
                    [subscriber sendNext:groupSubject];
                }
            }
            [groupSubject sendNext:transformBlock != NULL ? transformBlock(x) : x];
        } error:^(NSError *error) {
            [subscriber sendError:error];
            [orderedGroups makeObjectsPerformSelector:@selector(sendError:) withObject:error];
        } completed:^{
            [subscriber sendCompleted];
            [orderedGroups makeObjectsPerformSelector:@selector(sendCompleted)];
        }];
    }] setNameWithFormat:@"[%@] -groupBy:transform:", self.name];
}
- (RACSignal *)groupBy:(id<NSCopying> (^)(id object))keyBlock {
    return [[self groupBy:keyBlock transform:nil] setNameWithFormat:@"[%@] -groupBy:", self.name];
}
- (RACSignal *)any {
    return [[self any:^(id x) {
        return YES;
    }] setNameWithFormat:@"[%@] -any", self.name];
}
- (RACSignal *)any:(BOOL (^)(id object))predicateBlock {
    NSCParameterAssert(predicateBlock != NULL);
    return [[[self materialize] bind:^{
        return ^(RACEvent *event, BOOL *stop) {
            if (event.finished) {
                *stop = YES;
                return [RACSignal return:@NO];
            }
            if (predicateBlock(event.value)) {
                *stop = YES;
                return [RACSignal return:@YES];
            }
            return [RACSignal empty];
        };
    }] setNameWithFormat:@"[%@] -any:", self.name];
}
- (RACSignal *)all:(BOOL (^)(id object))predicateBlock {
    NSCParameterAssert(predicateBlock != NULL);
    return [[[self materialize] bind:^{
        return ^(RACEvent *event, BOOL *stop) {
            if (event.eventType == RACEventTypeCompleted) {
                *stop = YES;
                return [RACSignal return:@YES];
            }
            if (event.eventType == RACEventTypeError || !predicateBlock(event.value)) {
                *stop = YES;
                return [RACSignal return:@NO];
            }
            return [RACSignal empty];
        };
    }] setNameWithFormat:@"[%@] -all:", self.name];
}
- (RACSignal *)retry:(NSInteger)retryCount {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        __block NSInteger currentRetryCount = 0;
        return subscribeForever(self,
            ^(id x) {
                [subscriber sendNext:x];
            },
            ^(NSError *error, RACDisposable *disposable) {
                if (retryCount == 0 || currentRetryCount < retryCount) {
                    // Resubscribe.
                    currentRetryCount++;
                    return;
                }
                [disposable dispose];
                [subscriber sendError:error];
            },
            ^(RACDisposable *disposable) {
                [disposable dispose];
                [subscriber sendCompleted];
            });
    }] setNameWithFormat:@"[%@] -retry: %lu", self.name, (unsigned long)retryCount];
}
- (RACSignal *)retry {
    return [[self retry:0] setNameWithFormat:@"[%@] -retry", self.name];
}
- (RACSignal *)sample:(RACSignal *)sampler {
    NSCParameterAssert(sampler != nil);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        NSLock *lock = [[NSLock alloc] init];
        __block id lastValue;
        __block BOOL hasValue = NO;
        RACSerialDisposable *samplerDisposable = [[RACSerialDisposable alloc] init];
        RACDisposable *sourceDisposable = [self subscribeNext:^(id x) {
            [lock lock];
            hasValue = YES;
            lastValue = x;
            [lock unlock];
        } error:^(NSError *error) {
            [samplerDisposable dispose];
            [subscriber sendError:error];
        } completed:^{
            [samplerDisposable dispose];
            [subscriber sendCompleted];
        }];
        samplerDisposable.disposable = [sampler subscribeNext:^(id _) {
            BOOL shouldSend = NO;
            id value;
            [lock lock];
            shouldSend = hasValue;
            value = lastValue;
            [lock unlock];
            if (shouldSend) {
                [subscriber sendNext:value];
            }
        } error:^(NSError *error) {
            [sourceDisposable dispose];
            [subscriber sendError:error];
        } completed:^{
            [sourceDisposable dispose];
            [subscriber sendCompleted];
        }];
        return [RACDisposable disposableWithBlock:^{
            [samplerDisposable dispose];
            [sourceDisposable dispose];
        }];
    }] setNameWithFormat:@"[%@] -sample: %@", self.name, sampler];
}
- (RACSignal *)ignoreValues {
    return [[self filter:^(id _) {
        return NO;
    }] setNameWithFormat:@"[%@] -ignoreValues", self.name];
}
- (RACSignal *)materialize {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        return [self subscribeNext:^(id x) {
            [subscriber sendNext:[RACEvent eventWithValue:x]];
        } error:^(NSError *error) {
            [subscriber sendNext:[RACEvent eventWithError:error]];
            [subscriber sendCompleted];
        } completed:^{
            [subscriber sendNext:RACEvent.completedEvent];
            [subscriber sendCompleted];
        }];
    }] setNameWithFormat:@"[%@] -materialize", self.name];
}
- (RACSignal *)dematerialize {
    return [[self bind:^{
        return ^(RACEvent *event, BOOL *stop) {
            switch (event.eventType) {
                case RACEventTypeCompleted:
                    *stop = YES;
                    return [RACSignal empty];
                case RACEventTypeError:
                    *stop = YES;
                    return [RACSignal error:event.error];
                case RACEventTypeNext:
                    return [RACSignal return:event.value];
            }
        };
    }] setNameWithFormat:@"[%@] -dematerialize", self.name];
}
- (RACSignal *)not {
    return [[self map:^(NSNumber *value) {
        NSCAssert([value isKindOfClass:NSNumber.class], @"-not must only be used on a signal of NSNumbers. Instead, got: %@", value);
        return @(!value.boolValue);
    }] setNameWithFormat:@"[%@] -not", self.name];
}
- (RACSignal *)and {
    return [[self map:^(RACTuple *tuple) {
        NSCAssert([tuple isKindOfClass:RACTuple.class], @"-and must only be used on a signal of RACTuples of NSNumbers. Instead, received: %@", tuple);
        NSCAssert(tuple.count > 0, @"-and must only be used on a signal of RACTuples of NSNumbers, with at least 1 value in the tuple");
        return @([tuple.rac_sequence all:^(NSNumber *number) {
            NSCAssert([number isKindOfClass:NSNumber.class], @"-and must only be used on a signal of RACTuples of NSNumbers. Instead, tuple contains a non-NSNumber value: %@", tuple);
            return number.boolValue;
        }]);
    }] setNameWithFormat:@"[%@] -and", self.name];
}
- (RACSignal *)or {
    return [[self map:^(RACTuple *tuple) {
        NSCAssert([tuple isKindOfClass:RACTuple.class], @"-or must only be used on a signal of RACTuples of NSNumbers. Instead, received: %@", tuple);
        NSCAssert(tuple.count > 0, @"-or must only be used on a signal of RACTuples of NSNumbers, with at least 1 value in the tuple");
        return @([tuple.rac_sequence any:^(NSNumber *number) {
            NSCAssert([number isKindOfClass:NSNumber.class], @"-or must only be used on a signal of RACTuples of NSNumbers. Instead, tuple contains a non-NSNumber value: %@", tuple);
            return number.boolValue;
        }]);
    }] setNameWithFormat:@"[%@] -or", self.name];
}
- (RACSignal *)reduceApply {
    return [[self map:^(RACTuple *tuple) {
        NSCAssert([tuple isKindOfClass:RACTuple.class], @"-reduceApply must only be used on a signal of RACTuples. Instead, received: %@", tuple);
        NSCAssert(tuple.count > 1, @"-reduceApply must only be used on a signal of RACTuples, with at least a block in tuple[0] and its first argument in tuple[1]");
        // We can't use -array, because we need to preserve RACTupleNil
        NSMutableArray *tupleArray = [NSMutableArray arrayWithCapacity:tuple.count];
        for (id val in tuple) {
            [tupleArray addObject:val];
        }
        RACTuple *arguments = [RACTuple tupleWithObjectsFromArray:[tupleArray subarrayWithRange:NSMakeRange(1, tupleArray.count - 1)]];
        return [RACBlockTrampoline invokeBlock:tuple[0] withArguments:arguments];
    }] setNameWithFormat:@"[%@] -reduceApply", self.name];
}
@end
@implementation RACSignal (OperationsDeprecated)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
- (RACSignal *)windowWithStart:(RACSignal *)openSignal close:(RACSignal * (^)(RACSignal *start))closeBlock {
    NSCParameterAssert(openSignal != nil);
    NSCParameterAssert(closeBlock != NULL);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        __block RACSubject *currentWindow = nil;
        __block RACSignal *currentCloseWindow = nil;
        __block RACDisposable *closeObserverDisposable = NULL;
        void (^closeCurrentWindow)(void) = ^{
            [currentWindow sendCompleted];
            currentWindow = nil;
            currentCloseWindow = nil;
            [closeObserverDisposable dispose], closeObserverDisposable = nil;
        };
        RACDisposable *openObserverDisposable = [openSignal subscribe:[RACSubscriber subscriberWithNext:^(id x) {
            if(currentWindow == nil) {
                currentWindow = [RACSubject subject];
                [subscriber sendNext:currentWindow];
                currentCloseWindow = closeBlock(currentWindow);
                closeObserverDisposable = [currentCloseWindow subscribe:[RACSubscriber subscriberWithNext:^(id x) {
                    closeCurrentWindow();
                } error:^(NSError *error) {
                    closeCurrentWindow();
                } completed:^{
                    closeCurrentWindow();
                }]];
            }
        } error:^(NSError *error) {
        } completed:^{
        }]];
        RACDisposable *selfObserverDisposable = [self subscribeNext:^(id x) {
            [currentWindow sendNext:x];
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            [subscriber sendCompleted];
        }];
        return [RACDisposable disposableWithBlock:^{
            [closeObserverDisposable dispose];
            [openObserverDisposable dispose];
            [selfObserverDisposable dispose];
        }];
    }] setNameWithFormat:@"[%@] -windowWithStart: %@ close:", self.name, openSignal];
}
- (RACSignal *)buffer:(NSUInteger)bufferCount {
    NSCParameterAssert(bufferCount > 0);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        NSMutableArray *values = [NSMutableArray arrayWithCapacity:bufferCount];
        RACSubject *windowCloseSubject = [RACSubject subject];
        RACDisposable *closeDisposable = [windowCloseSubject subscribeNext:^(id x) {
            [subscriber sendNext:[RACTuple tupleWithObjectsFromArray:values]];
            [values removeAllObjects];
        }];
        __block RACDisposable *innerDisposable = nil;
        RACDisposable *outerDisposable = [[self windowWithStart:self close:^(RACSignal *start) {
            return windowCloseSubject;
        }] subscribeNext:^(id x) {
            innerDisposable = [x subscribeNext:^(id x) {
                [values addObject:x ? : [RACTupleNil tupleNil]];
                if(values.count % bufferCount == 0) {
                    [windowCloseSubject sendNext:[RACUnit defaultUnit]];
                }
            }];
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            [subscriber sendCompleted];
        }];
        return [RACDisposable disposableWithBlock:^{
            [innerDisposable dispose];
            [outerDisposable dispose];
            [closeDisposable dispose];
        }];
    }] setNameWithFormat:@"[%@] -buffer: %lu", self.name, (unsigned long)bufferCount];
}
- (RACSignal *)let:(RACSignal * (^)(RACSignal *sharedSignal))letBlock {
    NSCParameterAssert(letBlock != NULL);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACMulticastConnection *connection = [self publish];
        RACDisposable *finalDisposable = [letBlock(connection.signal) subscribeNext:^(id x) {
            [subscriber sendNext:x];
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            [subscriber sendCompleted];
        }];
        RACDisposable *connectionDisposable = [connection connect];
        return [RACDisposable disposableWithBlock:^{
            [connectionDisposable dispose];
            [finalDisposable dispose];
        }];
    }] setNameWithFormat:@"[%@] -let:", self.name];
}
+ (RACSignal *)interval:(NSTimeInterval)interval {
    return [RACSignal interval:interval onScheduler:[RACScheduler schedulerWithPriority:RACSchedulerPriorityHigh]];
}
+ (RACSignal *)interval:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway {
    return [RACSignal interval:interval onScheduler:[RACScheduler schedulerWithPriority:RACSchedulerPriorityHigh] withLeeway:leeway];
}
- (RACSignal *)timeout:(NSTimeInterval)interval {
    return [self timeout:interval onScheduler:[RACScheduler schedulerWithPriority:RACSchedulerPriorityHigh]];
}
- (RACSignal *)bufferWithTime:(NSTimeInterval)interval {
    return [self bufferWithTime:interval onScheduler:[RACScheduler schedulerWithPriority:RACSchedulerPriorityHigh]];
}
- (RACDisposable *)toProperty:(NSString *)keyPath onObject:(NSObject *)object {
    return [self setKeyPath:keyPath onObject:object];
}
- (RACSignal *)ignoreElements {
    return [self ignoreValues];
}
- (RACSignal *)sequenceNext:(RACSignal * (^)(void))block {
    return [self then:block];
}
- (RACSignal *)aggregateWithStart:(id)start combine:(id (^)(id running, id next))combineBlock {
    return [self aggregateWithStart:start reduce:combineBlock];
}
- (RACSignal *)aggregateWithStartFactory:(id (^)(void))startFactory combine:(id (^)(id running, id next))combineBlock {
    return [self aggregateWithStartFactory:startFactory reduce:combineBlock];
}
- (RACDisposable *)executeCommand:(RACCommand *)command {
    NSCParameterAssert(command != nil);
    return [self subscribeNext:^(id x) {
        [command execute:x];
    }];
}
#pragma clang diagnostic pop
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSignal.h
New file
@@ -0,0 +1,219 @@
//
//  RACSignal.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/1/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RACStream.h"
@class RACDisposable;
@class RACScheduler;
@class RACSubject;
@protocol RACSubscriber;
@interface RACSignal : RACStream
/// Creates a new signal. This is the preferred way to create a new signal
/// operation or behavior.
///
/// Events can be sent to new subscribers immediately in the `didSubscribe`
/// block, but the subscriber will not be able to dispose of the signal until
/// a RACDisposable is returned from `didSubscribe`. In the case of infinite
/// signals, this won't _ever_ happen if events are sent immediately.
///
/// To ensure that the signal is disposable, events can be scheduled on the
/// +[RACScheduler currentScheduler] (so that they're deferred, not sent
/// immediately), or they can be sent in the background. The RACDisposable
/// returned by the `didSubscribe` block should cancel any such scheduling or
/// asynchronous work.
///
/// didSubscribe - Called when the signal is subscribed to. The new subscriber is
///                passed in. You can then manually control the <RACSubscriber> by
///                sending it -sendNext:, -sendError:, and -sendCompleted,
///                as defined by the operation you're implementing. This block
///                should return a RACDisposable which cancels any ongoing work
///                triggered by the subscription, and cleans up any resources or
///                disposables created as part of it. When the disposable is
///                disposed of, the signal must not send any more events to the
///                `subscriber`. If no cleanup is necessary, return nil.
///
/// **Note:** The `didSubscribe` block is called every time a new subscriber
/// subscribes. Any side effects within the block will thus execute once for each
/// subscription, not necessarily on one thread, and possibly even
/// simultaneously!
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe;
/// Returns a signal that immediately sends the given error.
+ (RACSignal *)error:(NSError *)error;
/// Returns a signal that never completes.
+ (RACSignal *)never;
/// Immediately schedules the given block on the given scheduler. The block is
/// given a subscriber to which it can send events.
///
/// scheduler - The scheduler on which `block` will be scheduled and results
///             delivered. Cannot be nil.
/// block     - The block to invoke. Cannot be NULL.
///
/// Returns a signal which will send all events sent on the subscriber given to
/// `block`. All events will be sent on `scheduler` and it will replay any missed
/// events to new subscribers.
+ (RACSignal *)startEagerlyWithScheduler:(RACScheduler *)scheduler block:(void (^)(id<RACSubscriber> subscriber))block;
/// Invokes the given block only on the first subscription. The block is given a
/// subscriber to which it can send events.
///
/// Note that disposing of the subscription to the returned signal will *not*
/// dispose of the underlying subscription. If you need that behavior, see
/// -[RACMulticastConnection autoconnect]. The underlying subscription will never
/// be disposed of. Because of this, `block` should never return an infinite
/// signal since there would be no way of ending it.
///
/// scheduler - The scheduler on which the block should be scheduled. Note that
///             if given +[RACScheduler immediateScheduler], the block will be
///             invoked synchronously on the first subscription. Cannot be nil.
/// block     - The block to invoke on the first subscription. Cannot be NULL.
///
/// Returns a signal which will pass through the events sent to the subscriber
/// given to `block` and replay any missed events to new subscribers.
+ (RACSignal *)startLazilyWithScheduler:(RACScheduler *)scheduler block:(void (^)(id<RACSubscriber> subscriber))block;
@end
@interface RACSignal (RACStream)
/// Returns a signal that immediately sends the given value and then completes.
+ (RACSignal *)return:(id)value;
/// Returns a signal that immediately completes.
+ (RACSignal *)empty;
/// Subscribes to `signal` when the source signal completes.
- (RACSignal *)concat:(RACSignal *)signal;
/// Zips the values in the receiver with those of the given signal to create
/// RACTuples.
///
/// The first `next` of each stream will be combined, then the second `next`, and
/// so forth, until either signal completes or errors.
///
/// signal - The signal to zip with. This must not be `nil`.
///
/// Returns a new signal of RACTuples, representing the combined values of the
/// two signals. Any error from one of the original signals will be forwarded on
/// the returned signal.
- (RACSignal *)zipWith:(RACSignal *)signal;
@end
@interface RACSignal (Subscription)
/// Subscribes `subscriber` to changes on the receiver. The receiver defines which
/// events it actually sends and in what situations the events are sent.
///
/// Subscription will always happen on a valid RACScheduler. If the
/// +[RACScheduler currentScheduler] cannot be determined at the time of
/// subscription (e.g., because the calling code is running on a GCD queue or
/// NSOperationQueue), subscription will occur on a private background scheduler.
/// On the main thread, subscriptions will always occur immediately, with a
/// +[RACScheduler currentScheduler] of +[RACScheduler mainThreadScheduler].
///
/// This method must be overridden by any subclasses.
///
/// Returns nil or a disposable. You can call -[RACDisposable dispose] if you
/// need to end your subscription before it would "naturally" end, either by
/// completing or erroring. Once the disposable has been disposed, the subscriber
/// won't receive any more events from the subscription.
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber;
/// Convenience method to subscribe to the `next` event.
///
/// This corresponds to `IObserver<T>.OnNext` in Rx.
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock;
/// Convenience method to subscribe to the `next` and `completed` events.
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock completed:(void (^)(void))completedBlock;
/// Convenience method to subscribe to the `next`, `completed`, and `error` events.
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock;
/// Convenience method to subscribe to `error` events.
///
/// This corresponds to the `IObserver<T>.OnError` in Rx.
- (RACDisposable *)subscribeError:(void (^)(NSError *error))errorBlock;
/// Convenience method to subscribe to `completed` events.
///
/// This corresponds to the `IObserver<T>.OnCompleted` in Rx.
- (RACDisposable *)subscribeCompleted:(void (^)(void))completedBlock;
/// Convenience method to subscribe to `next` and `error` events.
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock;
/// Convenience method to subscribe to `error` and `completed` events.
- (RACDisposable *)subscribeError:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock;
@end
/// Additional methods to assist with debugging.
@interface RACSignal (Debugging)
/// Logs all events that the receiver sends.
- (RACSignal *)logAll;
/// Logs each `next` that the receiver sends.
- (RACSignal *)logNext;
/// Logs any error that the receiver sends.
- (RACSignal *)logError;
/// Logs any `completed` event that the receiver sends.
- (RACSignal *)logCompleted;
@end
/// Additional methods to assist with unit testing.
///
/// **These methods should never ship in production code.**
@interface RACSignal (Testing)
/// Spins the main run loop for a short while, waiting for the receiver to send a `next`.
///
/// **Because this method executes the run loop recursively, it should only be used
/// on the main thread, and only from a unit test.**
///
/// defaultValue - Returned if the receiver completes or errors before sending
///                a `next`, or if the method times out. This argument may be
///                nil.
/// success      - If not NULL, set to whether the receiver completed
///                successfully.
/// error        - If not NULL, set to any error that occurred.
///
/// Returns the first value received, or `defaultValue` if no value is received
/// before the signal finishes or the method times out.
- (id)asynchronousFirstOrDefault:(id)defaultValue success:(BOOL *)success error:(NSError **)error;
/// Spins the main run loop for a short while, waiting for the receiver to complete.
///
/// **Because this method executes the run loop recursively, it should only be used
/// on the main thread, and only from a unit test.**
///
/// error - If not NULL, set to any error that occurs.
///
/// Returns whether the signal completed successfully before timing out. If NO,
/// `error` will be set to any error that occurred.
- (BOOL)asynchronouslyWaitUntilCompleted:(NSError **)error;
@end
@interface RACSignal (Deprecated)
+ (RACSignal *)start:(id (^)(BOOL *success, NSError **error))block __attribute__((deprecated("Use +startEagerlyWithScheduler:block: instead")));
+ (RACSignal *)startWithScheduler:(RACScheduler *)scheduler subjectBlock:(void (^)(RACSubject *subject))block __attribute__((deprecated("Use +startEagerlyWithScheduler:block: instead")));
+ (RACSignal *)startWithScheduler:(RACScheduler *)scheduler block:(id (^)(BOOL *success, NSError **error))block __attribute__((deprecated("Use +startEagerlyWithScheduler:block: instead")));
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSignal.m
New file
@@ -0,0 +1,450 @@
//
//  RACSignal.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/15/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACSignal.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACDynamicSignal.h"
#import "RACEmptySignal.h"
#import "RACErrorSignal.h"
#import "RACMulticastConnection.h"
#import "RACReplaySubject.h"
#import "RACReturnSignal.h"
#import "RACScheduler.h"
#import "RACSerialDisposable.h"
#import "RACSignal+Operations.h"
#import "RACSubject.h"
#import "RACSubscriber+Private.h"
#import "RACTuple.h"
@implementation RACSignal
#pragma mark Lifecycle
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    return [RACDynamicSignal createSignal:didSubscribe];
}
+ (RACSignal *)error:(NSError *)error {
    return [RACErrorSignal error:error];
}
+ (RACSignal *)never {
    return [[self createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
        return nil;
    }] setNameWithFormat:@"+never"];
}
+ (RACSignal *)startEagerlyWithScheduler:(RACScheduler *)scheduler block:(void (^)(id<RACSubscriber> subscriber))block {
    NSCParameterAssert(scheduler != nil);
    NSCParameterAssert(block != NULL);
    RACSignal *signal = [self startLazilyWithScheduler:scheduler block:block];
    // Subscribe to force the lazy signal to call its block.
    [[signal publish] connect];
    return [signal setNameWithFormat:@"+startEagerlyWithScheduler: %@ block:", scheduler];
}
+ (RACSignal *)startLazilyWithScheduler:(RACScheduler *)scheduler block:(void (^)(id<RACSubscriber> subscriber))block {
    NSCParameterAssert(scheduler != nil);
    NSCParameterAssert(block != NULL);
    RACMulticastConnection *connection = [[RACSignal
        createSignal:^ id (id<RACSubscriber> subscriber) {
            block(subscriber);
            return nil;
        }]
        multicast:[RACReplaySubject subject]];
    return [[[RACSignal
        createSignal:^ id (id<RACSubscriber> subscriber) {
            [connection.signal subscribe:subscriber];
            [connection connect];
            return nil;
        }]
        subscribeOn:scheduler]
        setNameWithFormat:@"+startLazilyWithScheduler: %@ block:", scheduler];
}
#pragma mark NSObject
- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: %p> name: %@", self.class, self, self.name];
}
@end
@implementation RACSignal (RACStream)
+ (RACSignal *)empty {
    return [RACEmptySignal empty];
}
+ (RACSignal *)return:(id)value {
    return [RACReturnSignal return:value];
}
- (RACSignal *)bind:(RACStreamBindBlock (^)(void))block {
    NSCParameterAssert(block != NULL);
    /*
     * -bind: should:
     *
     * 1. Subscribe to the original signal of values.
     * 2. Any time the original signal sends a value, transform it using the binding block.
     * 3. If the binding block returns a signal, subscribe to it, and pass all of its values through to the subscriber as they're received.
     * 4. If the binding block asks the bind to terminate, complete the _original_ signal.
     * 5. When _all_ signals complete, send completed to the subscriber.
     *
     * If any signal sends an error at any point, send that to the subscriber.
     */
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACStreamBindBlock bindingBlock = block();
        NSMutableArray *signals = [NSMutableArray arrayWithObject:self];
        RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable];
        void (^completeSignal)(RACSignal *, RACDisposable *) = ^(RACSignal *signal, RACDisposable *finishedDisposable) {
            BOOL removeDisposable = NO;
            @synchronized (signals) {
                [signals removeObject:signal];
                if (signals.count == 0) {
                    [subscriber sendCompleted];
                    [compoundDisposable dispose];
                } else {
                    removeDisposable = YES;
                }
            }
            if (removeDisposable) [compoundDisposable removeDisposable:finishedDisposable];
        };
        void (^addSignal)(RACSignal *) = ^(RACSignal *signal) {
            @synchronized (signals) {
                [signals addObject:signal];
            }
            RACSerialDisposable *selfDisposable = [[RACSerialDisposable alloc] init];
            [compoundDisposable addDisposable:selfDisposable];
            RACDisposable *disposable = [signal subscribeNext:^(id x) {
                [subscriber sendNext:x];
            } error:^(NSError *error) {
                [compoundDisposable dispose];
                [subscriber sendError:error];
            } completed:^{
                @autoreleasepool {
                    completeSignal(signal, selfDisposable);
                }
            }];
            selfDisposable.disposable = disposable;
        };
        @autoreleasepool {
            RACSerialDisposable *selfDisposable = [[RACSerialDisposable alloc] init];
            [compoundDisposable addDisposable:selfDisposable];
            RACDisposable *bindingDisposable = [self subscribeNext:^(id x) {
                // Manually check disposal to handle synchronous errors.
                if (compoundDisposable.disposed) return;
                BOOL stop = NO;
                id signal = bindingBlock(x, &stop);
                @autoreleasepool {
                    if (signal != nil) addSignal(signal);
                    if (signal == nil || stop) {
                        [selfDisposable dispose];
                        completeSignal(self, selfDisposable);
                    }
                }
            } error:^(NSError *error) {
                [compoundDisposable dispose];
                [subscriber sendError:error];
            } completed:^{
                @autoreleasepool {
                    completeSignal(self, selfDisposable);
                }
            }];
            selfDisposable.disposable = bindingDisposable;
        }
        return compoundDisposable;
    }] setNameWithFormat:@"[%@] -bind:", self.name];
}
- (RACSignal *)concat:(RACSignal *)signal {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        RACSerialDisposable *serialDisposable = [[RACSerialDisposable alloc] init];
        RACDisposable *sourceDisposable = [self subscribeNext:^(id x) {
            [subscriber sendNext:x];
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            RACDisposable *concattedDisposable = [signal subscribe:subscriber];
            serialDisposable.disposable = concattedDisposable;
        }];
        serialDisposable.disposable = sourceDisposable;
        return serialDisposable;
    }] setNameWithFormat:@"[%@] -concat: %@", self.name, signal];
}
- (RACSignal *)zipWith:(RACSignal *)signal {
    NSCParameterAssert(signal != nil);
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        __block BOOL selfCompleted = NO;
        NSMutableArray *selfValues = [NSMutableArray array];
        __block BOOL otherCompleted = NO;
        NSMutableArray *otherValues = [NSMutableArray array];
        void (^sendCompletedIfNecessary)(void) = ^{
            @synchronized (selfValues) {
                BOOL selfEmpty = (selfCompleted && selfValues.count == 0);
                BOOL otherEmpty = (otherCompleted && otherValues.count == 0);
                if (selfEmpty || otherEmpty) [subscriber sendCompleted];
            }
        };
        void (^sendNext)(void) = ^{
            @synchronized (selfValues) {
                if (selfValues.count == 0) return;
                if (otherValues.count == 0) return;
                RACTuple *tuple = RACTuplePack(selfValues[0], otherValues[0]);
                [selfValues removeObjectAtIndex:0];
                [otherValues removeObjectAtIndex:0];
                [subscriber sendNext:tuple];
                sendCompletedIfNecessary();
            }
        };
        RACDisposable *selfDisposable = [self subscribeNext:^(id x) {
            @synchronized (selfValues) {
                [selfValues addObject:x ?: RACTupleNil.tupleNil];
                sendNext();
            }
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            @synchronized (selfValues) {
                selfCompleted = YES;
                sendCompletedIfNecessary();
            }
        }];
        RACDisposable *otherDisposable = [signal subscribeNext:^(id x) {
            @synchronized (selfValues) {
                [otherValues addObject:x ?: RACTupleNil.tupleNil];
                sendNext();
            }
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            @synchronized (selfValues) {
                otherCompleted = YES;
                sendCompletedIfNecessary();
            }
        }];
        return [RACDisposable disposableWithBlock:^{
            [selfDisposable dispose];
            [otherDisposable dispose];
        }];
    }] setNameWithFormat:@"[%@] -zipWith: %@", self.name, signal];
}
@end
@implementation RACSignal (Subscription)
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCAssert(NO, @"This method must be overridden by subclasses");
    return nil;
}
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);
    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
    return [self subscribe:o];
}
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock completed:(void (^)(void))completedBlock {
    NSCParameterAssert(nextBlock != NULL);
    NSCParameterAssert(completedBlock != NULL);
    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:completedBlock];
    return [self subscribe:o];
}
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock {
    NSCParameterAssert(nextBlock != NULL);
    NSCParameterAssert(errorBlock != NULL);
    NSCParameterAssert(completedBlock != NULL);
    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:errorBlock completed:completedBlock];
    return [self subscribe:o];
}
- (RACDisposable *)subscribeError:(void (^)(NSError *error))errorBlock {
    NSCParameterAssert(errorBlock != NULL);
    RACSubscriber *o = [RACSubscriber subscriberWithNext:NULL error:errorBlock completed:NULL];
    return [self subscribe:o];
}
- (RACDisposable *)subscribeCompleted:(void (^)(void))completedBlock {
    NSCParameterAssert(completedBlock != NULL);
    RACSubscriber *o = [RACSubscriber subscriberWithNext:NULL error:NULL completed:completedBlock];
    return [self subscribe:o];
}
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock {
    NSCParameterAssert(nextBlock != NULL);
    NSCParameterAssert(errorBlock != NULL);
    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:errorBlock completed:NULL];
    return [self subscribe:o];
}
- (RACDisposable *)subscribeError:(void (^)(NSError *))errorBlock completed:(void (^)(void))completedBlock {
    NSCParameterAssert(completedBlock != NULL);
    NSCParameterAssert(errorBlock != NULL);
    RACSubscriber *o = [RACSubscriber subscriberWithNext:NULL error:errorBlock completed:completedBlock];
    return [self subscribe:o];
}
@end
@implementation RACSignal (Debugging)
- (RACSignal *)logAll {
    return [[[self logNext] logError] logCompleted];
}
- (RACSignal *)logNext {
    return [[self doNext:^(id x) {
        NSLog(@"%@ next: %@", self, x);
    }] setNameWithFormat:@"%@", self.name];
}
- (RACSignal *)logError {
    return [[self doError:^(NSError *error) {
        NSLog(@"%@ error: %@", self, error);
    }] setNameWithFormat:@"%@", self.name];
}
- (RACSignal *)logCompleted {
    return [[self doCompleted:^{
        NSLog(@"%@ completed", self);
    }] setNameWithFormat:@"%@", self.name];
}
@end
@implementation RACSignal (Testing)
static const NSTimeInterval RACSignalAsynchronousWaitTimeout = 10;
- (id)asynchronousFirstOrDefault:(id)defaultValue success:(BOOL *)success error:(NSError **)error {
    NSCAssert([NSThread isMainThread], @"%s should only be used from the main thread", __func__);
    __block id result = defaultValue;
    __block BOOL done = NO;
    // Ensures that we don't pass values across thread boundaries by reference.
    __block NSError *localError;
    __block BOOL localSuccess = YES;
    [[[[self
        take:1]
        timeout:RACSignalAsynchronousWaitTimeout onScheduler:[RACScheduler scheduler]]
        deliverOn:RACScheduler.mainThreadScheduler]
        subscribeNext:^(id x) {
            result = x;
            done = YES;
        } error:^(NSError *e) {
            if (!done) {
                localSuccess = NO;
                localError = e;
                done = YES;
            }
        } completed:^{
            done = YES;
        }];
    do {
        [NSRunLoop.mainRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
    } while (!done);
    if (success != NULL) *success = localSuccess;
    if (error != NULL) *error = localError;
    return result;
}
- (BOOL)asynchronouslyWaitUntilCompleted:(NSError **)error {
    BOOL success = NO;
    [[self ignoreValues] asynchronousFirstOrDefault:nil success:&success error:error];
    return success;
}
@end
@implementation RACSignal (Deprecated)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
+ (RACSignal *)startWithScheduler:(RACScheduler *)scheduler subjectBlock:(void (^)(RACSubject *subject))block {
    NSCParameterAssert(block != NULL);
    RACReplaySubject *subject = [[RACReplaySubject subject] setNameWithFormat:@"+startWithScheduler:subjectBlock:"];
    [scheduler schedule:^{
        block(subject);
    }];
    return subject;
}
+ (RACSignal *)start:(id (^)(BOOL *success, NSError **error))block {
    return [[self startWithScheduler:[RACScheduler scheduler] block:block] setNameWithFormat:@"+start:"];
}
+ (RACSignal *)startWithScheduler:(RACScheduler *)scheduler block:(id (^)(BOOL *success, NSError **error))block {
    return [[self startWithScheduler:scheduler subjectBlock:^(id<RACSubscriber> subscriber) {
        BOOL success = YES;
        NSError *error = nil;
        id returned = block(&success, &error);
        if (!success) {
            [subscriber sendError:error];
        } else {
            [subscriber sendNext:returned];
            [subscriber sendCompleted];
        }
    }] setNameWithFormat:@"+startWithScheduler:block:"];
}
#pragma clang diagnostic pop
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSignalProvider.d
New file
@@ -0,0 +1,5 @@
provider RACSignal {
    probe next(char *signal, char *subscriber, char *valueDescription);
    probe completed(char *signal, char *subscriber);
    probe error(char *signal, char *subscriber, char *errorDescription);
};
Pods/ReactiveCocoa/ReactiveCocoa/RACSignalSequence.h
New file
@@ -0,0 +1,19 @@
//
//  RACSignalSequence.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-11-09.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACSequence.h"
@class RACSignal;
// Private class that adapts a RACSignal to the RACSequence interface.
@interface RACSignalSequence : RACSequence
// Returns a sequence for enumerating over the given signal.
+ (RACSequence *)sequenceWithSignal:(RACSignal *)signal;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSignalSequence.m
New file
@@ -0,0 +1,79 @@
//
//  RACSignalSequence.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-11-09.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACSignalSequence.h"
#import "RACDisposable.h"
#import "RACReplaySubject.h"
#import "RACSignal+Operations.h"
@interface RACSignalSequence ()
// Replays the signal given on initialization.
@property (nonatomic, strong, readonly) RACReplaySubject *subject;
@end
@implementation RACSignalSequence
#pragma mark Lifecycle
+ (RACSequence *)sequenceWithSignal:(RACSignal *)signal {
    RACSignalSequence *seq = [[self alloc] init];
    RACReplaySubject *subject = [RACReplaySubject subject];
    [signal subscribeNext:^(id value) {
        [subject sendNext:value];
    } error:^(NSError *error) {
        [subject sendError:error];
    } completed:^{
        [subject sendCompleted];
    }];
    seq->_subject = subject;
    return seq;
}
#pragma mark RACSequence
- (id)head {
    id value = [self.subject firstOrDefault:self];
    if (value == self) {
        return nil;
    } else {
        return value ?: NSNull.null;
    }
}
- (RACSequence *)tail {
    RACSequence *sequence = [self.class sequenceWithSignal:[self.subject skip:1]];
    sequence.name = self.name;
    return sequence;
}
- (NSArray *)array {
    return self.subject.toArray;
}
#pragma mark NSObject
- (NSString *)description {
    // Synchronously accumulate the values that have been sent so far.
    NSMutableArray *values = [NSMutableArray array];
    RACDisposable *disposable = [self.subject subscribeNext:^(id value) {
        @synchronized (values) {
            [values addObject:value ?: NSNull.null];
        }
    }];
    [disposable dispose];
    return [NSString stringWithFormat:@"<%@: %p>{ name = %@, values = %@ â€¦ }", self.class, self, self.name, values];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACStream+Private.h
New file
@@ -0,0 +1,23 @@
//
//  RACStream+Private.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-07-22.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACStream.h"
@interface RACStream ()
// Combines a list of streams using the logic of the given block.
//
// streams - The streams to combine.
// block   - An operator that combines two streams and returns a new one. The
//           returned stream should contain 2-tuples of the streams' combined
//           values.
//
// Returns a combined stream.
+ (instancetype)join:(id<NSFastEnumeration>)streams block:(RACStream * (^)(id, id))block;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACStream.h
New file
@@ -0,0 +1,335 @@
//
//  RACStream.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-31.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACStream;
/// A block which accepts a value from a RACStream and returns a new instance
/// of the same stream class.
///
/// Setting `stop` to `YES` will cause the bind to terminate after the returned
/// value. Returning `nil` will result in immediate termination.
typedef RACStream * (^RACStreamBindBlock)(id value, BOOL *stop);
/// An abstract class representing any stream of values.
///
/// This class represents a monad, upon which many stream-based operations can
/// be built.
///
/// When subclassing RACStream, only the methods in the main @interface body need
/// to be overridden.
@interface RACStream : NSObject
/// Returns an empty stream.
+ (instancetype)empty;
/// Lifts `value` into the stream monad.
///
/// Returns a stream containing only the given value.
+ (instancetype)return:(id)value;
/// Lazily binds a block to the values in the receiver.
///
/// This should only be used if you need to terminate the bind early, or close
/// over some state. -flattenMap: is more appropriate for all other cases.
///
/// block - A block returning a RACStreamBindBlock. This block will be invoked
///         each time the bound stream is re-evaluated. This block must not be
///         nil or return nil.
///
/// Returns a new stream which represents the combined result of all lazy
/// applications of `block`.
- (instancetype)bind:(RACStreamBindBlock (^)(void))block;
/// Appends the values of `stream` to the values in the receiver.
///
/// stream - A stream to concatenate. This must be an instance of the same
///          concrete class as the receiver, and should not be `nil`.
///
/// Returns a new stream representing the receiver followed by `stream`.
- (instancetype)concat:(RACStream *)stream;
/// Zips the values in the receiver with those of the given stream to create
/// RACTuples.
///
/// The first value of each stream will be combined, then the second value, and
/// so forth, until at least one of the streams is exhausted.
///
/// stream - The stream to zip with. This must be an instance of the same
///          concrete class as the receiver, and should not be `nil`.
///
/// Returns a new stream of RACTuples, representing the zipped values of the
/// two streams.
- (instancetype)zipWith:(RACStream *)stream;
@end
/// This extension contains functionality to support naming streams for
/// debugging.
///
/// Subclasses do not need to override the methods here.
@interface RACStream ()
/// The name of the stream. This is for debugging/human purposes only.
@property (copy) NSString *name;
/// Sets the name of the receiver to the given format string.
///
/// This is for debugging purposes only, and won't do anything unless the
/// RAC_DEBUG_SIGNAL_NAMES environment variable is set.
///
/// Returns the receiver, for easy method chaining.
- (instancetype)setNameWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
@end
/// Operations built on the RACStream primitives.
///
/// These methods do not need to be overridden, although subclasses may
/// occasionally gain better performance from doing so.
@interface RACStream (Operations)
/// Maps `block` across the values in the receiver and flattens the result.
///
/// Note that operators applied _after_ -flattenMap: behave differently from
/// operators _within_ -flattenMap:. See the Examples section below.
///
/// This corresponds to the `SelectMany` method in Rx.
///
/// block - A block which accepts the values in the receiver and returns a new
///         instance of the receiver's class. Returning `nil` from this block is
///         equivalent to returning an empty signal.
///
/// Examples
///
///   [signal flattenMap:^(id x) {
///       // Logs each time a returned signal completes.
///       return [[RACSignal return:x] logCompleted];
///   }];
///
///   [[signal
///       flattenMap:^(id x) {
///           return [RACSignal return:x];
///       }]
///       // Logs only once, when all of the signals complete.
///       logCompleted];
///
/// Returns a new stream which represents the combined streams resulting from
/// mapping `block`.
- (instancetype)flattenMap:(RACStream * (^)(id value))block;
/// Flattens a stream of streams.
///
/// This corresponds to the `Merge` method in Rx.
///
/// Returns a stream consisting of the combined streams obtained from the
/// receiver.
- (instancetype)flatten;
/// Maps `block` across the values in the receiver.
///
/// This corresponds to the `Select` method in Rx.
///
/// Returns a new stream with the mapped values.
- (instancetype)map:(id (^)(id value))block;
/// Replaces each value in the receiver with the given object.
///
/// Returns a new stream which includes the given object once for each value in
/// the receiver.
- (instancetype)mapReplace:(id)object;
/// Filters out values in the receiver that don't pass the given test.
///
/// This corresponds to the `Where` method in Rx.
///
/// Returns a new stream with only those values that passed.
- (instancetype)filter:(BOOL (^)(id value))block;
/// Filters out values in the receiver that equal (via -isEqual:) the provided value.
///
/// value - The value can be `nil`, in which case it ignores `nil` values.
///
/// Returns a new stream containing only the values which did not compare equal
/// to `value`.
- (instancetype)ignore:(id)value;
/// Unpacks each RACTuple in the receiver and maps the values to a new value.
///
/// reduceBlock - The block which reduces each RACTuple's values into one value.
///               It must take as many arguments as the number of tuple elements
///               to process. Each argument will be an object argument. The
///               return value must be an object. This argument cannot be nil.
///
/// Returns a new stream of reduced tuple values.
- (instancetype)reduceEach:(id (^)())reduceBlock;
/// Returns a stream consisting of `value`, followed by the values in the
/// receiver.
- (instancetype)startWith:(id)value;
/// Skips the first `skipCount` values in the receiver.
///
/// Returns the receiver after skipping the first `skipCount` values. If
/// `skipCount` is greater than the number of values in the stream, an empty
/// stream is returned.
- (instancetype)skip:(NSUInteger)skipCount;
/// Returns a stream of the first `count` values in the receiver. If `count` is
/// greater than or equal to the number of values in the stream, a stream
/// equivalent to the receiver is returned.
- (instancetype)take:(NSUInteger)count;
/// Zips the values in the given streams to create RACTuples.
///
/// The first value of each stream will be combined, then the second value, and
/// so forth, until at least one of the streams is exhausted.
///
/// streams - The streams to combine. These must all be instances of the same
///           concrete class implementing the protocol. If this collection is
///           empty, the returned stream will be empty.
///
/// Returns a new stream containing RACTuples of the zipped values from the
/// streams.
+ (instancetype)zip:(id<NSFastEnumeration>)streams;
/// Zips streams using +zip:, then reduces the resulting tuples into a single
/// value using -reduceEach:
///
/// streams     - The streams to combine. These must all be instances of the
///               same concrete class implementing the protocol. If this
///               collection is empty, the returned stream will be empty.
/// reduceBlock - The block which reduces the values from all the streams
///               into one value. It must take as many arguments as the
///               number of streams given. Each argument will be an object
///               argument. The return value must be an object. This argument
///               must not be nil.
///
/// Example:
///
///   [RACStream zip:@[ stringSignal, intSignal ] reduce:^(NSString *string, NSNumber *number) {
///       return [NSString stringWithFormat:@"%@: %@", string, number];
///   }];
///
/// Returns a new stream containing the results from each invocation of
/// `reduceBlock`.
+ (instancetype)zip:(id<NSFastEnumeration>)streams reduce:(id (^)())reduceBlock;
/// Returns a stream obtained by concatenating `streams` in order.
+ (instancetype)concat:(id<NSFastEnumeration>)streams;
/// Combines values in the receiver from left to right using the given block.
///
/// The algorithm proceeds as follows:
///
///  1. `startingValue` is passed into the block as the `running` value, and the
///  first element of the receiver is passed into the block as the `next` value.
///  2. The result of the invocation is added to the returned stream.
///  3. The result of the invocation (`running`) and the next element of the
///  receiver (`next`) is passed into `block`.
///  4. Steps 2 and 3 are repeated until all values have been processed.
///
/// startingValue - The value to be combined with the first element of the
///                 receiver. This value may be `nil`.
/// reduceBlock   - The block that describes how to combine values of the
///                 receiver. If the receiver is empty, this block will never be
///                 invoked. Cannot be nil.
///
/// Examples
///
///      RACSequence *numbers = @[ @1, @2, @3, @4 ].rac_sequence;
///
///      // Contains 1, 3, 6, 10
///      RACSequence *sums = [numbers scanWithStart:@0 reduce:^(NSNumber *sum, NSNumber *next) {
///          return @(sum.integerValue + next.integerValue);
///      }];
///
/// Returns a new stream that consists of each application of `reduceBlock`. If the
/// receiver is empty, an empty stream is returned.
- (instancetype)scanWithStart:(id)startingValue reduce:(id (^)(id running, id next))reduceBlock;
/// Combines values in the receiver from left to right using the given block
/// which also takes zero-based index of the values.
///
/// startingValue - The value to be combined with the first element of the
///                 receiver. This value may be `nil`.
/// reduceBlock   - The block that describes how to combine values of the
///                 receiver. This block takes zero-based index value as the last
///                 parameter. If the receiver is empty, this block will never
///                 be invoked. Cannot be nil.
///
/// Returns a new stream that consists of each application of `reduceBlock`. If the
/// receiver is empty, an empty stream is returned.
- (instancetype)scanWithStart:(id)startingValue reduceWithIndex:(id (^)(id running, id next, NSUInteger index))reduceBlock;
/// Combines each previous and current value into one object.
///
/// This method is similar to -scanWithStart:reduce:, but only ever operates on
/// the previous and current values (instead of the whole stream), and does not
/// pass the return value of `reduceBlock` into the next invocation of it.
///
/// start       - The value passed into `reduceBlock` as `previous` for the
///               first value.
/// reduceBlock - The block that combines the previous value and the current
///               value to create the reduced value. Cannot be nil.
///
/// Examples
///
///      RACSequence *numbers = @[ @1, @2, @3, @4 ].rac_sequence;
///
///      // Contains 1, 3, 5, 7
///      RACSequence *sums = [numbers combinePreviousWithStart:@0 reduce:^(NSNumber *previous, NSNumber *next) {
///          return @(previous.integerValue + next.integerValue);
///      }];
///
/// Returns a new stream consisting of the return values from each application of
/// `reduceBlock`.
- (instancetype)combinePreviousWithStart:(id)start reduce:(id (^)(id previous, id current))reduceBlock;
/// Takes values until the given block returns `YES`.
///
/// Returns a stream of the initial values in the receiver that fail `predicate`.
/// If `predicate` never returns `YES`, a stream equivalent to the receiver is
/// returned.
- (instancetype)takeUntilBlock:(BOOL (^)(id x))predicate;
/// Takes values until the given block returns `NO`.
///
/// Returns a stream of the initial values in the receiver that pass `predicate`.
/// If `predicate` never returns `NO`, a stream equivalent to the receiver is
/// returned.
- (instancetype)takeWhileBlock:(BOOL (^)(id x))predicate;
/// Skips values until the given block returns `YES`.
///
/// Returns a stream containing the values of the receiver that follow any
/// initial values failing `predicate`. If `predicate` never returns `YES`,
/// an empty stream is returned.
- (instancetype)skipUntilBlock:(BOOL (^)(id x))predicate;
/// Skips values until the given block returns `NO`.
///
/// Returns a stream containing the values of the receiver that follow any
/// initial values passing `predicate`. If `predicate` never returns `NO`, an
/// empty stream is returned.
- (instancetype)skipWhileBlock:(BOOL (^)(id x))predicate;
/// Returns a stream of values for which -isEqual: returns NO when compared to the
/// previous value.
- (instancetype)distinctUntilChanged;
@end
@interface RACStream (Deprecated)
- (instancetype)sequenceMany:(RACStream * (^)(void))block __attribute__((deprecated("Use -flattenMap: instead")));
- (instancetype)scanWithStart:(id)startingValue combine:(id (^)(id running, id next))block __attribute__((deprecated("Renamed to -scanWithStart:reduce:")));
- (instancetype)mapPreviousWithStart:(id)start reduce:(id (^)(id previous, id current))combineBlock __attribute__((deprecated("Renamed to -combinePreviousWithStart:reduce:")));
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACStream.m
New file
@@ -0,0 +1,377 @@
//
//  RACStream.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-31.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACStream.h"
#import "NSObject+RACDescription.h"
#import "RACBlockTrampoline.h"
#import "RACTuple.h"
@implementation RACStream
#pragma mark Lifecycle
- (id)init {
    self = [super init];
    if (self == nil) return nil;
    self.name = @"";
    return self;
}
#pragma mark Abstract methods
+ (instancetype)empty {
    return nil;
}
- (instancetype)bind:(RACStreamBindBlock (^)(void))block {
    return nil;
}
+ (instancetype)return:(id)value {
    return nil;
}
- (instancetype)concat:(RACStream *)stream {
    return nil;
}
- (instancetype)zipWith:(RACStream *)stream {
    return nil;
}
#pragma mark Naming
- (instancetype)setNameWithFormat:(NSString *)format, ... {
    if (getenv("RAC_DEBUG_SIGNAL_NAMES") == NULL) return self;
    NSCParameterAssert(format != nil);
    va_list args;
    va_start(args, format);
    NSString *str = [[NSString alloc] initWithFormat:format arguments:args];
    va_end(args);
    self.name = str;
    return self;
}
@end
@implementation RACStream (Operations)
- (instancetype)flattenMap:(RACStream * (^)(id value))block {
    Class class = self.class;
    return [[self bind:^{
        return ^(id value, BOOL *stop) {
            id stream = block(value) ?: [class empty];
            NSCAssert([stream isKindOfClass:RACStream.class], @"Value returned from -flattenMap: is not a stream: %@", stream);
            return stream;
        };
    }] setNameWithFormat:@"[%@] -flattenMap:", self.name];
}
- (instancetype)flatten {
    __weak RACStream *stream __attribute__((unused)) = self;
    return [[self flattenMap:^(id value) {
        return value;
    }] setNameWithFormat:@"[%@] -flatten", self.name];
}
- (instancetype)map:(id (^)(id value))block {
    NSCParameterAssert(block != nil);
    Class class = self.class;
    return [[self flattenMap:^(id value) {
        return [class return:block(value)];
    }] setNameWithFormat:@"[%@] -map:", self.name];
}
- (instancetype)mapReplace:(id)object {
    return [[self map:^(id _) {
        return object;
    }] setNameWithFormat:@"[%@] -mapReplace: %@", self.name, [object rac_description]];
}
- (instancetype)combinePreviousWithStart:(id)start reduce:(id (^)(id previous, id next))reduceBlock {
    NSCParameterAssert(reduceBlock != NULL);
    return [[[self
        scanWithStart:RACTuplePack(start)
        reduce:^(RACTuple *previousTuple, id next) {
            id value = reduceBlock(previousTuple[0], next);
            return RACTuplePack(next, value);
        }]
        map:^(RACTuple *tuple) {
            return tuple[1];
        }]
        setNameWithFormat:@"[%@] -combinePreviousWithStart: %@ reduce:", self.name, [start rac_description]];
}
- (instancetype)filter:(BOOL (^)(id value))block {
    NSCParameterAssert(block != nil);
    Class class = self.class;
    return [[self flattenMap:^ id (id value) {
        if (block(value)) {
            return [class return:value];
        } else {
            return class.empty;
        }
    }] setNameWithFormat:@"[%@] -filter:", self.name];
}
- (instancetype)ignore:(id)value {
    return [[self filter:^ BOOL (id innerValue) {
        return innerValue != value && ![innerValue isEqual:value];
    }] setNameWithFormat:@"[%@] -ignore: %@", self.name, [value rac_description]];
}
- (instancetype)reduceEach:(id (^)())reduceBlock {
    NSCParameterAssert(reduceBlock != nil);
    __weak RACStream *stream __attribute__((unused)) = self;
    return [[self map:^(RACTuple *t) {
        NSCAssert([t isKindOfClass:RACTuple.class], @"Value from stream %@ is not a tuple: %@", stream, t);
        return [RACBlockTrampoline invokeBlock:reduceBlock withArguments:t];
    }] setNameWithFormat:@"[%@] -reduceEach:", self.name];
}
- (instancetype)startWith:(id)value {
    return [[[self.class return:value]
        concat:self]
        setNameWithFormat:@"[%@] -startWith: %@", self.name, [value rac_description]];
}
- (instancetype)skip:(NSUInteger)skipCount {
    Class class = self.class;
    return [[self bind:^{
        __block NSUInteger skipped = 0;
        return ^(id value, BOOL *stop) {
            if (skipped >= skipCount) return [class return:value];
            skipped++;
            return class.empty;
        };
    }] setNameWithFormat:@"[%@] -skip: %lu", self.name, (unsigned long)skipCount];
}
- (instancetype)take:(NSUInteger)count {
    Class class = self.class;
    if (count == 0) return class.empty;
    return [[self bind:^{
        __block NSUInteger taken = 0;
        return ^ id (id value, BOOL *stop) {
            if (taken < count) {
                ++taken;
                if (taken == count) *stop = YES;
                return [class return:value];
            } else {
                return nil;
            }
        };
    }] setNameWithFormat:@"[%@] -take: %lu", self.name, (unsigned long)count];
}
+ (instancetype)join:(id<NSFastEnumeration>)streams block:(RACStream * (^)(id, id))block {
    RACStream *current = nil;
    // Creates streams of successively larger tuples by combining the input
    // streams one-by-one.
    for (RACStream *stream in streams) {
        // For the first stream, just wrap its values in a RACTuple. That way,
        // if only one stream is given, the result is still a stream of tuples.
        if (current == nil) {
            current = [stream map:^(id x) {
                return RACTuplePack(x);
            }];
            continue;
        }
        current = block(current, stream);
    }
    if (current == nil) return [self empty];
    return [current map:^(RACTuple *xs) {
        // Right now, each value is contained in its own tuple, sorta like:
        //
        // (((1), 2), 3)
        //
        // We need to unwrap all the layers and create a tuple out of the result.
        NSMutableArray *values = [[NSMutableArray alloc] init];
        while (xs != nil) {
            [values insertObject:xs.last ?: RACTupleNil.tupleNil atIndex:0];
            xs = (xs.count > 1 ? xs.first : nil);
        }
        return [RACTuple tupleWithObjectsFromArray:values];
    }];
}
+ (instancetype)zip:(id<NSFastEnumeration>)streams {
    return [[self join:streams block:^(RACStream *left, RACStream *right) {
        return [left zipWith:right];
    }] setNameWithFormat:@"+zip: %@", streams];
}
+ (instancetype)zip:(id<NSFastEnumeration>)streams reduce:(id (^)())reduceBlock {
    NSCParameterAssert(reduceBlock != nil);
    RACStream *result = [self zip:streams];
    // Although we assert this condition above, older versions of this method
    // supported this argument being nil. Avoid crashing Release builds of
    // apps that depended on that.
    if (reduceBlock != nil) result = [result reduceEach:reduceBlock];
    return [result setNameWithFormat:@"+zip: %@ reduce:", streams];
}
+ (instancetype)concat:(id<NSFastEnumeration>)streams {
    RACStream *result = self.empty;
    for (RACStream *stream in streams) {
        result = [result concat:stream];
    }
    return [result setNameWithFormat:@"+concat: %@", streams];
}
- (instancetype)scanWithStart:(id)startingValue reduce:(id (^)(id running, id next))reduceBlock {
    NSCParameterAssert(reduceBlock != nil);
    return [[self
        scanWithStart:startingValue
        reduceWithIndex:^(id running, id next, NSUInteger index) {
            return reduceBlock(running, next);
        }]
        setNameWithFormat:@"[%@] -scanWithStart: %@ reduce:", self.name, [startingValue rac_description]];
}
- (instancetype)scanWithStart:(id)startingValue reduceWithIndex:(id (^)(id, id, NSUInteger))reduceBlock {
    NSCParameterAssert(reduceBlock != nil);
    Class class = self.class;
    return [[self bind:^{
        __block id running = startingValue;
        __block NSUInteger index = 0;
        return ^(id value, BOOL *stop) {
            running = reduceBlock(running, value, index++);
            return [class return:running];
        };
    }] setNameWithFormat:@"[%@] -scanWithStart: %@ reduceWithIndex:", self.name, [startingValue rac_description]];
}
- (instancetype)takeUntilBlock:(BOOL (^)(id x))predicate {
    NSCParameterAssert(predicate != nil);
    Class class = self.class;
    return [[self bind:^{
        return ^ id (id value, BOOL *stop) {
            if (predicate(value)) return nil;
            return [class return:value];
        };
    }] setNameWithFormat:@"[%@] -takeUntilBlock:", self.name];
}
- (instancetype)takeWhileBlock:(BOOL (^)(id x))predicate {
    NSCParameterAssert(predicate != nil);
    return [[self takeUntilBlock:^ BOOL (id x) {
        return !predicate(x);
    }] setNameWithFormat:@"[%@] -takeWhileBlock:", self.name];
}
- (instancetype)skipUntilBlock:(BOOL (^)(id x))predicate {
    NSCParameterAssert(predicate != nil);
    Class class = self.class;
    return [[self bind:^{
        __block BOOL skipping = YES;
        return ^ id (id value, BOOL *stop) {
            if (skipping) {
                if (predicate(value)) {
                    skipping = NO;
                } else {
                    return class.empty;
                }
            }
            return [class return:value];
        };
    }] setNameWithFormat:@"[%@] -skipUntilBlock:", self.name];
}
- (instancetype)skipWhileBlock:(BOOL (^)(id x))predicate {
    NSCParameterAssert(predicate != nil);
    return [[self skipUntilBlock:^ BOOL (id x) {
        return !predicate(x);
    }] setNameWithFormat:@"[%@] -skipWhileBlock:", self.name];
}
- (instancetype)distinctUntilChanged {
    Class class = self.class;
    return [[self bind:^{
        __block id lastValue = nil;
        __block BOOL initial = YES;
        return ^(id x, BOOL *stop) {
            if (!initial && (lastValue == x || [x isEqual:lastValue])) return [class empty];
            initial = NO;
            lastValue = x;
            return [class return:x];
        };
    }] setNameWithFormat:@"[%@] -distinctUntilChanged", self.name];
}
@end
@implementation RACStream (Deprecated)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
- (instancetype)sequenceMany:(RACStream * (^)(void))block {
    NSCParameterAssert(block != NULL);
    return [[self flattenMap:^(id _) {
        return block();
    }] setNameWithFormat:@"[%@] -sequenceMany:", self.name];
}
- (instancetype)scanWithStart:(id)startingValue combine:(id (^)(id running, id next))block {
    return [self scanWithStart:startingValue reduce:block];
}
- (instancetype)mapPreviousWithStart:(id)start reduce:(id (^)(id previous, id current))combineBlock {
    return [self combinePreviousWithStart:start reduce:combineBlock];
}
#pragma clang diagnostic pop
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACStringSequence.h
New file
@@ -0,0 +1,18 @@
//
//  RACStringSequence.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "RACSequence.h"
// Private class that adapts a string to the RACSequence interface.
@interface RACStringSequence : RACSequence
// Returns a sequence for enumerating over the given string, starting from the
// given character offset. The string will be copied to prevent mutation.
+ (RACSequence *)sequenceWithString:(NSString *)string offset:(NSUInteger)offset;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACStringSequence.m
New file
@@ -0,0 +1,65 @@
//
//  RACStringSequence.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2012-10-29.
//  Copyright (c) 2012 GitHub. All rights reserved.
//
#import "RACStringSequence.h"
@interface RACStringSequence ()
// The string being sequenced.
@property (nonatomic, copy, readonly) NSString *string;
// The index in the string from which the sequence starts.
@property (nonatomic, assign, readonly) NSUInteger offset;
@end
@implementation RACStringSequence
#pragma mark Lifecycle
+ (RACSequence *)sequenceWithString:(NSString *)string offset:(NSUInteger)offset {
    NSCParameterAssert(offset <= string.length);
    if (offset == string.length) return self.empty;
    RACStringSequence *seq = [[self alloc] init];
    seq->_string = [string copy];
    seq->_offset = offset;
    return seq;
}
#pragma mark RACSequence
- (id)head {
    return [self.string substringWithRange:NSMakeRange(self.offset, 1)];
}
- (RACSequence *)tail {
    RACSequence *sequence = [self.class sequenceWithString:self.string offset:self.offset + 1];
    sequence.name = self.name;
    return sequence;
}
- (NSArray *)array {
    NSUInteger substringLength = self.string.length - self.offset;
    NSMutableArray *array = [NSMutableArray arrayWithCapacity:substringLength];
    [self.string enumerateSubstringsInRange:NSMakeRange(self.offset, substringLength) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
        [array addObject:substring];
    }];
    return [array copy];
}
#pragma mark NSObject
- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: %p>{ name = %@, string = %@ }", self.class, self, self.name, [self.string substringFromIndex:self.offset]];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSubject.h
New file
@@ -0,0 +1,22 @@
//
//  RACSubject.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/9/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACSignal.h"
#import "RACSubscriber.h"
/// A subject can be thought of as a signal that you can manually control by
/// sending next, completed, and error.
///
/// They're most helpful in bridging the non-RAC world to RAC, since they let you
/// manually control the sending of events.
@interface RACSubject : RACSignal <RACSubscriber>
/// Returns a new subject.
+ (instancetype)subject;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSubject.m
New file
@@ -0,0 +1,124 @@
//
//  RACSubject.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/9/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACSubject.h"
#import "RACEXTScope.h"
#import "RACCompoundDisposable.h"
#import "RACPassthroughSubscriber.h"
@interface RACSubject ()
// Contains all current subscribers to the receiver.
//
// This should only be used while synchronized on `self`.
@property (nonatomic, strong, readonly) NSMutableArray *subscribers;
// Contains all of the receiver's subscriptions to other signals.
@property (nonatomic, strong, readonly) RACCompoundDisposable *disposable;
// Enumerates over each of the receiver's `subscribers` and invokes `block` for
// each.
- (void)enumerateSubscribersUsingBlock:(void (^)(id<RACSubscriber> subscriber))block;
@end
@implementation RACSubject
#pragma mark Lifecycle
+ (instancetype)subject {
    return [[self alloc] init];
}
- (id)init {
    self = [super init];
    if (self == nil) return nil;
    _disposable = [RACCompoundDisposable compoundDisposable];
    _subscribers = [[NSMutableArray alloc] initWithCapacity:1];
    return self;
}
- (void)dealloc {
    [self.disposable dispose];
}
#pragma mark Subscription
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCParameterAssert(subscriber != nil);
    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
    NSMutableArray *subscribers = self.subscribers;
    @synchronized (subscribers) {
        [subscribers addObject:subscriber];
    }
    return [RACDisposable disposableWithBlock:^{
        @synchronized (subscribers) {
            // Since newer subscribers are generally shorter-lived, search
            // starting from the end of the list.
            NSUInteger index = [subscribers indexOfObjectWithOptions:NSEnumerationReverse passingTest:^ BOOL (id<RACSubscriber> obj, NSUInteger index, BOOL *stop) {
                return obj == subscriber;
            }];
            if (index != NSNotFound) [subscribers removeObjectAtIndex:index];
        }
    }];
}
- (void)enumerateSubscribersUsingBlock:(void (^)(id<RACSubscriber> subscriber))block {
    NSArray *subscribers;
    @synchronized (self.subscribers) {
        subscribers = [self.subscribers copy];
    }
    for (id<RACSubscriber> subscriber in subscribers) {
        block(subscriber);
    }
}
#pragma mark RACSubscriber
- (void)sendNext:(id)value {
    [self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
        [subscriber sendNext:value];
    }];
}
- (void)sendError:(NSError *)error {
    [self.disposable dispose];
    [self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
        [subscriber sendError:error];
    }];
}
- (void)sendCompleted {
    [self.disposable dispose];
    [self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
        [subscriber sendCompleted];
    }];
}
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)d {
    if (d.disposed) return;
    [self.disposable addDisposable:d];
    @weakify(self, d);
    [d addDisposable:[RACDisposable disposableWithBlock:^{
        @strongify(self, d);
        [self.disposable removeDisposable:d];
    }]];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriber+Private.h
New file
@@ -0,0 +1,17 @@
//
//  RACSubscriber+Private.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-06-13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACSubscriber.h"
// A simple block-based subscriber.
@interface RACSubscriber : NSObject <RACSubscriber>
// Creates a new subscriber with the given blocks.
+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriber.h
New file
@@ -0,0 +1,51 @@
//
//  RACSubscriber.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/1/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
@class RACCompoundDisposable;
/// Represents any object which can directly receive values from a RACSignal.
///
/// You generally shouldn't need to implement this protocol. +[RACSignal
/// createSignal:], RACSignal's subscription methods, or RACSubject should work
/// for most uses.
///
/// Implementors of this protocol may receive messages and values from multiple
/// threads simultaneously, and so should be thread-safe. Subscribers will also
/// be weakly referenced so implementations must allow that.
@protocol RACSubscriber <NSObject>
@required
/// Sends the next value to subscribers.
///
/// value - The value to send. This can be `nil`.
- (void)sendNext:(id)value;
/// Sends the error to subscribers.
///
/// error - The error to send. This can be `nil`.
///
/// This terminates the subscription, and invalidates the subscriber (such that
/// it cannot subscribe to anything else in the future).
- (void)sendError:(NSError *)error;
/// Sends completed to subscribers.
///
/// This terminates the subscription, and invalidates the subscriber (such that
/// it cannot subscribe to anything else in the future).
- (void)sendCompleted;
/// Sends the subscriber a disposable that represents one of its subscriptions.
///
/// A subscriber may receive multiple disposables if it gets subscribed to
/// multiple signals; however, any error or completed events must terminate _all_
/// subscriptions.
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriber.m
New file
@@ -0,0 +1,112 @@
//
//  RACSubscriber.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/1/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACSubscriber.h"
#import "RACSubscriber+Private.h"
#import "RACEXTScope.h"
#import "RACCompoundDisposable.h"
@interface RACSubscriber ()
// These callbacks should only be accessed while synchronized on self.
@property (nonatomic, copy) void (^next)(id value);
@property (nonatomic, copy) void (^error)(NSError *error);
@property (nonatomic, copy) void (^completed)(void);
@property (nonatomic, strong, readonly) RACCompoundDisposable *disposable;
@end
@implementation RACSubscriber
#pragma mark Lifecycle
+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed {
    RACSubscriber *subscriber = [[self alloc] init];
    subscriber->_next = [next copy];
    subscriber->_error = [error copy];
    subscriber->_completed = [completed copy];
    return subscriber;
}
- (id)init {
    self = [super init];
    if (self == nil) return nil;
    @unsafeify(self);
    RACDisposable *selfDisposable = [RACDisposable disposableWithBlock:^{
        @strongify(self);
        @synchronized (self) {
            self.next = nil;
            self.error = nil;
            self.completed = nil;
        }
    }];
    _disposable = [RACCompoundDisposable compoundDisposable];
    [_disposable addDisposable:selfDisposable];
    return self;
}
- (void)dealloc {
    [self.disposable dispose];
}
#pragma mark RACSubscriber
- (void)sendNext:(id)value {
    @synchronized (self) {
        void (^nextBlock)(id) = [self.next copy];
        if (nextBlock == nil) return;
        nextBlock(value);
    }
}
- (void)sendError:(NSError *)e {
    @synchronized (self) {
        void (^errorBlock)(NSError *) = [self.error copy];
        [self.disposable dispose];
        if (errorBlock == nil) return;
        errorBlock(e);
    }
}
- (void)sendCompleted {
    @synchronized (self) {
        void (^completedBlock)(void) = [self.completed copy];
        [self.disposable dispose];
        if (completedBlock == nil) return;
        completedBlock();
    }
}
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)otherDisposable {
    if (otherDisposable.disposed) return;
    RACCompoundDisposable *selfDisposable = self.disposable;
    [selfDisposable addDisposable:otherDisposable];
    @unsafeify(otherDisposable);
    // If this subscription terminates, purge its disposable to avoid unbounded
    // memory growth.
    [otherDisposable addDisposable:[RACDisposable disposableWithBlock:^{
        @strongify(otherDisposable);
        [selfDisposable removeDisposable:otherDisposable];
    }]];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriptingAssignmentTrampoline.h
New file
@@ -0,0 +1,54 @@
//
//  RACSubscriptingAssignmentTrampoline.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 9/24/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RACEXTKeyPathCoding.h"
@class RACSignal;
/// Assigns a signal to an object property, automatically setting the given key
/// path on every `next`. When the signal completes, the binding is automatically
/// disposed of.
///
/// There are two different versions of this macro:
///
///  - RAC(TARGET, KEYPATH, NILVALUE) will bind the `KEYPATH` of `TARGET` to the
///    given signal. If the signal ever sends a `nil` value, the property will be
///    set to `NILVALUE` instead. `NILVALUE` may itself be `nil` for object
///    properties, but an NSValue should be used for primitive properties, to
///    avoid an exception if `nil` is sent (which might occur if an intermediate
///    object is set to `nil`).
///  - RAC(TARGET, KEYPATH) is the same as the above, but `NILVALUE` defaults to
///    `nil`.
///
/// See -[RACSignal setKeyPath:onObject:nilValue:] for more information about the
/// binding's semantics.
///
/// Examples
///
///  RAC(self, objectProperty) = objectSignal;
///  RAC(self, stringProperty, @"foobar") = stringSignal;
///  RAC(self, integerProperty, @42) = integerSignal;
///
/// WARNING: Under certain conditions, use of this macro can be thread-unsafe.
///          See the documentation of -setKeyPath:onObject:nilValue:.
#define RAC(TARGET, ...) \
    metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \
        (RAC_(TARGET, __VA_ARGS__, nil)) \
        (RAC_(TARGET, __VA_ARGS__))
/// Do not use this directly. Use the RAC macro above.
#define RAC_(TARGET, KEYPATH, NILVALUE) \
    [[RACSubscriptingAssignmentTrampoline alloc] initWithTarget:(TARGET) nilValue:(NILVALUE)][@keypath(TARGET, KEYPATH)]
@interface RACSubscriptingAssignmentTrampoline : NSObject
- (id)initWithTarget:(id)target nilValue:(id)nilValue;
- (void)setObject:(RACSignal *)signal forKeyedSubscript:(NSString *)keyPath;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriptingAssignmentTrampoline.m
New file
@@ -0,0 +1,42 @@
//
//  RACSubscriptingAssignmentTrampoline.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 9/24/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACSubscriptingAssignmentTrampoline.h"
#import "RACSignal+Operations.h"
@interface RACSubscriptingAssignmentTrampoline ()
// The object to bind to.
@property (nonatomic, strong, readonly) id target;
// A value to use when `nil` is sent on the bound signal.
@property (nonatomic, strong, readonly) id nilValue;
@end
@implementation RACSubscriptingAssignmentTrampoline
- (id)initWithTarget:(id)target nilValue:(id)nilValue {
    // This is often a programmer error, but this prevents crashes if the target
    // object has unexpectedly deallocated.
    if (target == nil) return nil;
    self = [super init];
    if (self == nil) return nil;
    _target = target;
    _nilValue = nilValue;
    return self;
}
- (void)setObject:(RACSignal *)signal forKeyedSubscript:(NSString *)keyPath {
    [signal setKeyPath:keyPath onObject:self.target nilValue:self.nilValue];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriptionScheduler.h
New file
@@ -0,0 +1,15 @@
//
//  RACSubscriptionScheduler.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 11/30/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACScheduler.h"
// A private scheduler used only for subscriptions. See the private
// +[RACScheduler subscriptionScheduler] method for more information.
@interface RACSubscriptionScheduler : RACScheduler
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACSubscriptionScheduler.m
New file
@@ -0,0 +1,54 @@
//
//  RACSubscriptionScheduler.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 11/30/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACSubscriptionScheduler.h"
#import "RACScheduler+Private.h"
@interface RACSubscriptionScheduler ()
// A private background scheduler on which to subscribe if the +currentScheduler
// is unknown.
@property (nonatomic, strong, readonly) RACScheduler *backgroundScheduler;
@end
@implementation RACSubscriptionScheduler
#pragma mark Lifecycle
- (id)init {
    self = [super initWithName:@"com.ReactiveCocoa.RACScheduler.subscriptionScheduler"];
    if (self == nil) return nil;
    _backgroundScheduler = [RACScheduler scheduler];
    return self;
}
#pragma mark RACScheduler
- (RACDisposable *)schedule:(void (^)(void))block {
    NSCParameterAssert(block != NULL);
    if (RACScheduler.currentScheduler == nil) return [self.backgroundScheduler schedule:block];
    block();
    return nil;
}
- (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block {
    RACScheduler *scheduler = RACScheduler.currentScheduler ?: self.backgroundScheduler;
    return [scheduler after:date schedule:block];
}
- (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block {
    RACScheduler *scheduler = RACScheduler.currentScheduler ?: self.backgroundScheduler;
    return [scheduler after:date repeatingEvery:interval withLeeway:leeway schedule:block];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACTargetQueueScheduler.h
New file
@@ -0,0 +1,24 @@
//
//  RACTargetQueueScheduler.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 6/6/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACQueueScheduler.h"
/// A scheduler that enqueues blocks on a private serial queue, targeting an
/// arbitrary GCD queue.
@interface RACTargetQueueScheduler : RACQueueScheduler
/// Initializes the receiver with a serial queue that will target the given
/// `targetQueue`.
///
/// name        - The name of the scheduler. If nil, a default name will be used.
/// targetQueue - The queue to target. Cannot be NULL.
///
/// Returns the initialized object.
- (id)initWithName:(NSString *)name targetQueue:(dispatch_queue_t)targetQueue;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACTargetQueueScheduler.m
New file
@@ -0,0 +1,31 @@
//
//  RACTargetQueueScheduler.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 6/6/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACTargetQueueScheduler.h"
#import "RACQueueScheduler+Subclass.h"
@implementation RACTargetQueueScheduler
#pragma mark Lifecycle
- (id)initWithName:(NSString *)name targetQueue:(dispatch_queue_t)targetQueue {
    NSCParameterAssert(targetQueue != NULL);
    if (name == nil) {
        name = [NSString stringWithFormat:@"com.ReactiveCocoa.RACTargetQueueScheduler(%s)", dispatch_queue_get_label(targetQueue)];
    }
    dispatch_queue_t queue = dispatch_queue_create(name.UTF8String, DISPATCH_QUEUE_SERIAL);
    if (queue == NULL) return nil;
    dispatch_set_target_queue(queue, targetQueue);
    return [super initWithName:name queue:queue];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACTestScheduler.h
New file
@@ -0,0 +1,42 @@
//
//  RACTestScheduler.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-07-06.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACScheduler.h"
/// A special kind of scheduler that steps through virtualized time.
///
/// This scheduler class can be used in unit tests to verify asynchronous
/// behaviors without spending significant time waiting.
///
/// This class can be used from multiple threads, but only one thread can `step`
/// through the enqueued actions at a time. Other threads will wait while the
/// scheduled blocks are being executed.
@interface RACTestScheduler : RACScheduler
/// Initializes a new test scheduler.
- (instancetype)init;
/// Executes the next scheduled block, if any.
///
/// This method will block until the scheduled action has completed.
- (void)step;
/// Executes up to the next `ticks` scheduled blocks.
///
/// This method will block until the scheduled actions have completed.
///
/// ticks - The number of scheduled blocks to execute. If there aren't this many
///         blocks enqueued, all scheduled blocks are executed.
- (void)step:(NSUInteger)ticks;
/// Executes all of the scheduled blocks on the receiver.
///
/// This method will block until the scheduled actions have completed.
- (void)stepAll;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACTestScheduler.m
New file
@@ -0,0 +1,223 @@
//
//  RACTestScheduler.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-07-06.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACTestScheduler.h"
#import "RACEXTScope.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACScheduler+Private.h"
@interface RACTestSchedulerAction : NSObject
// The date at which the action should be executed.
//
// This absolute time will not actually be honored. This date is only used for
// comparison, to determine which block should be run _next_.
@property (nonatomic, copy, readonly) NSDate *date;
// The scheduled block.
@property (nonatomic, copy, readonly) void (^block)(void);
// A disposable for this action.
//
// When disposed, the action should not start executing if it hasn't already.
@property (nonatomic, strong, readonly) RACDisposable *disposable;
// Initializes a new scheduler action.
- (id)initWithDate:(NSDate *)date block:(void (^)(void))block;
@end
static CFComparisonResult RACCompareScheduledActions(const void *ptr1, const void *ptr2, void *info) {
    RACTestSchedulerAction *action1 = (__bridge id)ptr1;
    RACTestSchedulerAction *action2 = (__bridge id)ptr2;
    return CFDateCompare((__bridge CFDateRef)action1.date, (__bridge CFDateRef)action2.date, NULL);
}
static const void *RACRetainScheduledAction(CFAllocatorRef allocator, const void *ptr) {
    return CFRetain(ptr);
}
static void RACReleaseScheduledAction(CFAllocatorRef allocator, const void *ptr) {
    CFRelease(ptr);
}
@interface RACTestScheduler ()
// All of the RACTestSchedulerActions that have been enqueued and not yet
// executed.
//
// The minimum value in the heap represents the action to execute next.
//
// This property should only be used while synchronized on self.
@property (nonatomic, assign, readonly) CFBinaryHeapRef scheduledActions;
// The number of blocks that have been directly enqueued with -schedule: so
// far.
//
// This is used to ensure unique dates when two blocks are enqueued
// simultaneously.
//
// This property should only be used while synchronized on self.
@property (nonatomic, assign) NSUInteger numberOfDirectlyScheduledBlocks;
@end
@implementation RACTestScheduler
#pragma mark Lifecycle
- (instancetype)init {
    self = [super initWithName:@"org.reactivecocoa.ReactiveCocoa.RACTestScheduler"];
    if (self == nil) return nil;
    CFBinaryHeapCallBacks callbacks = (CFBinaryHeapCallBacks){
        .version = 0,
        .retain = &RACRetainScheduledAction,
        .release = &RACReleaseScheduledAction,
        .copyDescription = &CFCopyDescription,
        .compare = &RACCompareScheduledActions
    };
    _scheduledActions = CFBinaryHeapCreate(NULL, 0, &callbacks, NULL);
    return self;
}
- (void)dealloc {
    [self stepAll];
    if (_scheduledActions != NULL) {
        CFRelease(_scheduledActions);
        _scheduledActions = NULL;
    }
}
#pragma mark Execution
- (void)step {
    [self step:1];
}
- (void)step:(NSUInteger)ticks {
    @synchronized (self) {
        for (NSUInteger i = 0; i < ticks; i++) {
            const void *actionPtr = NULL;
            if (!CFBinaryHeapGetMinimumIfPresent(self.scheduledActions, &actionPtr)) break;
            RACTestSchedulerAction *action = (__bridge id)actionPtr;
            CFBinaryHeapRemoveMinimumValue(self.scheduledActions);
            if (action.disposable.disposed) continue;
            RACScheduler *previousScheduler = RACScheduler.currentScheduler;
            NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = self;
            action.block();
            if (previousScheduler != nil) {
                NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = previousScheduler;
            } else {
                [NSThread.currentThread.threadDictionary removeObjectForKey:RACSchedulerCurrentSchedulerKey];
            }
        }
    }
}
- (void)stepAll {
    [self step:NSUIntegerMax];
}
#pragma mark RACScheduler
- (RACDisposable *)schedule:(void (^)(void))block {
    NSCParameterAssert(block != nil);
    @synchronized (self) {
        NSDate *uniqueDate = [NSDate dateWithTimeIntervalSinceReferenceDate:self.numberOfDirectlyScheduledBlocks];
        self.numberOfDirectlyScheduledBlocks++;
        RACTestSchedulerAction *action = [[RACTestSchedulerAction alloc] initWithDate:uniqueDate block:block];
        CFBinaryHeapAddValue(self.scheduledActions, (__bridge void *)action);
        return action.disposable;
    }
}
- (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block {
    NSCParameterAssert(date != nil);
    NSCParameterAssert(block != nil);
    @synchronized (self) {
        RACTestSchedulerAction *action = [[RACTestSchedulerAction alloc] initWithDate:date block:block];
        CFBinaryHeapAddValue(self.scheduledActions, (__bridge void *)action);
        return action.disposable;
    }
}
- (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block {
    NSCParameterAssert(date != nil);
    NSCParameterAssert(block != nil);
    NSCParameterAssert(interval >= 0);
    NSCParameterAssert(leeway >= 0);
    RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable];
    @weakify(self);
    @synchronized (self) {
        __block RACDisposable *thisDisposable = nil;
        void (^reschedulingBlock)(void) = ^{
            @strongify(self);
            [compoundDisposable removeDisposable:thisDisposable];
            // Schedule the next interval.
            RACDisposable *schedulingDisposable = [self after:[date dateByAddingTimeInterval:interval] repeatingEvery:interval withLeeway:leeway schedule:block];
            [compoundDisposable addDisposable:schedulingDisposable];
            block();
        };
        RACTestSchedulerAction *action = [[RACTestSchedulerAction alloc] initWithDate:date block:reschedulingBlock];
        CFBinaryHeapAddValue(self.scheduledActions, (__bridge void *)action);
        thisDisposable = action.disposable;
        [compoundDisposable addDisposable:thisDisposable];
    }
    return compoundDisposable;
}
@end
@implementation RACTestSchedulerAction
#pragma mark Lifecycle
- (id)initWithDate:(NSDate *)date block:(void (^)(void))block {
    NSCParameterAssert(date != nil);
    NSCParameterAssert(block != nil);
    self = [super init];
    if (self == nil) return nil;
    _date = [date copy];
    _block = [block copy];
    _disposable = [[RACDisposable alloc] init];
    return self;
}
#pragma mark NSObject
- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: %p>{ date: %@ }", self.class, self, self.date];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACTuple.h
New file
@@ -0,0 +1,159 @@
//
//  RACTuple.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 4/12/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RACmetamacros.h"
@class RACSequence;
/// Creates a new tuple with the given values. At least one value must be given.
/// Values can be nil.
#define RACTuplePack(...) \
    RACTuplePack_(__VA_ARGS__)
/// Declares new object variables and unpacks a RACTuple into them.
///
/// This macro should be used on the left side of an assignment, with the
/// tuple on the right side. Nothing else should appear on the same line, and the
/// macro should not be the only statement in a conditional or loop body.
///
/// If the tuple has more values than there are variables listed, the excess
/// values are ignored.
///
/// If the tuple has fewer values than there are variables listed, the excess
/// variables are initialized to nil.
///
/// Examples
///
///   RACTupleUnpack(NSString *string, NSNumber *num) = [RACTuple tupleWithObjects:@"foo", @5, nil];
///   NSLog(@"string: %@", string);
///   NSLog(@"num: %@", num);
///
///   /* The above is equivalent to: */
///   RACTuple *t = [RACTuple tupleWithObjects:@"foo", @5, nil];
///   NSString *string = t[0];
///   NSNumber *num = t[1];
///   NSLog(@"string: %@", string);
///   NSLog(@"num: %@", num);
#define RACTupleUnpack(...) \
        RACTupleUnpack_(__VA_ARGS__)
/// A sentinel object that represents nils in the tuple.
///
/// It should never be necessary to create a tuple nil yourself. Just use
/// +tupleNil.
@interface RACTupleNil : NSObject <NSCopying, NSCoding>
/// A singleton instance.
+ (RACTupleNil *)tupleNil;
@end
/// A tuple is an ordered collection of objects. It may contain nils, represented
/// by RACTupleNil.
@interface RACTuple : NSObject <NSCoding, NSCopying, NSFastEnumeration>
@property (nonatomic, readonly) NSUInteger count;
/// These properties all return the object at that index or nil if the number of
/// objects is less than the index.
@property (nonatomic, readonly) id first;
@property (nonatomic, readonly) id second;
@property (nonatomic, readonly) id third;
@property (nonatomic, readonly) id fourth;
@property (nonatomic, readonly) id fifth;
@property (nonatomic, readonly) id last;
/// Creates a new tuple out of the array. Does not convert nulls to nils.
+ (instancetype)tupleWithObjectsFromArray:(NSArray *)array;
/// Creates a new tuple out of the array. If `convert` is YES, it also converts
/// every NSNull to RACTupleNil.
+ (instancetype)tupleWithObjectsFromArray:(NSArray *)array convertNullsToNils:(BOOL)convert;
/// Creates a new tuple with the given objects. Use RACTupleNil to represent
/// nils.
+ (instancetype)tupleWithObjects:(id)object, ... NS_REQUIRES_NIL_TERMINATION;
/// Returns the object at `index` or nil if the object is a RACTupleNil. Unlike
/// NSArray and friends, it's perfectly fine to ask for the object at an index
/// past the tuple's count - 1. It will simply return nil.
- (id)objectAtIndex:(NSUInteger)index;
/// Returns an array of all the objects. RACTupleNils are converted to NSNulls.
- (NSArray *)allObjects;
/// Appends `obj` to the receiver.
///
/// obj - The object to add to the tuple. This argument may be nil.
///
/// Returns a new tuple.
- (instancetype)tupleByAddingObject:(id)obj;
@end
@interface RACTuple (RACSequenceAdditions)
/// Returns a sequence of all the objects. RACTupleNils are converted to NSNulls.
@property (nonatomic, copy, readonly) RACSequence *rac_sequence;
@end
@interface RACTuple (ObjectSubscripting)
/// Returns the object at that index or nil if the number of objects is less
/// than the index.
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
@end
/// This and everything below is for internal use only.
///
/// See RACTuplePack() and RACTupleUnpack() instead.
#define RACTuplePack_(...) \
    ([RACTuple tupleWithObjectsFromArray:@[ metamacro_foreach(RACTuplePack_object_or_ractuplenil,, __VA_ARGS__) ]])
#define RACTuplePack_object_or_ractuplenil(INDEX, ARG) \
    (ARG) ?: RACTupleNil.tupleNil,
#define RACTupleUnpack_(...) \
    metamacro_foreach(RACTupleUnpack_decl,, __VA_ARGS__) \
    \
    int RACTupleUnpack_state = 0; \
    \
    RACTupleUnpack_after: \
        ; \
        metamacro_foreach(RACTupleUnpack_assign,, __VA_ARGS__) \
        if (RACTupleUnpack_state != 0) RACTupleUnpack_state = 2; \
        \
        while (RACTupleUnpack_state != 2) \
            if (RACTupleUnpack_state == 1) { \
                goto RACTupleUnpack_after; \
            } else \
                for (; RACTupleUnpack_state != 1; RACTupleUnpack_state = 1) \
                    [RACTupleUnpackingTrampoline trampoline][ @[ metamacro_foreach(RACTupleUnpack_value,, __VA_ARGS__) ] ]
#define RACTupleUnpack_state metamacro_concat(RACTupleUnpack_state, __LINE__)
#define RACTupleUnpack_after metamacro_concat(RACTupleUnpack_after, __LINE__)
#define RACTupleUnpack_loop metamacro_concat(RACTupleUnpack_loop, __LINE__)
#define RACTupleUnpack_decl_name(INDEX) \
    metamacro_concat(metamacro_concat(RACTupleUnpack, __LINE__), metamacro_concat(_var, INDEX))
#define RACTupleUnpack_decl(INDEX, ARG) \
    __strong id RACTupleUnpack_decl_name(INDEX);
#define RACTupleUnpack_assign(INDEX, ARG) \
    __strong ARG = RACTupleUnpack_decl_name(INDEX);
#define RACTupleUnpack_value(INDEX, ARG) \
    [NSValue valueWithPointer:&RACTupleUnpack_decl_name(INDEX)],
@interface RACTupleUnpackingTrampoline : NSObject
+ (instancetype)trampoline;
- (void)setObject:(RACTuple *)tuple forKeyedSubscript:(NSArray *)variables;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACTuple.m
New file
@@ -0,0 +1,252 @@
//
//  RACTuple.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 4/12/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACTuple.h"
#import "RACEXTKeyPathCoding.h"
#import "RACTupleSequence.h"
@implementation RACTupleNil
+ (RACTupleNil *)tupleNil {
    static dispatch_once_t onceToken;
    static RACTupleNil *tupleNil = nil;
    dispatch_once(&onceToken, ^{
        tupleNil = [[self alloc] init];
    });
    return tupleNil;
}
#pragma mark NSCopying
- (id)copyWithZone:(NSZone *)zone {
    return self;
}
#pragma mark NSCoding
- (id)initWithCoder:(NSCoder *)coder {
    // Always return the singleton.
    return self.class.tupleNil;
}
- (void)encodeWithCoder:(NSCoder *)coder {
}
@end
@interface RACTuple ()
@property (nonatomic, strong) NSArray *backingArray;
@end
@implementation RACTuple
- (instancetype)init {
    self = [super init];
    if (self == nil) return nil;
    self.backingArray = [NSArray array];
    return self;
}
- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: %p> %@", self.class, self, self.allObjects];
}
- (BOOL)isEqual:(RACTuple *)object {
    if (object == self) return YES;
    if (![object isKindOfClass:self.class]) return NO;
    return [self.backingArray isEqual:object.backingArray];
}
- (NSUInteger)hash {
    return self.backingArray.hash;
}
#pragma mark NSFastEnumeration
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len {
    return [self.backingArray countByEnumeratingWithState:state objects:buffer count:len];
}
#pragma mark NSCopying
- (instancetype)copyWithZone:(NSZone *)zone {
    // we're immutable, bitches!
    return self;
}
#pragma mark NSCoding
- (id)initWithCoder:(NSCoder *)coder {
    self = [self init];
    if (self == nil) return nil;
    self.backingArray = [coder decodeObjectForKey:@keypath(self.backingArray)];
    return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
    if (self.backingArray != nil) [coder encodeObject:self.backingArray forKey:@keypath(self.backingArray)];
}
#pragma mark API
+ (instancetype)tupleWithObjectsFromArray:(NSArray *)array {
    return [self tupleWithObjectsFromArray:array convertNullsToNils:NO];
}
+ (instancetype)tupleWithObjectsFromArray:(NSArray *)array convertNullsToNils:(BOOL)convert {
    RACTuple *tuple = [[self alloc] init];
    if (convert) {
        NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:array.count];
        for (id object in array) {
            [newArray addObject:(object == NSNull.null ? RACTupleNil.tupleNil : object)];
        }
        tuple.backingArray = newArray;
    } else {
        tuple.backingArray = [array copy];
    }
    return tuple;
}
+ (instancetype)tupleWithObjects:(id)object, ... {
    RACTuple *tuple = [[self alloc] init];
    va_list args;
    va_start(args, object);
    NSUInteger count = 0;
    for (id currentObject = object; currentObject != nil; currentObject = va_arg(args, id)) {
        ++count;
    }
    va_end(args);
    if (count == 0) {
        tuple.backingArray = @[];
        return tuple;
    }
    NSMutableArray *objects = [[NSMutableArray alloc] initWithCapacity:count];
    va_start(args, object);
    for (id currentObject = object; currentObject != nil; currentObject = va_arg(args, id)) {
        [objects addObject:currentObject];
    }
    va_end(args);
    tuple.backingArray = objects;
    return tuple;
}
- (id)objectAtIndex:(NSUInteger)index {
    if (index >= self.count) return nil;
    id object = self.backingArray[index];
    return (object == RACTupleNil.tupleNil ? nil : object);
}
- (NSArray *)allObjects {
    NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:self.backingArray.count];
    for (id object in self.backingArray) {
        [newArray addObject:(object == RACTupleNil.tupleNil ? NSNull.null : object)];
    }
    return newArray;
}
- (instancetype)tupleByAddingObject:(id)obj {
    NSArray *newArray = [self.backingArray arrayByAddingObject:obj ?: RACTupleNil.tupleNil];
    return [self.class tupleWithObjectsFromArray:newArray];
}
- (NSUInteger)count {
    return self.backingArray.count;
}
- (id)first {
    return self[0];
}
- (id)second {
    return self[1];
}
- (id)third {
    return self[2];
}
- (id)fourth {
    return self[3];
}
- (id)fifth {
    return self[4];
}
- (id)last {
    return self[self.count - 1];
}
@end
@implementation RACTuple (RACSequenceAdditions)
- (RACSequence *)rac_sequence {
    return [RACTupleSequence sequenceWithTupleBackingArray:self.backingArray offset:0];
}
@end
@implementation RACTuple (ObjectSubscripting)
- (id)objectAtIndexedSubscript:(NSUInteger)idx {
    return [self objectAtIndex:idx];
}
@end
@implementation RACTupleUnpackingTrampoline
#pragma mark Lifecycle
+ (instancetype)trampoline {
    static dispatch_once_t onceToken;
    static id trampoline = nil;
    dispatch_once(&onceToken, ^{
        trampoline = [[self alloc] init];
    });
    return trampoline;
}
- (void)setObject:(RACTuple *)tuple forKeyedSubscript:(NSArray *)variables {
    NSCParameterAssert(variables != nil);
    [variables enumerateObjectsUsingBlock:^(NSValue *value, NSUInteger index, BOOL *stop) {
        __strong id *ptr = (__strong id *)value.pointerValue;
        *ptr = tuple[index];
    }];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACTupleSequence.h
New file
@@ -0,0 +1,18 @@
//
//  RACTupleSequence.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-05-01.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACSequence.h"
// Private class that adapts a RACTuple to the RACSequence interface.
@interface RACTupleSequence : RACSequence
// Returns a sequence for enumerating over the given backing array (from a
// RACTuple), starting from the given offset.
+ (instancetype)sequenceWithTupleBackingArray:(NSArray *)backingArray offset:(NSUInteger)offset;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACTupleSequence.m
New file
@@ -0,0 +1,68 @@
//
//  RACTupleSequence.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-05-01.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACTupleSequence.h"
#import "RACTuple.h"
@interface RACTupleSequence ()
// The array being sequenced, as taken from RACTuple.backingArray.
@property (nonatomic, strong, readonly) NSArray *tupleBackingArray;
// The index in the array from which the sequence starts.
@property (nonatomic, assign, readonly) NSUInteger offset;
@end
@implementation RACTupleSequence
#pragma mark Lifecycle
+ (instancetype)sequenceWithTupleBackingArray:(NSArray *)backingArray offset:(NSUInteger)offset {
    NSCParameterAssert(offset <= backingArray.count);
    if (offset == backingArray.count) return self.empty;
    RACTupleSequence *seq = [[self alloc] init];
    seq->_tupleBackingArray = backingArray;
    seq->_offset = offset;
    return seq;
}
#pragma mark RACSequence
- (id)head {
    id object = self.tupleBackingArray[self.offset];
    return (object == RACTupleNil.tupleNil ? NSNull.null : object);
}
- (RACSequence *)tail {
    RACSequence *sequence = [self.class sequenceWithTupleBackingArray:self.tupleBackingArray offset:self.offset + 1];
    sequence.name = self.name;
    return sequence;
}
- (NSArray *)array {
    NSRange range = NSMakeRange(self.offset, self.tupleBackingArray.count - self.offset);
    NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:range.length];
    [self.tupleBackingArray enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range] options:0 usingBlock:^(id object, NSUInteger index, BOOL *stop) {
        id mappedObject = (object == RACTupleNil.tupleNil ? NSNull.null : object);
        [array addObject:mappedObject];
    }];
    return array;
}
#pragma mark NSObject
- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: %p>{ name = %@, tuple = %@ }", self.class, self, self.name, self.tupleBackingArray];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACUnarySequence.h
New file
@@ -0,0 +1,14 @@
//
//  RACUnarySequence.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-05-01.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACSequence.h"
// Private class representing a sequence of exactly one value.
@interface RACUnarySequence : RACSequence
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACUnarySequence.m
New file
@@ -0,0 +1,81 @@
//
//  RACUnarySequence.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-05-01.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "RACUnarySequence.h"
#import "RACEXTKeyPathCoding.h"
#import "NSObject+RACDescription.h"
@interface RACUnarySequence ()
// The single value stored in this sequence.
@property (nonatomic, strong, readwrite) id head;
@end
@implementation RACUnarySequence
#pragma mark Properties
@synthesize head = _head;
#pragma mark Lifecycle
+ (instancetype)return:(id)value {
    RACUnarySequence *sequence = [[self alloc] init];
    sequence.head = value;
    return [sequence setNameWithFormat:@"+return: %@", [value rac_description]];
}
#pragma mark RACSequence
- (RACSequence *)tail {
    return nil;
}
- (instancetype)bind:(RACStreamBindBlock (^)(void))block {
    RACStreamBindBlock bindBlock = block();
    BOOL stop = NO;
    RACSequence *result = (id)[bindBlock(self.head, &stop) setNameWithFormat:@"[%@] -bind:", self.name];
    return result ?: self.class.empty;
}
#pragma mark NSCoding
- (Class)classForCoder {
    // Unary sequences should be encoded as themselves, not array sequences.
    return self.class;
}
- (id)initWithCoder:(NSCoder *)coder {
    id value = [coder decodeObjectForKey:@keypath(self.head)];
    return [self.class return:value];
}
- (void)encodeWithCoder:(NSCoder *)coder {
    if (self.head != nil) [coder encodeObject:self.head forKey:@keypath(self.head)];
}
#pragma mark NSObject
- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: %p>{ name = %@, head = %@ }", self.class, self, self.name, self.head];
}
- (NSUInteger)hash {
    return [self.head hash];
}
- (BOOL)isEqual:(RACUnarySequence *)seq {
    if (self == seq) return YES;
    if (![seq isKindOfClass:RACUnarySequence.class]) return NO;
    return self.head == seq.head || [(NSObject *)self.head isEqual:seq.head];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACUnit.h
New file
@@ -0,0 +1,19 @@
//
//  RACUnit.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/27/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
/// A unit represents an empty value.
///
/// It should never be necessary to create a unit yourself. Just use +defaultUnit.
@interface RACUnit : NSObject
/// A singleton instance.
+ (RACUnit *)defaultUnit;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACUnit.m
New file
@@ -0,0 +1,25 @@
//
//  RACUnit.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/27/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACUnit.h"
@implementation RACUnit
#pragma mark API
+ (RACUnit *)defaultUnit {
    static dispatch_once_t onceToken;
    static RACUnit *defaultUnit = nil;
    dispatch_once(&onceToken, ^{
        defaultUnit = [[self alloc] init];
    });
    return defaultUnit;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACValueTransformer.h
New file
@@ -0,0 +1,16 @@
//
//  RACValueTransformer.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/6/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
// A private block based transformer.
@interface RACValueTransformer : NSValueTransformer
+ (instancetype)transformerWithBlock:(id (^)(id value))block;
@end
Pods/ReactiveCocoa/ReactiveCocoa/RACValueTransformer.m
New file
@@ -0,0 +1,42 @@
//
//  RACValueTransformer.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/6/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "RACValueTransformer.h"
@interface RACValueTransformer ()
@property (nonatomic, copy) id (^transformBlock)(id value);
@end
@implementation RACValueTransformer
#pragma mark NSValueTransformer
+ (BOOL)allowsReverseTransformation {
    return NO;
}
- (id)transformedValue:(id)value {
    return self.transformBlock(value);
}
#pragma mark API
@synthesize transformBlock;
+ (instancetype)transformerWithBlock:(id (^)(id value))block {
    NSCParameterAssert(block != NULL);
    RACValueTransformer *transformer = [[self alloc] init];
    transformer.transformBlock = block;
    return transformer;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/ReactiveCocoa.h
New file
@@ -0,0 +1,89 @@
//
//  ReactiveCocoa.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 3/5/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
//! Project version number for ReactiveCocoa.
FOUNDATION_EXPORT double ReactiveCocoaVersionNumber;
//! Project version string for ReactiveCocoa.
FOUNDATION_EXPORT const unsigned char ReactiveCocoaVersionString[];
#import <ReactiveCocoa/RACEXTKeyPathCoding.h>
#import <ReactiveCocoa/RACEXTScope.h>
#import <ReactiveCocoa/NSArray+RACSequenceAdditions.h>
#import <ReactiveCocoa/NSData+RACSupport.h>
#import <ReactiveCocoa/NSDictionary+RACSequenceAdditions.h>
#import <ReactiveCocoa/NSEnumerator+RACSequenceAdditions.h>
#import <ReactiveCocoa/NSFileHandle+RACSupport.h>
#import <ReactiveCocoa/NSNotificationCenter+RACSupport.h>
#import <ReactiveCocoa/NSObject+RACDeallocating.h>
#import <ReactiveCocoa/NSObject+RACLifting.h>
#import <ReactiveCocoa/NSObject+RACPropertySubscribing.h>
#import <ReactiveCocoa/NSObject+RACSelectorSignal.h>
#import <ReactiveCocoa/NSOrderedSet+RACSequenceAdditions.h>
#import <ReactiveCocoa/NSSet+RACSequenceAdditions.h>
#import <ReactiveCocoa/NSString+RACSequenceAdditions.h>
#import <ReactiveCocoa/NSString+RACSupport.h>
#import <ReactiveCocoa/NSIndexSet+RACSequenceAdditions.h>
#import <ReactiveCocoa/NSURLConnection+RACSupport.h>
#import <ReactiveCocoa/NSUserDefaults+RACSupport.h>
#import <ReactiveCocoa/RACBehaviorSubject.h>
#import <ReactiveCocoa/RACChannel.h>
#import <ReactiveCocoa/RACCommand.h>
#import <ReactiveCocoa/RACCompoundDisposable.h>
#import <ReactiveCocoa/RACDisposable.h>
#import <ReactiveCocoa/RACEvent.h>
#import <ReactiveCocoa/RACGroupedSignal.h>
#import <ReactiveCocoa/RACKVOChannel.h>
#import <ReactiveCocoa/RACMulticastConnection.h>
#import <ReactiveCocoa/RACQueueScheduler.h>
#import <ReactiveCocoa/RACQueueScheduler+Subclass.h>
#import <ReactiveCocoa/RACReplaySubject.h>
#import <ReactiveCocoa/RACScheduler.h>
#import <ReactiveCocoa/RACScheduler+Subclass.h>
#import <ReactiveCocoa/RACScopedDisposable.h>
#import <ReactiveCocoa/RACSequence.h>
#import <ReactiveCocoa/RACSerialDisposable.h>
#import <ReactiveCocoa/RACSignal+Operations.h>
#import <ReactiveCocoa/RACSignal.h>
#import <ReactiveCocoa/RACStream.h>
#import <ReactiveCocoa/RACSubject.h>
#import <ReactiveCocoa/RACSubscriber.h>
#import <ReactiveCocoa/RACSubscriptingAssignmentTrampoline.h>
#import <ReactiveCocoa/RACTargetQueueScheduler.h>
#import <ReactiveCocoa/RACTestScheduler.h>
#import <ReactiveCocoa/RACTuple.h>
#import <ReactiveCocoa/RACUnit.h>
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
    #import <ReactiveCocoa/MKAnnotationView+RACSignalSupport.h>
    #import <ReactiveCocoa/UIActionSheet+RACSignalSupport.h>
    #import <ReactiveCocoa/UIAlertView+RACSignalSupport.h>
    #import <ReactiveCocoa/UIBarButtonItem+RACCommandSupport.h>
    #import <ReactiveCocoa/UIButton+RACCommandSupport.h>
    #import <ReactiveCocoa/UICollectionReusableView+RACSignalSupport.h>
    #import <ReactiveCocoa/UIControl+RACSignalSupport.h>
    #import <ReactiveCocoa/UIDatePicker+RACSignalSupport.h>
    #import <ReactiveCocoa/UIGestureRecognizer+RACSignalSupport.h>
    #import <ReactiveCocoa/UIImagePickerController+RACSignalSupport.h>
    #import <ReactiveCocoa/UIRefreshControl+RACCommandSupport.h>
    #import <ReactiveCocoa/UISegmentedControl+RACSignalSupport.h>
    #import <ReactiveCocoa/UISlider+RACSignalSupport.h>
    #import <ReactiveCocoa/UIStepper+RACSignalSupport.h>
    #import <ReactiveCocoa/UISwitch+RACSignalSupport.h>
    #import <ReactiveCocoa/UITableViewCell+RACSignalSupport.h>
    #import <ReactiveCocoa/UITableViewHeaderFooterView+RACSignalSupport.h>
    #import <ReactiveCocoa/UITextField+RACSignalSupport.h>
    #import <ReactiveCocoa/UITextView+RACSignalSupport.h>
#elif TARGET_OS_MAC
    #import <ReactiveCocoa/NSControl+RACCommandSupport.h>
    #import <ReactiveCocoa/NSControl+RACTextSignalSupport.h>
    #import <ReactiveCocoa/NSObject+RACAppKitBindings.h>
    #import <ReactiveCocoa/NSText+RACSignalSupport.h>
#endif
Pods/ReactiveCocoa/ReactiveCocoa/UIActionSheet+RACSignalSupport.h
New file
@@ -0,0 +1,32 @@
//
//  UIActionSheet+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Dave Lee on 2013-06-22.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACDelegateProxy;
@class RACSignal;
@interface UIActionSheet (RACSignalSupport)
/// A delegate proxy which will be set as the receiver's delegate when any of the
/// methods in this category are used.
@property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy;
/// Creates a signal for button clicks on the receiver.
///
/// When this method is invoked, the `rac_delegateProxy` will become the
/// receiver's delegate. Any previous delegate will become the -[RACDelegateProxy
/// rac_proxiedDelegate], so that it receives any messages that the proxy doesn't
/// know how to handle. Setting the receiver's `delegate` afterward is
/// considered undefined behavior.
///
/// Returns a signal which will send the index of the specific button clicked.
/// The signal will complete when the receiver is deallocated.
- (RACSignal *)rac_buttonClickedSignal;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIActionSheet+RACSignalSupport.m
New file
@@ -0,0 +1,49 @@
//
//  UIActionSheet+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Dave Lee on 2013-06-22.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UIActionSheet+RACSignalSupport.h"
#import "RACDelegateProxy.h"
#import "RACSignal+Operations.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACDescription.h"
#import <objc/runtime.h>
@implementation UIActionSheet (RACSignalSupport)
static void RACUseDelegateProxy(UIActionSheet *self) {
    if (self.delegate == self.rac_delegateProxy) return;
    self.rac_delegateProxy.rac_proxiedDelegate = self.delegate;
    self.delegate = (id)self.rac_delegateProxy;
}
- (RACDelegateProxy *)rac_delegateProxy {
    RACDelegateProxy *proxy = objc_getAssociatedObject(self, _cmd);
    if (proxy == nil) {
        proxy = [[RACDelegateProxy alloc] initWithProtocol:@protocol(UIActionSheetDelegate)];
        objc_setAssociatedObject(self, _cmd, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return proxy;
}
- (RACSignal *)rac_buttonClickedSignal {
    RACSignal *signal = [[[[self.rac_delegateProxy
        signalForSelector:@selector(actionSheet:clickedButtonAtIndex:)]
        reduceEach:^(UIActionSheet *actionSheet, NSNumber *buttonIndex) {
            return buttonIndex;
        }]
        takeUntil:self.rac_willDeallocSignal]
        setNameWithFormat:@"%@ -rac_buttonClickedSignal", self.rac_description];
    RACUseDelegateProxy(self);
    return signal;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIAlertView+RACSignalSupport.h
New file
@@ -0,0 +1,47 @@
//
//  UIAlertView+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Henrik Hodne on 6/16/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACDelegateProxy;
@class RACSignal;
@interface UIAlertView (RACSignalSupport)
/// A delegate proxy which will be set as the receiver's delegate when any of the
/// methods in this category are used.
@property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy;
/// Creates a signal for button clicks on the receiver.
///
/// When this method is invoked, the `rac_delegateProxy` will become the
/// receiver's delegate. Any previous delegate will become the -[RACDelegateProxy
/// rac_proxiedDelegate], so that it receives any messages that the proxy doesn't
/// know how to handle. Setting the receiver's `delegate` afterward is considered
/// undefined behavior.
///
/// Note that this signal will not send a value when the alert is dismissed
/// programatically.
///
/// Returns a signal which will send the index of the specific button clicked.
/// The signal will complete itself when the receiver is deallocated.
- (RACSignal *)rac_buttonClickedSignal;
/// Creates a signal for dismissal of the receiver.
///
/// When this method is invoked, the `rac_delegateProxy` will become the
/// receiver's delegate. Any previous delegate will become the -[RACDelegateProxy
/// rac_proxiedDelegate], so that it receives any messages that the proxy doesn't
/// know how to handle. Setting the receiver's `delegate` afterward is considered
/// undefined behavior.
///
/// Returns a signal which will send the index of the button associated with the
/// dismissal. The signal will complete itself when the receiver is deallocated.
- (RACSignal *)rac_willDismissSignal;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIAlertView+RACSignalSupport.m
New file
@@ -0,0 +1,63 @@
//
//  UIAlertView+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Henrik Hodne on 6/16/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UIAlertView+RACSignalSupport.h"
#import "RACDelegateProxy.h"
#import "RACSignal+Operations.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACDescription.h"
#import <objc/runtime.h>
@implementation UIAlertView (RACSignalSupport)
static void RACUseDelegateProxy(UIAlertView *self) {
    if (self.delegate == self.rac_delegateProxy) return;
    self.rac_delegateProxy.rac_proxiedDelegate = self.delegate;
    self.delegate = (id)self.rac_delegateProxy;
}
- (RACDelegateProxy *)rac_delegateProxy {
    RACDelegateProxy *proxy = objc_getAssociatedObject(self, _cmd);
    if (proxy == nil) {
        proxy = [[RACDelegateProxy alloc] initWithProtocol:@protocol(UIAlertViewDelegate)];
        objc_setAssociatedObject(self, _cmd, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return proxy;
}
- (RACSignal *)rac_buttonClickedSignal {
    RACSignal *signal = [[[[self.rac_delegateProxy
        signalForSelector:@selector(alertView:clickedButtonAtIndex:)]
        reduceEach:^(UIAlertView *alertView, NSNumber *buttonIndex) {
            return buttonIndex;
        }]
        takeUntil:self.rac_willDeallocSignal]
        setNameWithFormat:@"%@ -rac_buttonClickedSignal", self.rac_description];
    RACUseDelegateProxy(self);
    return signal;
}
- (RACSignal *)rac_willDismissSignal {
    RACSignal *signal = [[[[self.rac_delegateProxy
        signalForSelector:@selector(alertView:willDismissWithButtonIndex:)]
        reduceEach:^(UIAlertView *alertView, NSNumber *buttonIndex) {
            return buttonIndex;
        }]
        takeUntil:self.rac_willDeallocSignal]
        setNameWithFormat:@"%@ -rac_willDismissSignal", self.rac_description];
    RACUseDelegateProxy(self);
    return signal;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIBarButtonItem+RACCommandSupport.h
New file
@@ -0,0 +1,22 @@
//
//  UIBarButtonItem+RACCommandSupport.h
//  ReactiveCocoa
//
//  Created by Kyle LeNeau on 3/27/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACCommand;
@interface UIBarButtonItem (RACCommandSupport)
/// Sets the control's command. When the control is clicked, the command is
/// executed with the sender of the event. The control's enabledness is bound
/// to the command's `canExecute`.
///
/// Note: this will reset the control's target and action.
@property (nonatomic, strong) RACCommand *rac_command;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIBarButtonItem+RACCommandSupport.m
New file
@@ -0,0 +1,54 @@
//
//  UIBarButtonItem+RACCommandSupport.m
//  ReactiveCocoa
//
//  Created by Kyle LeNeau on 3/27/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UIBarButtonItem+RACCommandSupport.h"
#import "RACEXTKeyPathCoding.h"
#import "RACCommand.h"
#import "RACDisposable.h"
#import "RACSignal+Operations.h"
#import <objc/runtime.h>
static void *UIControlRACCommandKey = &UIControlRACCommandKey;
static void *UIControlEnabledDisposableKey = &UIControlEnabledDisposableKey;
@implementation UIBarButtonItem (RACCommandSupport)
- (RACCommand *)rac_command {
    return objc_getAssociatedObject(self, UIControlRACCommandKey);
}
- (void)setRac_command:(RACCommand *)command {
    objc_setAssociatedObject(self, UIControlRACCommandKey, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    // Check for stored signal in order to remove it and add a new one
    RACDisposable *disposable = objc_getAssociatedObject(self, UIControlEnabledDisposableKey);
    [disposable dispose];
    if (command == nil) return;
    disposable = [command.enabled setKeyPath:@keypath(self.enabled) onObject:self];
    objc_setAssociatedObject(self, UIControlEnabledDisposableKey, disposable, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [self rac_hijackActionAndTargetIfNeeded];
}
- (void)rac_hijackActionAndTargetIfNeeded {
    SEL hijackSelector = @selector(rac_commandPerformAction:);
    if (self.target == self && self.action == hijackSelector) return;
    if (self.target != nil) NSLog(@"WARNING: UIBarButtonItem.rac_command hijacks the control's existing target and action.");
    self.target = self;
    self.action = hijackSelector;
}
- (void)rac_commandPerformAction:(id)sender {
    [self.rac_command execute:sender];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIButton+RACCommandSupport.h
New file
@@ -0,0 +1,20 @@
//
//  UIButton+RACCommandSupport.h
//  ReactiveCocoa
//
//  Created by Ash Furrow on 2013-06-06.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACCommand;
@interface UIButton (RACCommandSupport)
/// Sets the button's command. When the button is clicked, the command is
/// executed with the sender of the event. The button's enabledness is bound
/// to the command's `canExecute`.
@property (nonatomic, strong) RACCommand *rac_command;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIButton+RACCommandSupport.m
New file
@@ -0,0 +1,56 @@
//
//  UIButton+RACCommandSupport.m
//  ReactiveCocoa
//
//  Created by Ash Furrow on 2013-06-06.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UIButton+RACCommandSupport.h"
#import "RACEXTKeyPathCoding.h"
#import "RACCommand.h"
#import "RACDisposable.h"
#import "RACSignal+Operations.h"
#import <objc/runtime.h>
static void *UIButtonRACCommandKey = &UIButtonRACCommandKey;
static void *UIButtonEnabledDisposableKey = &UIButtonEnabledDisposableKey;
@implementation UIButton (RACCommandSupport)
- (RACCommand *)rac_command {
    return objc_getAssociatedObject(self, UIButtonRACCommandKey);
}
- (void)setRac_command:(RACCommand *)command {
    objc_setAssociatedObject(self, UIButtonRACCommandKey, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    // Check for stored signal in order to remove it and add a new one
    RACDisposable *disposable = objc_getAssociatedObject(self, UIButtonEnabledDisposableKey);
    [disposable dispose];
    if (command == nil) return;
    disposable = [command.enabled setKeyPath:@keypath(self.enabled) onObject:self];
    objc_setAssociatedObject(self, UIButtonEnabledDisposableKey, disposable, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [self rac_hijackActionAndTargetIfNeeded];
}
- (void)rac_hijackActionAndTargetIfNeeded {
    SEL hijackSelector = @selector(rac_commandPerformAction:);
    for (NSString *selector in [self actionsForTarget:self forControlEvent:UIControlEventTouchUpInside]) {
        if (hijackSelector == NSSelectorFromString(selector)) {
            return;
        }
    }
    [self addTarget:self action:hijackSelector forControlEvents:UIControlEventTouchUpInside];
}
- (void)rac_commandPerformAction:(id)sender {
    [self.rac_command execute:sender];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UICollectionReusableView+RACSignalSupport.h
New file
@@ -0,0 +1,29 @@
//
//  UICollectionReusableView+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Kent Wong on 2013-10-04.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACSignal;
// This category is only applicable to iOS >= 6.0.
@interface UICollectionReusableView (RACSignalSupport)
/// A signal which will send a RACUnit whenever -prepareForReuse is invoked upon
/// the receiver.
///
/// Examples
///
///  [[[self.cancelButton
///     rac_signalForControlEvents:UIControlEventTouchUpInside]
///     takeUntil:self.rac_prepareForReuseSignal]
///     subscribeNext:^(UIButton *x) {
///         // do other things
///     }];
@property (nonatomic, strong, readonly) RACSignal *rac_prepareForReuseSignal;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UICollectionReusableView+RACSignalSupport.m
New file
@@ -0,0 +1,31 @@
//
//  UICollectionReusableView+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Kent Wong on 2013-10-04.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UICollectionReusableView+RACSignalSupport.h"
#import "NSObject+RACDescription.h"
#import "NSObject+RACSelectorSignal.h"
#import "RACSignal+Operations.h"
#import "RACUnit.h"
#import <objc/runtime.h>
@implementation UICollectionReusableView (RACSignalSupport)
- (RACSignal *)rac_prepareForReuseSignal {
    RACSignal *signal = objc_getAssociatedObject(self, _cmd);
    if (signal != nil) return signal;
    signal = [[[self
        rac_signalForSelector:@selector(prepareForReuse)]
        mapReplace:RACUnit.defaultUnit]
        setNameWithFormat:@"%@ -rac_prepareForReuseSignal", self.rac_description];
    objc_setAssociatedObject(self, _cmd, signal, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    return signal;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIControl+RACSignalSupport.h
New file
@@ -0,0 +1,19 @@
//
//  UIControl+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 4/17/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACSignal;
@interface UIControl (RACSignalSupport)
/// Creates and returns a signal that sends the sender of the control event
/// whenever one of the control events is triggered.
- (RACSignal *)rac_signalForControlEvents:(UIControlEvents)controlEvents;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIControl+RACSignalSupport.m
New file
@@ -0,0 +1,40 @@
//
//  UIControl+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 4/17/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "UIControl+RACSignalSupport.h"
#import "RACEXTScope.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACSignal.h"
#import "RACSubscriber.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACDescription.h"
@implementation UIControl (RACSignalSupport)
- (RACSignal *)rac_signalForControlEvents:(UIControlEvents)controlEvents {
    @weakify(self);
    return [[RACSignal
        createSignal:^(id<RACSubscriber> subscriber) {
            @strongify(self);
            [self addTarget:subscriber action:@selector(sendNext:) forControlEvents:controlEvents];
            [self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
                [subscriber sendCompleted];
            }]];
            return [RACDisposable disposableWithBlock:^{
                @strongify(self);
                [self removeTarget:subscriber action:@selector(sendNext:) forControlEvents:controlEvents];
            }];
        }]
        setNameWithFormat:@"%@ -rac_signalForControlEvents: %lx", self.rac_description, (unsigned long)controlEvents];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIControl+RACSignalSupportPrivate.h
New file
@@ -0,0 +1,29 @@
//
//  UIControl+RACSignalSupportPrivate.h
//  ReactiveCocoa
//
//  Created by Uri Baghin on 06/08/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACChannelTerminal;
@interface UIControl (RACSignalSupportPrivate)
// Adds a RACChannel-based interface to the receiver for the given
// UIControlEvents and exposes it.
//
// controlEvents - A mask of UIControlEvents on which to send new values.
// key           - The key whose value should be read and set when a control
//                 event fires and when a value is sent to the
//                 RACChannelTerminal respectively.
// nilValue      - The value to be assigned to the key when `nil` is sent to the
//                 RACChannelTerminal.
//
// Returns a RACChannelTerminal which will send future values from the receiver,
// and update the receiver when values are sent to the terminal.
- (RACChannelTerminal *)rac_channelForControlEvents:(UIControlEvents)controlEvents key:(NSString *)key nilValue:(id)nilValue;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIControl+RACSignalSupportPrivate.m
New file
@@ -0,0 +1,48 @@
//
//  UIControl+RACSignalSupportPrivate.m
//  ReactiveCocoa
//
//  Created by Uri Baghin on 06/08/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UIControl+RACSignalSupportPrivate.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACLifting.h"
#import "RACChannel.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACSignal+Operations.h"
#import "UIControl+RACSignalSupport.h"
@implementation UIControl (RACSignalSupportPrivate)
- (RACChannelTerminal *)rac_channelForControlEvents:(UIControlEvents)controlEvents key:(NSString *)key nilValue:(id)nilValue {
    NSCParameterAssert(key.length > 0);
    key = [key copy];
    RACChannel *channel = [[RACChannel alloc] init];
    [self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
        [channel.followingTerminal sendCompleted];
    }]];
    RACSignal *eventSignal = [[[self
        rac_signalForControlEvents:controlEvents]
        mapReplace:key]
        takeUntil:[[channel.followingTerminal
            ignoreValues]
            catchTo:RACSignal.empty]];
    [[self
        rac_liftSelector:@selector(valueForKey:) withSignals:eventSignal, nil]
        subscribe:channel.followingTerminal];
    RACSignal *valuesSignal = [channel.followingTerminal
        map:^(id value) {
            return value ?: nilValue;
        }];
    [self rac_liftSelector:@selector(setValue:forKey:) withSignals:valuesSignal, [RACSignal return:key], nil];
    return channel.leadingTerminal;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIDatePicker+RACSignalSupport.h
New file
@@ -0,0 +1,24 @@
//
//  UIDatePicker+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Uri Baghin on 20/07/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACChannelTerminal;
@interface UIDatePicker (RACSignalSupport)
/// Creates a new RACChannel-based binding to the receiver.
///
/// nilValue - The date to set when the terminal receives `nil`.
///
/// Returns a RACChannelTerminal that sends the receiver's date whenever the
/// UIControlEventValueChanged control event is fired, and sets the date to the
/// values it receives.
- (RACChannelTerminal *)rac_newDateChannelWithNilValue:(NSDate *)nilValue;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIDatePicker+RACSignalSupport.m
New file
@@ -0,0 +1,19 @@
//
//  UIDatePicker+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Uri Baghin on 20/07/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UIDatePicker+RACSignalSupport.h"
#import "RACEXTKeyPathCoding.h"
#import "UIControl+RACSignalSupportPrivate.h"
@implementation UIDatePicker (RACSignalSupport)
- (RACChannelTerminal *)rac_newDateChannelWithNilValue:(NSDate *)nilValue {
    return [self rac_channelForControlEvents:UIControlEventValueChanged key:@keypath(self.date) nilValue:nilValue];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIGestureRecognizer+RACSignalSupport.h
New file
@@ -0,0 +1,18 @@
//
//  UIGestureRecognizer+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Josh Vera on 5/5/13.
//  Copyright (c) 2013 GitHub. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACSignal;
@interface UIGestureRecognizer (RACSignalSupport)
/// Returns a signal that sends the receiver when its gesture occurs.
- (RACSignal *)rac_gestureSignal;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIGestureRecognizer+RACSignalSupport.m
New file
@@ -0,0 +1,40 @@
//
//  UIGestureRecognizer+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Josh Vera on 5/5/13.
//  Copyright (c) 2013 GitHub. All rights reserved.
//
#import "UIGestureRecognizer+RACSignalSupport.h"
#import "RACEXTScope.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACDescription.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACSignal.h"
#import "RACSubscriber.h"
@implementation UIGestureRecognizer (RACSignalSupport)
- (RACSignal *)rac_gestureSignal {
    @weakify(self);
    return [[RACSignal
        createSignal:^(id<RACSubscriber> subscriber) {
            @strongify(self);
            [self addTarget:subscriber action:@selector(sendNext:)];
            [self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
                [subscriber sendCompleted];
            }]];
            return [RACDisposable disposableWithBlock:^{
                @strongify(self);
                [self removeTarget:subscriber action:@selector(sendNext:)];
            }];
        }]
        setNameWithFormat:@"%@ -rac_gestureSignal", self.rac_description];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIImagePickerController+RACSignalSupport.h
New file
@@ -0,0 +1,33 @@
//
//  UIImagePickerController+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Timur Kuchkarov on 28.03.14.
//  Copyright (c) 2014 GitHub. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACDelegateProxy;
@class RACSignal;
@interface UIImagePickerController (RACSignalSupport)
/// A delegate proxy which will be set as the receiver's delegate when any of the
/// methods in this category are used.
@property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy;
/// Creates a signal for every new selected image.
///
/// When this method is invoked, the `rac_delegateProxy` will become the
/// receiver's delegate. Any previous delegate will become the -[RACDelegateProxy
/// rac_proxiedDelegate], so that it receives any messages that the proxy doesn't
/// know how to handle. Setting the receiver's `delegate` afterward is considered
/// undefined behavior.
///
/// Returns a signal which will send the dictionary with info for the selected image.
/// Caller is responsible for picker controller dismissal. The signal will complete
/// itself when the receiver is deallocated or when user cancels selection.
- (RACSignal *)rac_imageSelectedSignal;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIImagePickerController+RACSignalSupport.m
New file
@@ -0,0 +1,53 @@
//
//  UIImagePickerController+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Timur Kuchkarov on 28.03.14.
//  Copyright (c) 2014 GitHub. All rights reserved.
//
#import "UIImagePickerController+RACSignalSupport.h"
#import "RACDelegateProxy.h"
#import "RACSignal+Operations.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACDescription.h"
#import <objc/runtime.h>
@implementation UIImagePickerController (RACSignalSupport)
static void RACUseDelegateProxy(UIImagePickerController *self) {
    if (self.delegate == self.rac_delegateProxy) return;
    self.rac_delegateProxy.rac_proxiedDelegate = self.delegate;
    self.delegate = (id)self.rac_delegateProxy;
}
- (RACDelegateProxy *)rac_delegateProxy {
    RACDelegateProxy *proxy = objc_getAssociatedObject(self, _cmd);
    if (proxy == nil) {
        proxy = [[RACDelegateProxy alloc] initWithProtocol:@protocol(UIImagePickerControllerDelegate)];
        objc_setAssociatedObject(self, _cmd, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return proxy;
}
- (RACSignal *)rac_imageSelectedSignal {
    RACSignal *pickerCancelledSignal = [[self.rac_delegateProxy
        signalForSelector:@selector(imagePickerControllerDidCancel:)]
        merge:self.rac_willDeallocSignal];
    RACSignal *imagePickerSignal = [[[[self.rac_delegateProxy
        signalForSelector:@selector(imagePickerController:didFinishPickingMediaWithInfo:)]
        reduceEach:^(UIImagePickerController *pickerController, NSDictionary *userInfo) {
            return userInfo;
        }]
        takeUntil:pickerCancelledSignal]
        setNameWithFormat:@"%@ -rac_imageSelectedSignal", self.rac_description];
    RACUseDelegateProxy(self);
    return imagePickerSignal;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIRefreshControl+RACCommandSupport.h
New file
@@ -0,0 +1,22 @@
//
//  UIRefreshControl+RACCommandSupport.h
//  ReactiveCocoa
//
//  Created by Dave Lee on 2013-10-17.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACCommand;
@interface UIRefreshControl (RACCommandSupport)
/// Manipulate the RACCommand property associated with this refresh control.
///
/// When this refresh control is activated by the user, the command will be
/// executed. Upon completion or error of the execution signal, -endRefreshing
/// will be invoked.
@property (nonatomic, strong) RACCommand *rac_command;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIRefreshControl+RACCommandSupport.m
New file
@@ -0,0 +1,58 @@
//
//  UIRefreshControl+RACCommandSupport.m
//  ReactiveCocoa
//
//  Created by Dave Lee on 2013-10-17.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UIRefreshControl+RACCommandSupport.h"
#import "RACEXTKeyPathCoding.h"
#import "RACCommand.h"
#import "RACCompoundDisposable.h"
#import "RACDisposable.h"
#import "RACSignal.h"
#import "RACSignal+Operations.h"
#import "UIControl+RACSignalSupport.h"
#import <objc/runtime.h>
static void *UIRefreshControlRACCommandKey = &UIRefreshControlRACCommandKey;
static void *UIRefreshControlDisposableKey = &UIRefreshControlDisposableKey;
@implementation UIRefreshControl (RACCommandSupport)
- (RACCommand *)rac_command {
    return objc_getAssociatedObject(self, UIRefreshControlRACCommandKey);
}
- (void)setRac_command:(RACCommand *)command {
    objc_setAssociatedObject(self, UIRefreshControlRACCommandKey, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    // Dispose of any active command associations.
    [objc_getAssociatedObject(self, UIRefreshControlDisposableKey) dispose];
    if (command == nil) return;
    // Like RAC(self, enabled) = command.enabled; but with access to disposable.
    RACDisposable *enabledDisposable = [command.enabled setKeyPath:@keypath(self.enabled) onObject:self];
    RACDisposable *executionDisposable = [[[[self
        rac_signalForControlEvents:UIControlEventValueChanged]
        map:^(UIRefreshControl *x) {
            return [[[command
                execute:x]
                catchTo:[RACSignal empty]]
                then:^{
                    return [RACSignal return:x];
                }];
        }]
        concat]
        subscribeNext:^(UIRefreshControl *x) {
            [x endRefreshing];
        }];
    RACDisposable *commandDisposable = [RACCompoundDisposable compoundDisposableWithDisposables:@[ enabledDisposable, executionDisposable ]];
    objc_setAssociatedObject(self, UIRefreshControlDisposableKey, commandDisposable, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UISegmentedControl+RACSignalSupport.h
New file
@@ -0,0 +1,24 @@
//
//  UISegmentedControl+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Uri Baghin on 20/07/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACChannelTerminal;
@interface UISegmentedControl (RACSignalSupport)
/// Creates a new RACChannel-based binding to the receiver.
///
/// nilValue - The segment to select when the terminal receives `nil`.
///
/// Returns a RACChannelTerminal that sends the receiver's currently selected
/// segment's index whenever the UIControlEventValueChanged control event is
/// fired, and sets the selected segment index to the values it receives.
- (RACChannelTerminal *)rac_newSelectedSegmentIndexChannelWithNilValue:(NSNumber *)nilValue;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UISegmentedControl+RACSignalSupport.m
New file
@@ -0,0 +1,19 @@
//
//  UISegmentedControl+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Uri Baghin on 20/07/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UISegmentedControl+RACSignalSupport.h"
#import "RACEXTKeyPathCoding.h"
#import "UIControl+RACSignalSupportPrivate.h"
@implementation UISegmentedControl (RACSignalSupport)
- (RACChannelTerminal *)rac_newSelectedSegmentIndexChannelWithNilValue:(NSNumber *)nilValue {
    return [self rac_channelForControlEvents:UIControlEventValueChanged key:@keypath(self.selectedSegmentIndex) nilValue:nilValue];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UISlider+RACSignalSupport.h
New file
@@ -0,0 +1,24 @@
//
//  UISlider+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Uri Baghin on 20/07/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACChannelTerminal;
@interface UISlider (RACSignalSupport)
/// Creates a new RACChannel-based binding to the receiver.
///
/// nilValue - The value to set when the terminal receives `nil`.
///
/// Returns a RACChannelTerminal that sends the receiver's value whenever the
/// UIControlEventValueChanged control event is fired, and sets the value to the
/// values it receives.
- (RACChannelTerminal *)rac_newValueChannelWithNilValue:(NSNumber *)nilValue;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UISlider+RACSignalSupport.m
New file
@@ -0,0 +1,19 @@
//
//  UISlider+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Uri Baghin on 20/07/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UISlider+RACSignalSupport.h"
#import "RACEXTKeyPathCoding.h"
#import "UIControl+RACSignalSupportPrivate.h"
@implementation UISlider (RACSignalSupport)
- (RACChannelTerminal *)rac_newValueChannelWithNilValue:(NSNumber *)nilValue {
    return [self rac_channelForControlEvents:UIControlEventValueChanged key:@keypath(self.value) nilValue:nilValue];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIStepper+RACSignalSupport.h
New file
@@ -0,0 +1,24 @@
//
//  UIStepper+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Uri Baghin on 20/07/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACChannelTerminal;
@interface UIStepper (RACSignalSupport)
/// Creates a new RACChannel-based binding to the receiver.
///
/// nilValue - The value to set when the terminal receives `nil`.
///
/// Returns a RACChannelTerminal that sends the receiver's value whenever the
/// UIControlEventValueChanged control event is fired, and sets the value to the
/// values it receives.
- (RACChannelTerminal *)rac_newValueChannelWithNilValue:(NSNumber *)nilValue;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UIStepper+RACSignalSupport.m
New file
@@ -0,0 +1,19 @@
//
//  UIStepper+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Uri Baghin on 20/07/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UIStepper+RACSignalSupport.h"
#import "RACEXTKeyPathCoding.h"
#import "UIControl+RACSignalSupportPrivate.h"
@implementation UIStepper (RACSignalSupport)
- (RACChannelTerminal *)rac_newValueChannelWithNilValue:(NSNumber *)nilValue {
    return [self rac_channelForControlEvents:UIControlEventValueChanged key:@keypath(self.value) nilValue:nilValue];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UISwitch+RACSignalSupport.h
New file
@@ -0,0 +1,22 @@
//
//  UISwitch+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Uri Baghin on 20/07/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACChannelTerminal;
@interface UISwitch (RACSignalSupport)
/// Creates a new RACChannel-based binding to the receiver.
///
/// Returns a RACChannelTerminal that sends whether the receiver is on whenever
/// the UIControlEventValueChanged control event is fired, and sets it on or off
/// when it receives @YES or @NO respectively.
- (RACChannelTerminal *)rac_newOnChannel;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UISwitch+RACSignalSupport.m
New file
@@ -0,0 +1,19 @@
//
//  UISwitch+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Uri Baghin on 20/07/2013.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UISwitch+RACSignalSupport.h"
#import "RACEXTKeyPathCoding.h"
#import "UIControl+RACSignalSupportPrivate.h"
@implementation UISwitch (RACSignalSupport)
- (RACChannelTerminal *)rac_newOnChannel {
    return [self rac_channelForControlEvents:UIControlEventValueChanged key:@keypath(self.on) nilValue:@NO];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UITableViewCell+RACSignalSupport.h
New file
@@ -0,0 +1,28 @@
//
//  UITableViewCell+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-07-22.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACSignal;
@interface UITableViewCell (RACSignalSupport)
/// A signal which will send a RACUnit whenever -prepareForReuse is invoked upon
/// the receiver.
///
/// Examples
///
///  [[[self.cancelButton
///     rac_signalForControlEvents:UIControlEventTouchUpInside]
///     takeUntil:self.rac_prepareForReuseSignal]
///     subscribeNext:^(UIButton *x) {
///         // do other things
///     }];
@property (nonatomic, strong, readonly) RACSignal *rac_prepareForReuseSignal;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UITableViewCell+RACSignalSupport.m
New file
@@ -0,0 +1,31 @@
//
//  UITableViewCell+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Justin Spahr-Summers on 2013-07-22.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UITableViewCell+RACSignalSupport.h"
#import "NSObject+RACDescription.h"
#import "NSObject+RACSelectorSignal.h"
#import "RACSignal+Operations.h"
#import "RACUnit.h"
#import <objc/runtime.h>
@implementation UITableViewCell (RACSignalSupport)
- (RACSignal *)rac_prepareForReuseSignal {
    RACSignal *signal = objc_getAssociatedObject(self, _cmd);
    if (signal != nil) return signal;
    signal = [[[self
        rac_signalForSelector:@selector(prepareForReuse)]
        mapReplace:RACUnit.defaultUnit]
        setNameWithFormat:@"%@ -rac_prepareForReuseSignal", self.rac_description];
    objc_setAssociatedObject(self, _cmd, signal, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    return signal;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UITableViewHeaderFooterView+RACSignalSupport.h
New file
@@ -0,0 +1,29 @@
//
//  UITableViewHeaderFooterView+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Syo Ikeda on 12/30/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACSignal;
// This category is only applicable to iOS >= 6.0.
@interface UITableViewHeaderFooterView (RACSignalSupport)
/// A signal which will send a RACUnit whenever -prepareForReuse is invoked upon
/// the receiver.
///
/// Examples
///
///  [[[self.cancelButton
///     rac_signalForControlEvents:UIControlEventTouchUpInside]
///     takeUntil:self.rac_prepareForReuseSignal]
///     subscribeNext:^(UIButton *x) {
///         // do other things
///     }];
@property (nonatomic, strong, readonly) RACSignal *rac_prepareForReuseSignal;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UITableViewHeaderFooterView+RACSignalSupport.m
New file
@@ -0,0 +1,31 @@
//
//  UITableViewHeaderFooterView+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Syo Ikeda on 12/30/13.
//  Copyright (c) 2013 GitHub, Inc. All rights reserved.
//
#import "UITableViewHeaderFooterView+RACSignalSupport.h"
#import "NSObject+RACDescription.h"
#import "NSObject+RACSelectorSignal.h"
#import "RACSignal+Operations.h"
#import "RACUnit.h"
#import <objc/runtime.h>
@implementation UITableViewHeaderFooterView (RACSignalSupport)
- (RACSignal *)rac_prepareForReuseSignal {
    RACSignal *signal = objc_getAssociatedObject(self, _cmd);
    if (signal != nil) return signal;
    signal = [[[self
        rac_signalForSelector:@selector(prepareForReuse)]
        mapReplace:RACUnit.defaultUnit]
        setNameWithFormat:@"%@ -rac_prepareForReuseSignal", self.rac_description];
    objc_setAssociatedObject(self, _cmd, signal, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    return signal;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UITextField+RACSignalSupport.h
New file
@@ -0,0 +1,28 @@
//
//  UITextField+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 4/17/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACChannelTerminal;
@class RACSignal;
@interface UITextField (RACSignalSupport)
/// Creates and returns a signal for the text of the field. It always starts with
/// the current text. The signal sends next when the UIControlEventAllEditingEvents
/// control event is fired on the control.
- (RACSignal *)rac_textSignal;
/// Creates a new RACChannel-based binding to the receiver.
///
/// Returns a RACChannelTerminal that sends the receiver's text whenever the
/// UIControlEventAllEditingEvents control event is fired, and sets the text
/// to the values it receives.
- (RACChannelTerminal *)rac_newTextChannel;
@end
Pods/ReactiveCocoa/ReactiveCocoa/UITextField+RACSignalSupport.m
New file
@@ -0,0 +1,39 @@
//
//  UITextField+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Josh Abernathy on 4/17/12.
//  Copyright (c) 2012 GitHub, Inc. All rights reserved.
//
#import "UITextField+RACSignalSupport.h"
#import "RACEXTKeyPathCoding.h"
#import "RACEXTScope.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACDescription.h"
#import "RACSignal+Operations.h"
#import "UIControl+RACSignalSupport.h"
#import "UIControl+RACSignalSupportPrivate.h"
@implementation UITextField (RACSignalSupport)
- (RACSignal *)rac_textSignal {
    @weakify(self);
    return [[[[[RACSignal
        defer:^{
            @strongify(self);
            return [RACSignal return:self];
        }]
        concat:[self rac_signalForControlEvents:UIControlEventAllEditingEvents]]
        map:^(UITextField *x) {
            return x.text;
        }]
        takeUntil:self.rac_willDeallocSignal]
        setNameWithFormat:@"%@ -rac_textSignal", self.rac_description];
}
- (RACChannelTerminal *)rac_newTextChannel {
    return [self rac_channelForControlEvents:UIControlEventAllEditingEvents key:@keypath(self.text) nilValue:@""];
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/UITextView+RACSignalSupport.h
New file
@@ -0,0 +1,39 @@
//
//  UITextView+RACSignalSupport.h
//  ReactiveCocoa
//
//  Created by Cody Krieger on 5/18/12.
//  Copyright (c) 2012 Cody Krieger. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RACDelegateProxy;
@class RACSignal;
@interface UITextView (RACSignalSupport)
/// A delegate proxy which will be set as the receiver's delegate when any of the
/// methods in this category are used.
@property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy;
/// Creates a signal for the text of the receiver.
///
/// When this method is invoked, the `rac_delegateProxy` will become the
/// receiver's delegate. Any previous delegate will become the -[RACDelegateProxy
/// rac_proxiedDelegate], so that it receives any messages that the proxy doesn't
/// know how to handle. Setting the receiver's `delegate` afterward is
/// considered undefined behavior.
///
/// Returns a signal which will send the current text upon subscription, then
/// again whenever the receiver's text is changed. The signal will complete when
/// the receiver is deallocated.
- (RACSignal *)rac_textSignal;
@end
@interface UITextView (RACSignalSupportUnavailable)
- (RACSignal *)rac_signalForDelegateMethod:(SEL)method __attribute__((unavailable("Use -rac_signalForSelector:fromProtocol: instead")));
@end
Pods/ReactiveCocoa/ReactiveCocoa/UITextView+RACSignalSupport.m
New file
@@ -0,0 +1,56 @@
//
//  UITextView+RACSignalSupport.m
//  ReactiveCocoa
//
//  Created by Cody Krieger on 5/18/12.
//  Copyright (c) 2012 Cody Krieger. All rights reserved.
//
#import "UITextView+RACSignalSupport.h"
#import "RACEXTScope.h"
#import "NSObject+RACDeallocating.h"
#import "NSObject+RACDescription.h"
#import "RACDelegateProxy.h"
#import "RACSignal+Operations.h"
#import "RACTuple.h"
#import <objc/runtime.h>
@implementation UITextView (RACSignalSupport)
static void RACUseDelegateProxy(UITextView *self) {
    if (self.delegate == self.rac_delegateProxy) return;
    self.rac_delegateProxy.rac_proxiedDelegate = self.delegate;
    self.delegate = (id)self.rac_delegateProxy;
}
- (RACDelegateProxy *)rac_delegateProxy {
    RACDelegateProxy *proxy = objc_getAssociatedObject(self, _cmd);
    if (proxy == nil) {
        proxy = [[RACDelegateProxy alloc] initWithProtocol:@protocol(UITextViewDelegate)];
        objc_setAssociatedObject(self, _cmd, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return proxy;
}
- (RACSignal *)rac_textSignal {
    @weakify(self);
    RACSignal *signal = [[[[[RACSignal
        defer:^{
            @strongify(self);
            return [RACSignal return:RACTuplePack(self)];
        }]
        concat:[self.rac_delegateProxy signalForSelector:@selector(textViewDidChange:)]]
        reduceEach:^(UITextView *x) {
            return x.text;
        }]
        takeUntil:self.rac_willDeallocSignal]
        setNameWithFormat:@"%@ -rac_textSignal", self.rac_description];
    RACUseDelegateProxy(self);
    return signal;
}
@end
Pods/ReactiveCocoa/ReactiveCocoa/extobjc/RACEXTKeyPathCoding.h
New file
@@ -0,0 +1,68 @@
//
//  EXTKeyPathCoding.h
//  extobjc
//
//  Created by Justin Spahr-Summers on 19.06.12.
//  Copyright (C) 2012 Justin Spahr-Summers.
//  Released under the MIT license.
//
#import <Foundation/Foundation.h>
#import "RACmetamacros.h"
/**
 * \@keypath allows compile-time verification of key paths. Given a real object
 * receiver and key path:
 *
 * @code
NSString *UTF8StringPath = @keypath(str.lowercaseString.UTF8String);
// => @"lowercaseString.UTF8String"
NSString *versionPath = @keypath(NSObject, version);
// => @"version"
NSString *lowercaseStringPath = @keypath(NSString.new, lowercaseString);
// => @"lowercaseString"
 * @endcode
 *
 * ... the macro returns an \c NSString containing all but the first path
 * component or argument (e.g., @"lowercaseString.UTF8String", @"version").
 *
 * In addition to simply creating a key path, this macro ensures that the key
 * path is valid at compile-time (causing a syntax error if not), and supports
 * refactoring, such that changing the name of the property will also update any
 * uses of \@keypath.
 */
#define keypath(...) \
    metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__))(keypath1(__VA_ARGS__))(keypath2(__VA_ARGS__))
#define keypath1(PATH) \
    (((void)(NO && ((void)PATH, NO)), strchr(# PATH, '.') + 1))
#define keypath2(OBJ, PATH) \
    (((void)(NO && ((void)OBJ.PATH, NO)), # PATH))
/**
 * \@collectionKeypath allows compile-time verification of key paths across collections NSArray/NSSet etc. Given a real object
 * receiver, collection object receiver and related keypaths:
 *
 * @code
 NSString *employessFirstNamePath = @collectionKeypath(department.employees, Employee.new, firstName)
 // => @"employees.firstName"
 NSString *employessFirstNamePath = @collectionKeypath(Department.new, employees, Employee.new, firstName)
 // => @"employees.firstName"
 * @endcode
 *
 */
#define collectionKeypath(...) \
    metamacro_if_eq(3, metamacro_argcount(__VA_ARGS__))(collectionKeypath3(__VA_ARGS__))(collectionKeypath4(__VA_ARGS__))
#define collectionKeypath3(PATH, COLLECTION_OBJECT, COLLECTION_PATH) ([[NSString stringWithFormat:@"%s.%s",keypath(PATH), keypath(COLLECTION_OBJECT, COLLECTION_PATH)] UTF8String])
#define collectionKeypath4(OBJ, PATH, COLLECTION_OBJECT, COLLECTION_PATH) ([[NSString stringWithFormat:@"%s.%s",keypath(OBJ, PATH), keypath(COLLECTION_OBJECT, COLLECTION_PATH)] UTF8String])
Pods/ReactiveCocoa/ReactiveCocoa/extobjc/RACEXTRuntimeExtensions.h
New file
@@ -0,0 +1,122 @@
//
//  EXTRuntimeExtensions.h
//  extobjc
//
//  Created by Justin Spahr-Summers on 2011-03-05.
//  Copyright (C) 2012 Justin Spahr-Summers.
//  Released under the MIT license.
//
#import <objc/runtime.h>
/**
 * Describes the memory management policy of a property.
 */
typedef enum {
    /**
     * The value is assigned.
     */
    rac_propertyMemoryManagementPolicyAssign = 0,
    /**
     * The value is retained.
     */
    rac_propertyMemoryManagementPolicyRetain,
    /**
     * The value is copied.
     */
    rac_propertyMemoryManagementPolicyCopy
} rac_propertyMemoryManagementPolicy;
/**
 * Describes the attributes and type information of a property.
 */
typedef struct {
    /**
     * Whether this property was declared with the \c readonly attribute.
     */
    BOOL readonly;
    /**
     * Whether this property was declared with the \c nonatomic attribute.
     */
    BOOL nonatomic;
    /**
     * Whether the property is a weak reference.
     */
    BOOL weak;
    /**
     * Whether the property is eligible for garbage collection.
     */
    BOOL canBeCollected;
    /**
     * Whether this property is defined with \c \@dynamic.
     */
    BOOL dynamic;
    /**
     * The memory management policy for this property. This will always be
     * #rac_propertyMemoryManagementPolicyAssign if #readonly is \c YES.
     */
    rac_propertyMemoryManagementPolicy memoryManagementPolicy;
    /**
     * The selector for the getter of this property. This will reflect any
     * custom \c getter= attribute provided in the property declaration, or the
     * inferred getter name otherwise.
     */
    SEL getter;
    /**
     * The selector for the setter of this property. This will reflect any
     * custom \c setter= attribute provided in the property declaration, or the
     * inferred setter name otherwise.
     *
     * @note If #readonly is \c YES, this value will represent what the setter
     * \e would be, if the property were writable.
     */
    SEL setter;
    /**
     * The backing instance variable for this property, or \c NULL if \c
     * \c @synthesize was not used, and therefore no instance variable exists. This
     * would also be the case if the property is implemented dynamically.
     */
    const char *ivar;
    /**
     * If this property is defined as being an instance of a specific class,
     * this will be the class object representing it.
     *
     * This will be \c nil if the property was defined as type \c id, if the
     * property is not of an object type, or if the class could not be found at
     * runtime.
     */
    Class objectClass;
    /**
     * The type encoding for the value of this property. This is the type as it
     * would be returned by the \c \@encode() directive.
     */
    char type[];
} rac_propertyAttributes;
/**
 * Finds the instance method named \a aSelector on \a aClass and returns it, or
 * returns \c NULL if no such instance method exists. Unlike \c
 * class_getInstanceMethod(), this does not search superclasses.
 *
 * @note To get class methods in this manner, use a metaclass for \a aClass.
 */
Method rac_getImmediateInstanceMethod (Class aClass, SEL aSelector);
/**
 * Returns a pointer to a structure containing information about \a property.
 * You must \c free() the returned pointer. Returns \c NULL if there is an error
 * obtaining information from \a property.
 */
rac_propertyAttributes *rac_copyPropertyAttributes (objc_property_t property);
Pods/ReactiveCocoa/ReactiveCocoa/extobjc/RACEXTRuntimeExtensions.m
New file
@@ -0,0 +1,234 @@
//
//  EXTRuntimeExtensions.m
//  extobjc
//
//  Created by Justin Spahr-Summers on 2011-03-05.
//  Copyright (C) 2012 Justin Spahr-Summers.
//  Released under the MIT license.
//
#import "RACEXTRuntimeExtensions.h"
#import <ctype.h>
#import <Foundation/Foundation.h>
#import <libkern/OSAtomic.h>
#import <objc/message.h>
#import <pthread.h>
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
rac_propertyAttributes *rac_copyPropertyAttributes (objc_property_t property) {
    const char * const attrString = property_getAttributes(property);
    if (!attrString) {
        fprintf(stderr, "ERROR: Could not get attribute string from property %s\n", property_getName(property));
        return NULL;
    }
    if (attrString[0] != 'T') {
        fprintf(stderr, "ERROR: Expected attribute string \"%s\" for property %s to start with 'T'\n", attrString, property_getName(property));
        return NULL;
    }
    const char *typeString = attrString + 1;
    const char *next = NSGetSizeAndAlignment(typeString, NULL, NULL);
    if (!next) {
        fprintf(stderr, "ERROR: Could not read past type in attribute string \"%s\" for property %s\n", attrString, property_getName(property));
        return NULL;
    }
    size_t typeLength = (size_t)(next - typeString);
    if (!typeLength) {
        fprintf(stderr, "ERROR: Invalid type in attribute string \"%s\" for property %s\n", attrString, property_getName(property));
        return NULL;
    }
    // allocate enough space for the structure and the type string (plus a NUL)
    rac_propertyAttributes *attributes = calloc(1, sizeof(rac_propertyAttributes) + typeLength + 1);
    if (!attributes) {
        fprintf(stderr, "ERROR: Could not allocate rac_propertyAttributes structure for attribute string \"%s\" for property %s\n", attrString, property_getName(property));
        return NULL;
    }
    // copy the type string
    strncpy(attributes->type, typeString, typeLength);
    attributes->type[typeLength] = '\0';
    // if this is an object type, and immediately followed by a quoted string...
    if (typeString[0] == *(@encode(id)) && typeString[1] == '"') {
        // we should be able to extract a class name
        const char *className = typeString + 2;
        next = strchr(className, '"');
        if (!next) {
            fprintf(stderr, "ERROR: Could not read class name in attribute string \"%s\" for property %s\n", attrString, property_getName(property));
            return NULL;
        }
        if (className != next) {
            size_t classNameLength = (size_t)(next - className);
            char trimmedName[classNameLength + 1];
            strncpy(trimmedName, className, classNameLength);
            trimmedName[classNameLength] = '\0';
            // attempt to look up the class in the runtime
            attributes->objectClass = objc_getClass(trimmedName);
        }
    }
    if (*next != '\0') {
        // skip past any junk before the first flag
        next = strchr(next, ',');
    }
    while (next && *next == ',') {
        char flag = next[1];
        next += 2;
        switch (flag) {
        case '\0':
            break;
        case 'R':
            attributes->readonly = YES;
            break;
        case 'C':
            attributes->memoryManagementPolicy = rac_propertyMemoryManagementPolicyCopy;
            break;
        case '&':
            attributes->memoryManagementPolicy = rac_propertyMemoryManagementPolicyRetain;
            break;
        case 'N':
            attributes->nonatomic = YES;
            break;
        case 'G':
        case 'S':
            {
                const char *nextFlag = strchr(next, ',');
                SEL name = NULL;
                if (!nextFlag) {
                    // assume that the rest of the string is the selector
                    const char *selectorString = next;
                    next = "";
                    name = sel_registerName(selectorString);
                } else {
                    size_t selectorLength = (size_t)(nextFlag - next);
                    if (!selectorLength) {
                        fprintf(stderr, "ERROR: Found zero length selector name in attribute string \"%s\" for property %s\n", attrString, property_getName(property));
                        goto errorOut;
                    }
                    char selectorString[selectorLength + 1];
                    strncpy(selectorString, next, selectorLength);
                    selectorString[selectorLength] = '\0';
                    name = sel_registerName(selectorString);
                    next = nextFlag;
                }
                if (flag == 'G')
                    attributes->getter = name;
                else
                    attributes->setter = name;
            }
            break;
        case 'D':
            attributes->dynamic = YES;
            attributes->ivar = NULL;
            break;
        case 'V':
            // assume that the rest of the string (if present) is the ivar name
            if (*next == '\0') {
                // if there's nothing there, let's assume this is dynamic
                attributes->ivar = NULL;
            } else {
                attributes->ivar = next;
                next = "";
            }
            break;
        case 'W':
            attributes->weak = YES;
            break;
        case 'P':
            attributes->canBeCollected = YES;
            break;
        case 't':
            fprintf(stderr, "ERROR: Old-style type encoding is unsupported in attribute string \"%s\" for property %s\n", attrString, property_getName(property));
            // skip over this type encoding
            while (*next != ',' && *next != '\0')
                ++next;
            break;
        default:
            fprintf(stderr, "ERROR: Unrecognized attribute string flag '%c' in attribute string \"%s\" for property %s\n", flag, attrString, property_getName(property));
        }
    }
    if (next && *next != '\0') {
        fprintf(stderr, "Warning: Unparsed data \"%s\" in attribute string \"%s\" for property %s\n", next, attrString, property_getName(property));
    }
    if (!attributes->getter) {
        // use the property name as the getter by default
        attributes->getter = sel_registerName(property_getName(property));
    }
    if (!attributes->setter) {
        const char *propertyName = property_getName(property);
        size_t propertyNameLength = strlen(propertyName);
        // we want to transform the name to setProperty: style
        size_t setterLength = propertyNameLength + 4;
        char setterName[setterLength + 1];
        strncpy(setterName, "set", 3);
        strncpy(setterName + 3, propertyName, propertyNameLength);
        // capitalize property name for the setter
        setterName[3] = (char)toupper(setterName[3]);
        setterName[setterLength - 1] = ':';
        setterName[setterLength] = '\0';
        attributes->setter = sel_registerName(setterName);
    }
    return attributes;
errorOut:
    free(attributes);
    return NULL;
}
Method rac_getImmediateInstanceMethod (Class aClass, SEL aSelector) {
    unsigned methodCount = 0;
    Method *methods = class_copyMethodList(aClass, &methodCount);
    Method foundMethod = NULL;
    for (unsigned methodIndex = 0;methodIndex < methodCount;++methodIndex) {
        if (method_getName(methods[methodIndex]) == aSelector) {
            foundMethod = methods[methodIndex];
            break;
        }
    }
    free(methods);
    return foundMethod;
}
Pods/ReactiveCocoa/ReactiveCocoa/extobjc/RACEXTScope.h
New file
@@ -0,0 +1,118 @@
//
//  EXTScope.h
//  extobjc
//
//  Created by Justin Spahr-Summers on 2011-05-04.
//  Copyright (C) 2012 Justin Spahr-Summers.
//  Released under the MIT license.
//
#import "RACmetamacros.h"
/**
 * \@onExit defines some code to be executed when the current scope exits. The
 * code must be enclosed in braces and terminated with a semicolon, and will be
 * executed regardless of how the scope is exited, including from exceptions,
 * \c goto, \c return, \c break, and \c continue.
 *
 * Provided code will go into a block to be executed later. Keep this in mind as
 * it pertains to memory management, restrictions on assignment, etc. Because
 * the code is used within a block, \c return is a legal (though perhaps
 * confusing) way to exit the cleanup block early.
 *
 * Multiple \@onExit statements in the same scope are executed in reverse
 * lexical order. This helps when pairing resource acquisition with \@onExit
 * statements, as it guarantees teardown in the opposite order of acquisition.
 *
 * @note This statement cannot be used within scopes defined without braces
 * (like a one line \c if). In practice, this is not an issue, since \@onExit is
 * a useless construct in such a case anyways.
 */
#define onExit \
    rac_keywordify \
    __strong rac_cleanupBlock_t metamacro_concat(rac_exitBlock_, __LINE__) __attribute__((cleanup(rac_executeCleanupBlock), unused)) = ^
/**
 * Creates \c __weak shadow variables for each of the variables provided as
 * arguments, which can later be made strong again with #strongify.
 *
 * This is typically used to weakly reference variables in a block, but then
 * ensure that the variables stay alive during the actual execution of the block
 * (if they were live upon entry).
 *
 * See #strongify for an example of usage.
 */
#define weakify(...) \
    rac_keywordify \
    metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
/**
 * Like #weakify, but uses \c __unsafe_unretained instead, for targets or
 * classes that do not support weak references.
 */
#define unsafeify(...) \
    rac_keywordify \
    metamacro_foreach_cxt(rac_weakify_,, __unsafe_unretained, __VA_ARGS__)
/**
 * Strongly references each of the variables provided as arguments, which must
 * have previously been passed to #weakify.
 *
 * The strong references created will shadow the original variable names, such
 * that the original names can be used without issue (and a significantly
 * reduced risk of retain cycles) in the current scope.
 *
 * @code
    id foo = [[NSObject alloc] init];
    id bar = [[NSObject alloc] init];
    @weakify(foo, bar);
    // this block will not keep 'foo' or 'bar' alive
    BOOL (^matchesFooOrBar)(id) = ^ BOOL (id obj){
        // but now, upon entry, 'foo' and 'bar' will stay alive until the block has
        // finished executing
        @strongify(foo, bar);
        return [foo isEqual:obj] || [bar isEqual:obj];
    };
 * @endcode
 */
#define strongify(...) \
    rac_keywordify \
    _Pragma("clang diagnostic push") \
    _Pragma("clang diagnostic ignored \"-Wshadow\"") \
    metamacro_foreach(rac_strongify_,, __VA_ARGS__) \
    _Pragma("clang diagnostic pop")
/*** implementation details follow ***/
typedef void (^rac_cleanupBlock_t)();
static inline void rac_executeCleanupBlock (__strong rac_cleanupBlock_t *block) {
    (*block)();
}
#define rac_weakify_(INDEX, CONTEXT, VAR) \
    CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);
#define rac_strongify_(INDEX, VAR) \
    __strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_);
// Details about the choice of backing keyword:
//
// The use of @try/@catch/@finally can cause the compiler to suppress
// return-type warnings.
// The use of @autoreleasepool {} is not optimized away by the compiler,
// resulting in superfluous creation of autorelease pools.
//
// Since neither option is perfect, and with no other alternatives, the
// compromise is to use @autorelease in DEBUG builds to maintain compiler
// analysis, and to use @try/@catch otherwise to avoid insertion of unnecessary
// autorelease pools.
#if DEBUG
#define rac_keywordify autoreleasepool {}
#else
#define rac_keywordify try {} @catch (...) {}
#endif
Pods/ReactiveCocoa/ReactiveCocoa/extobjc/RACmetamacros.h
New file
@@ -0,0 +1,666 @@
/**
 * Macros for metaprogramming
 * ExtendedC
 *
 * Copyright (C) 2012 Justin Spahr-Summers
 * Released under the MIT license
 */
#ifndef EXTC_METAMACROS_H
#define EXTC_METAMACROS_H
/**
 * Executes one or more expressions (which may have a void type, such as a call
 * to a function that returns no value) and always returns true.
 */
#define metamacro_exprify(...) \
    ((__VA_ARGS__), true)
/**
 * Returns a string representation of VALUE after full macro expansion.
 */
#define metamacro_stringify(VALUE) \
        metamacro_stringify_(VALUE)
/**
 * Returns A and B concatenated after full macro expansion.
 */
#define metamacro_concat(A, B) \
        metamacro_concat_(A, B)
/**
 * Returns the Nth variadic argument (starting from zero). At least
 * N + 1 variadic arguments must be given. N must be between zero and twenty,
 * inclusive.
 */
#define metamacro_at(N, ...) \
        metamacro_concat(metamacro_at, N)(__VA_ARGS__)
/**
 * Returns the number of arguments (up to twenty) provided to the macro. At
 * least one argument must be provided.
 *
 * Inspired by P99: http://p99.gforge.inria.fr
 */
#define metamacro_argcount(...) \
        metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
/**
 * Identical to #metamacro_foreach_cxt, except that no CONTEXT argument is
 * given. Only the index and current argument will thus be passed to MACRO.
 */
#define metamacro_foreach(MACRO, SEP, ...) \
        metamacro_foreach_cxt(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__)
/**
 * For each consecutive variadic argument (up to twenty), MACRO is passed the
 * zero-based index of the current argument, CONTEXT, and then the argument
 * itself. The results of adjoining invocations of MACRO are then separated by
 * SEP.
 *
 * Inspired by P99: http://p99.gforge.inria.fr
 */
#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
        metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
/**
 * Identical to #metamacro_foreach_cxt. This can be used when the former would
 * fail due to recursive macro expansion.
 */
#define metamacro_foreach_cxt_recursive(MACRO, SEP, CONTEXT, ...) \
        metamacro_concat(metamacro_foreach_cxt_recursive, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
/**
 * In consecutive order, appends each variadic argument (up to twenty) onto
 * BASE. The resulting concatenations are then separated by SEP.
 *
 * This is primarily useful to manipulate a list of macro invocations into instead
 * invoking a different, possibly related macro.
 */
#define metamacro_foreach_concat(BASE, SEP, ...) \
        metamacro_foreach_cxt(metamacro_foreach_concat_iter, SEP, BASE, __VA_ARGS__)
/**
 * Iterates COUNT times, each time invoking MACRO with the current index
 * (starting at zero) and CONTEXT. The results of adjoining invocations of MACRO
 * are then separated by SEP.
 *
 * COUNT must be an integer between zero and twenty, inclusive.
 */
#define metamacro_for_cxt(COUNT, MACRO, SEP, CONTEXT) \
        metamacro_concat(metamacro_for_cxt, COUNT)(MACRO, SEP, CONTEXT)
/**
 * Returns the first argument given. At least one argument must be provided.
 *
 * This is useful when implementing a variadic macro, where you may have only
 * one variadic argument, but no way to retrieve it (for example, because \c ...
 * always needs to match at least one argument).
 *
 * @code
#define varmacro(...) \
    metamacro_head(__VA_ARGS__)
 * @endcode
 */
#define metamacro_head(...) \
        metamacro_head_(__VA_ARGS__, 0)
/**
 * Returns every argument except the first. At least two arguments must be
 * provided.
 */
#define metamacro_tail(...) \
        metamacro_tail_(__VA_ARGS__)
/**
 * Returns the first N (up to twenty) variadic arguments as a new argument list.
 * At least N variadic arguments must be provided.
 */
#define metamacro_take(N, ...) \
        metamacro_concat(metamacro_take, N)(__VA_ARGS__)
/**
 * Removes the first N (up to twenty) variadic arguments from the given argument
 * list. At least N variadic arguments must be provided.
 */
#define metamacro_drop(N, ...) \
        metamacro_concat(metamacro_drop, N)(__VA_ARGS__)
/**
 * Decrements VAL, which must be a number between zero and twenty, inclusive.
 *
 * This is primarily useful when dealing with indexes and counts in
 * metaprogramming.
 */
#define metamacro_dec(VAL) \
        metamacro_at(VAL, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
/**
 * Increments VAL, which must be a number between zero and twenty, inclusive.
 *
 * This is primarily useful when dealing with indexes and counts in
 * metaprogramming.
 */
#define metamacro_inc(VAL) \
        metamacro_at(VAL, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
/**
 * If A is equal to B, the next argument list is expanded; otherwise, the
 * argument list after that is expanded. A and B must be numbers between zero
 * and twenty, inclusive. Additionally, B must be greater than or equal to A.
 *
 * @code
// expands to true
metamacro_if_eq(0, 0)(true)(false)
// expands to false
metamacro_if_eq(0, 1)(true)(false)
 * @endcode
 *
 * This is primarily useful when dealing with indexes and counts in
 * metaprogramming.
 */
#define metamacro_if_eq(A, B) \
        metamacro_concat(metamacro_if_eq, A)(B)
/**
 * Identical to #metamacro_if_eq. This can be used when the former would fail
 * due to recursive macro expansion.
 */
#define metamacro_if_eq_recursive(A, B) \
        metamacro_concat(metamacro_if_eq_recursive, A)(B)
/**
 * Returns 1 if N is an even number, or 0 otherwise. N must be between zero and
 * twenty, inclusive.
 *
 * For the purposes of this test, zero is considered even.
 */
#define metamacro_is_even(N) \
        metamacro_at(N, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
/**
 * Returns the logical NOT of B, which must be the number zero or one.
 */
#define metamacro_not(B) \
        metamacro_at(B, 1, 0)
// IMPLEMENTATION DETAILS FOLLOW!
// Do not write code that depends on anything below this line.
#define metamacro_stringify_(VALUE) # VALUE
#define metamacro_concat_(A, B) A ## B
#define metamacro_foreach_iter(INDEX, MACRO, ARG) MACRO(INDEX, ARG)
#define metamacro_head_(FIRST, ...) FIRST
#define metamacro_tail_(FIRST, ...) __VA_ARGS__
#define metamacro_consume_(...)
#define metamacro_expand_(...) __VA_ARGS__
// implemented from scratch so that metamacro_concat() doesn't end up nesting
#define metamacro_foreach_concat_iter(INDEX, BASE, ARG) metamacro_foreach_concat_iter_(BASE, ARG)
#define metamacro_foreach_concat_iter_(BASE, ARG) BASE ## ARG
// metamacro_at expansions
#define metamacro_at0(...) metamacro_head(__VA_ARGS__)
#define metamacro_at1(_0, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at2(_0, _1, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at3(_0, _1, _2, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at4(_0, _1, _2, _3, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at5(_0, _1, _2, _3, _4, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at6(_0, _1, _2, _3, _4, _5, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at7(_0, _1, _2, _3, _4, _5, _6, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at8(_0, _1, _2, _3, _4, _5, _6, _7, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at9(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at19(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) metamacro_head(__VA_ARGS__)
// metamacro_foreach_cxt expansions
#define metamacro_foreach_cxt0(MACRO, SEP, CONTEXT)
#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)
#define metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
    metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) \
    SEP \
    MACRO(1, CONTEXT, _1)
#define metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \
    metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
    SEP \
    MACRO(2, CONTEXT, _2)
#define metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
    metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \
    SEP \
    MACRO(3, CONTEXT, _3)
#define metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
    metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
    SEP \
    MACRO(4, CONTEXT, _4)
#define metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
    metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
    SEP \
    MACRO(5, CONTEXT, _5)
#define metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
    metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
    SEP \
    MACRO(6, CONTEXT, _6)
#define metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
    metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
    SEP \
    MACRO(7, CONTEXT, _7)
#define metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
    metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
    SEP \
    MACRO(8, CONTEXT, _8)
#define metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
    metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
    SEP \
    MACRO(9, CONTEXT, _9)
#define metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
    metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
    SEP \
    MACRO(10, CONTEXT, _10)
#define metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
    metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
    SEP \
    MACRO(11, CONTEXT, _11)
#define metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
    metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
    SEP \
    MACRO(12, CONTEXT, _12)
#define metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
    metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
    SEP \
    MACRO(13, CONTEXT, _13)
#define metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
    metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
    SEP \
    MACRO(14, CONTEXT, _14)
#define metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
    metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
    SEP \
    MACRO(15, CONTEXT, _15)
#define metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
    metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
    SEP \
    MACRO(16, CONTEXT, _16)
#define metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \
    metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
    SEP \
    MACRO(17, CONTEXT, _17)
#define metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \
    metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \
    SEP \
    MACRO(18, CONTEXT, _18)
#define metamacro_foreach_cxt20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \
    metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \
    SEP \
    MACRO(19, CONTEXT, _19)
// metamacro_foreach_cxt_recursive expansions
#define metamacro_foreach_cxt_recursive0(MACRO, SEP, CONTEXT)
#define metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)
#define metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \
    metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) \
    SEP \
    MACRO(1, CONTEXT, _1)
#define metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \
    metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \
    SEP \
    MACRO(2, CONTEXT, _2)
#define metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
    metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \
    SEP \
    MACRO(3, CONTEXT, _3)
#define metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
    metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
    SEP \
    MACRO(4, CONTEXT, _4)
#define metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
    metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
    SEP \
    MACRO(5, CONTEXT, _5)
#define metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
    metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
    SEP \
    MACRO(6, CONTEXT, _6)
#define metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
    metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
    SEP \
    MACRO(7, CONTEXT, _7)
#define metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
    metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
    SEP \
    MACRO(8, CONTEXT, _8)
#define metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
    metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
    SEP \
    MACRO(9, CONTEXT, _9)
#define metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
    metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
    SEP \
    MACRO(10, CONTEXT, _10)
#define metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
    metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
    SEP \
    MACRO(11, CONTEXT, _11)
#define metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
    metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
    SEP \
    MACRO(12, CONTEXT, _12)
#define metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
    metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
    SEP \
    MACRO(13, CONTEXT, _13)
#define metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
    metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
    SEP \
    MACRO(14, CONTEXT, _14)
#define metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
    metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
    SEP \
    MACRO(15, CONTEXT, _15)
#define metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
    metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
    SEP \
    MACRO(16, CONTEXT, _16)
#define metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \
    metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
    SEP \
    MACRO(17, CONTEXT, _17)
#define metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \
    metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \
    SEP \
    MACRO(18, CONTEXT, _18)
#define metamacro_foreach_cxt_recursive20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \
    metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \
    SEP \
    MACRO(19, CONTEXT, _19)
// metamacro_for_cxt expansions
#define metamacro_for_cxt0(MACRO, SEP, CONTEXT)
#define metamacro_for_cxt1(MACRO, SEP, CONTEXT) MACRO(0, CONTEXT)
#define metamacro_for_cxt2(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt1(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(1, CONTEXT)
#define metamacro_for_cxt3(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt2(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(2, CONTEXT)
#define metamacro_for_cxt4(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt3(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(3, CONTEXT)
#define metamacro_for_cxt5(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt4(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(4, CONTEXT)
#define metamacro_for_cxt6(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt5(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(5, CONTEXT)
#define metamacro_for_cxt7(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt6(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(6, CONTEXT)
#define metamacro_for_cxt8(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt7(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(7, CONTEXT)
#define metamacro_for_cxt9(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt8(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(8, CONTEXT)
#define metamacro_for_cxt10(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt9(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(9, CONTEXT)
#define metamacro_for_cxt11(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt10(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(10, CONTEXT)
#define metamacro_for_cxt12(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt11(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(11, CONTEXT)
#define metamacro_for_cxt13(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt12(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(12, CONTEXT)
#define metamacro_for_cxt14(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt13(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(13, CONTEXT)
#define metamacro_for_cxt15(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt14(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(14, CONTEXT)
#define metamacro_for_cxt16(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt15(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(15, CONTEXT)
#define metamacro_for_cxt17(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt16(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(16, CONTEXT)
#define metamacro_for_cxt18(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt17(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(17, CONTEXT)
#define metamacro_for_cxt19(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt18(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(18, CONTEXT)
#define metamacro_for_cxt20(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt19(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(19, CONTEXT)
// metamacro_if_eq expansions
#define metamacro_if_eq0(VALUE) \
    metamacro_concat(metamacro_if_eq0_, VALUE)
#define metamacro_if_eq0_0(...) __VA_ARGS__ metamacro_consume_
#define metamacro_if_eq0_1(...) metamacro_expand_
#define metamacro_if_eq0_2(...) metamacro_expand_
#define metamacro_if_eq0_3(...) metamacro_expand_
#define metamacro_if_eq0_4(...) metamacro_expand_
#define metamacro_if_eq0_5(...) metamacro_expand_
#define metamacro_if_eq0_6(...) metamacro_expand_
#define metamacro_if_eq0_7(...) metamacro_expand_
#define metamacro_if_eq0_8(...) metamacro_expand_
#define metamacro_if_eq0_9(...) metamacro_expand_
#define metamacro_if_eq0_10(...) metamacro_expand_
#define metamacro_if_eq0_11(...) metamacro_expand_
#define metamacro_if_eq0_12(...) metamacro_expand_
#define metamacro_if_eq0_13(...) metamacro_expand_
#define metamacro_if_eq0_14(...) metamacro_expand_
#define metamacro_if_eq0_15(...) metamacro_expand_
#define metamacro_if_eq0_16(...) metamacro_expand_
#define metamacro_if_eq0_17(...) metamacro_expand_
#define metamacro_if_eq0_18(...) metamacro_expand_
#define metamacro_if_eq0_19(...) metamacro_expand_
#define metamacro_if_eq0_20(...) metamacro_expand_
#define metamacro_if_eq1(VALUE) metamacro_if_eq0(metamacro_dec(VALUE))
#define metamacro_if_eq2(VALUE) metamacro_if_eq1(metamacro_dec(VALUE))
#define metamacro_if_eq3(VALUE) metamacro_if_eq2(metamacro_dec(VALUE))
#define metamacro_if_eq4(VALUE) metamacro_if_eq3(metamacro_dec(VALUE))
#define metamacro_if_eq5(VALUE) metamacro_if_eq4(metamacro_dec(VALUE))
#define metamacro_if_eq6(VALUE) metamacro_if_eq5(metamacro_dec(VALUE))
#define metamacro_if_eq7(VALUE) metamacro_if_eq6(metamacro_dec(VALUE))
#define metamacro_if_eq8(VALUE) metamacro_if_eq7(metamacro_dec(VALUE))
#define metamacro_if_eq9(VALUE) metamacro_if_eq8(metamacro_dec(VALUE))
#define metamacro_if_eq10(VALUE) metamacro_if_eq9(metamacro_dec(VALUE))
#define metamacro_if_eq11(VALUE) metamacro_if_eq10(metamacro_dec(VALUE))
#define metamacro_if_eq12(VALUE) metamacro_if_eq11(metamacro_dec(VALUE))
#define metamacro_if_eq13(VALUE) metamacro_if_eq12(metamacro_dec(VALUE))
#define metamacro_if_eq14(VALUE) metamacro_if_eq13(metamacro_dec(VALUE))
#define metamacro_if_eq15(VALUE) metamacro_if_eq14(metamacro_dec(VALUE))
#define metamacro_if_eq16(VALUE) metamacro_if_eq15(metamacro_dec(VALUE))
#define metamacro_if_eq17(VALUE) metamacro_if_eq16(metamacro_dec(VALUE))
#define metamacro_if_eq18(VALUE) metamacro_if_eq17(metamacro_dec(VALUE))
#define metamacro_if_eq19(VALUE) metamacro_if_eq18(metamacro_dec(VALUE))
#define metamacro_if_eq20(VALUE) metamacro_if_eq19(metamacro_dec(VALUE))
// metamacro_if_eq_recursive expansions
#define metamacro_if_eq_recursive0(VALUE) \
    metamacro_concat(metamacro_if_eq_recursive0_, VALUE)
#define metamacro_if_eq_recursive0_0(...) __VA_ARGS__ metamacro_consume_
#define metamacro_if_eq_recursive0_1(...) metamacro_expand_
#define metamacro_if_eq_recursive0_2(...) metamacro_expand_
#define metamacro_if_eq_recursive0_3(...) metamacro_expand_
#define metamacro_if_eq_recursive0_4(...) metamacro_expand_
#define metamacro_if_eq_recursive0_5(...) metamacro_expand_
#define metamacro_if_eq_recursive0_6(...) metamacro_expand_
#define metamacro_if_eq_recursive0_7(...) metamacro_expand_
#define metamacro_if_eq_recursive0_8(...) metamacro_expand_
#define metamacro_if_eq_recursive0_9(...) metamacro_expand_
#define metamacro_if_eq_recursive0_10(...) metamacro_expand_
#define metamacro_if_eq_recursive0_11(...) metamacro_expand_
#define metamacro_if_eq_recursive0_12(...) metamacro_expand_
#define metamacro_if_eq_recursive0_13(...) metamacro_expand_
#define metamacro_if_eq_recursive0_14(...) metamacro_expand_
#define metamacro_if_eq_recursive0_15(...) metamacro_expand_
#define metamacro_if_eq_recursive0_16(...) metamacro_expand_
#define metamacro_if_eq_recursive0_17(...) metamacro_expand_
#define metamacro_if_eq_recursive0_18(...) metamacro_expand_
#define metamacro_if_eq_recursive0_19(...) metamacro_expand_
#define metamacro_if_eq_recursive0_20(...) metamacro_expand_
#define metamacro_if_eq_recursive1(VALUE) metamacro_if_eq_recursive0(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive2(VALUE) metamacro_if_eq_recursive1(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive3(VALUE) metamacro_if_eq_recursive2(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive4(VALUE) metamacro_if_eq_recursive3(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive5(VALUE) metamacro_if_eq_recursive4(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive6(VALUE) metamacro_if_eq_recursive5(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive7(VALUE) metamacro_if_eq_recursive6(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive8(VALUE) metamacro_if_eq_recursive7(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive9(VALUE) metamacro_if_eq_recursive8(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive10(VALUE) metamacro_if_eq_recursive9(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive11(VALUE) metamacro_if_eq_recursive10(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive12(VALUE) metamacro_if_eq_recursive11(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive13(VALUE) metamacro_if_eq_recursive12(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive14(VALUE) metamacro_if_eq_recursive13(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive15(VALUE) metamacro_if_eq_recursive14(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive16(VALUE) metamacro_if_eq_recursive15(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive17(VALUE) metamacro_if_eq_recursive16(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive18(VALUE) metamacro_if_eq_recursive17(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive19(VALUE) metamacro_if_eq_recursive18(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive20(VALUE) metamacro_if_eq_recursive19(metamacro_dec(VALUE))
// metamacro_take expansions
#define metamacro_take0(...)
#define metamacro_take1(...) metamacro_head(__VA_ARGS__)
#define metamacro_take2(...) metamacro_head(__VA_ARGS__), metamacro_take1(metamacro_tail(__VA_ARGS__))
#define metamacro_take3(...) metamacro_head(__VA_ARGS__), metamacro_take2(metamacro_tail(__VA_ARGS__))
#define metamacro_take4(...) metamacro_head(__VA_ARGS__), metamacro_take3(metamacro_tail(__VA_ARGS__))
#define metamacro_take5(...) metamacro_head(__VA_ARGS__), metamacro_take4(metamacro_tail(__VA_ARGS__))
#define metamacro_take6(...) metamacro_head(__VA_ARGS__), metamacro_take5(metamacro_tail(__VA_ARGS__))
#define metamacro_take7(...) metamacro_head(__VA_ARGS__), metamacro_take6(metamacro_tail(__VA_ARGS__))
#define metamacro_take8(...) metamacro_head(__VA_ARGS__), metamacro_take7(metamacro_tail(__VA_ARGS__))
#define metamacro_take9(...) metamacro_head(__VA_ARGS__), metamacro_take8(metamacro_tail(__VA_ARGS__))
#define metamacro_take10(...) metamacro_head(__VA_ARGS__), metamacro_take9(metamacro_tail(__VA_ARGS__))
#define metamacro_take11(...) metamacro_head(__VA_ARGS__), metamacro_take10(metamacro_tail(__VA_ARGS__))
#define metamacro_take12(...) metamacro_head(__VA_ARGS__), metamacro_take11(metamacro_tail(__VA_ARGS__))
#define metamacro_take13(...) metamacro_head(__VA_ARGS__), metamacro_take12(metamacro_tail(__VA_ARGS__))
#define metamacro_take14(...) metamacro_head(__VA_ARGS__), metamacro_take13(metamacro_tail(__VA_ARGS__))
#define metamacro_take15(...) metamacro_head(__VA_ARGS__), metamacro_take14(metamacro_tail(__VA_ARGS__))
#define metamacro_take16(...) metamacro_head(__VA_ARGS__), metamacro_take15(metamacro_tail(__VA_ARGS__))
#define metamacro_take17(...) metamacro_head(__VA_ARGS__), metamacro_take16(metamacro_tail(__VA_ARGS__))
#define metamacro_take18(...) metamacro_head(__VA_ARGS__), metamacro_take17(metamacro_tail(__VA_ARGS__))
#define metamacro_take19(...) metamacro_head(__VA_ARGS__), metamacro_take18(metamacro_tail(__VA_ARGS__))
#define metamacro_take20(...) metamacro_head(__VA_ARGS__), metamacro_take19(metamacro_tail(__VA_ARGS__))
// metamacro_drop expansions
#define metamacro_drop0(...) __VA_ARGS__
#define metamacro_drop1(...) metamacro_tail(__VA_ARGS__)
#define metamacro_drop2(...) metamacro_drop1(metamacro_tail(__VA_ARGS__))
#define metamacro_drop3(...) metamacro_drop2(metamacro_tail(__VA_ARGS__))
#define metamacro_drop4(...) metamacro_drop3(metamacro_tail(__VA_ARGS__))
#define metamacro_drop5(...) metamacro_drop4(metamacro_tail(__VA_ARGS__))
#define metamacro_drop6(...) metamacro_drop5(metamacro_tail(__VA_ARGS__))
#define metamacro_drop7(...) metamacro_drop6(metamacro_tail(__VA_ARGS__))
#define metamacro_drop8(...) metamacro_drop7(metamacro_tail(__VA_ARGS__))
#define metamacro_drop9(...) metamacro_drop8(metamacro_tail(__VA_ARGS__))
#define metamacro_drop10(...) metamacro_drop9(metamacro_tail(__VA_ARGS__))
#define metamacro_drop11(...) metamacro_drop10(metamacro_tail(__VA_ARGS__))
#define metamacro_drop12(...) metamacro_drop11(metamacro_tail(__VA_ARGS__))
#define metamacro_drop13(...) metamacro_drop12(metamacro_tail(__VA_ARGS__))
#define metamacro_drop14(...) metamacro_drop13(metamacro_tail(__VA_ARGS__))
#define metamacro_drop15(...) metamacro_drop14(metamacro_tail(__VA_ARGS__))
#define metamacro_drop16(...) metamacro_drop15(metamacro_tail(__VA_ARGS__))
#define metamacro_drop17(...) metamacro_drop16(metamacro_tail(__VA_ARGS__))
#define metamacro_drop18(...) metamacro_drop17(metamacro_tail(__VA_ARGS__))
#define metamacro_drop19(...) metamacro_drop18(metamacro_tail(__VA_ARGS__))
#define metamacro_drop20(...) metamacro_drop19(metamacro_tail(__VA_ARGS__))
#endif
Pods/SDAutoLayout/LICENSE
New file
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 GSD_iOS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Pods/SDAutoLayout/README.md
New file
@@ -0,0 +1,182 @@
# SDAutoLayout(一行代码搞定自动布局!)
##众多公司和个人开发者已经使用本库布局:
SDAutoLayout使用者开发的部分app截图 http://www.jianshu.com/p/9bc04d3effb8
一行代码搞定自动布局!致力于做最简单易用的Autolayout库。The most easy way for autolayout.
## æŠ€æœ¯æ”¯æŒ(QQ交流群):
497140713(1群)  519489682(2群已满)
##Pod支持:
支持pod:  pod 'SDAutoLayout', '~> 2.1.3'
如果发现pod search SDAutoLayout æœç´¢å‡ºæ¥çš„不是最新版本,需要在终端执行cd转换文件路径命令退回到desktop,然后执行pod setup命令更新本地spec缓存(可能需要几分钟),然后再搜索就可以了
## æ›´æ–°è®°å½•:
2017.06.26 -- è§£å†³éƒ¨åˆ†å¼€å‘者反应因出现“UITableViewCellContentView”而导致应用审核被拒问题
2016.08.12 -- å®žçŽ°åœ¨tableview插入新的cell数据时自动缓存管理
2016.06.30 -- å¢žåŠ å¤šå‚ç…§view的leftSpaceToView和topSpaceToView约束,例:topSpaceToView(@[self.view3, self.view4], 30)
2016.06.24 -- ä¿®å¤ç»™button设置约束时在iOS8.x系统中出现的崩溃问题;发布2.1.2版本
2016.06.23 -- å®žçŽ°åˆ é™¤æŸè¡Œcell时自动调整height缓存
2016.05.16 -- ä¿®å¤ç”¨xib生成的view出现的部分约束失效问题(发布pod2.0.0版本)
2016.05.15 -- å¢žåŠ è®¾ç½®åç§»é‡offset功能
2016.04.30 -- ä¿®å¤ä¹‹å‰button作为父视图时内部控件不能自动布局问题
2016.04.05 -- ä¿®å¤å®½åº¦è‡ªé€‚应label在重用时候偶尔出现的宽度计算不准确的问题(发布pod1.51版本)
2016.03.23 -- å‡çº§äº†ç¼“存机制,新版本在tableview滑动cell时候流畅度和性能提升20%以上(发布pod1.50版本)
2016.01.23 -- å¢žåŠ label对attributedString的内容自适应
2016.01.21 -- å®žçްtableview局部刷新cell高度缓存的自动管理
2016.01.20 -- demo适配在ios7上的屏幕旋转问题
2016.01.18 -- æŽ¨å‡ºâ€œæ™®é€šç®€åŒ–版”tableview的cell自动高度方法(推荐使用),原来的需2步设置的普通版方法将标记过期
2016.01.13 -- å¢žåŠ åœ¨ä¸ç¡®å®šbottom view的情况下的cell高度自适应方法
2016.01.07 -- 1.增加 scrollview æ¨ªå‘内容自适应功能;2.增加view宽高相等的功能
2016.01.03 -- å¢žåŠ ä»»ä½•ç±»åž‹å¯¹è±¡éƒ½å¯ä»¥å®žçŽ°ä¸€è¡Œä»£ç æžå®šcell高度自适应;增加文档注释
2015.12.08 -- é‡å¤§å‡çº§ï¼š1.支持scrollview内容自适应;2.任意添加或者修改约束不冲突;3.性能提升40%以上;4.添加最大、最小宽高约束
## è§†é¢‘教程:
☆☆ SDAutoLayout åŸºç¡€ç‰ˆè§†é¢‘教程:http://www.letv.com/ptv/vplay/24038772.html â˜†â˜†
☆☆ SDAutoLayout è¿›é˜¶ç‰ˆè§†é¢‘教程:http://www.letv.com/ptv/vplay/24381390.html â˜†â˜†
☆☆ SDAutoLayout åŽŸç†ç®€ä»‹è§†é¢‘æ•™ç¨‹ï¼šhttp://www.iqiyi.com/w_19rt0tec4p.html â˜†â˜†
☆☆ SDAutoLayout æœ‹å‹åœˆdemo视频教程:http://v.youku.com/v_show/id_XMTYzNzg2NzA0MA==.html â˜†â˜†
## éƒ¨åˆ†SDAutoLayout的DEMO:
完整微信Demo https://github.com/gsdios/GSD_WeiXin
![](http://ww3.sinaimg.cn/mw690/9b8146edgw1f1nm3pziawg205u0a0qv5.gif)![](http://ww1.sinaimg.cn/bmiddle/9b8146edgw1f06aoe2umhg206e0b4u0x.gif)![](http://ww4.sinaimg.cn/bmiddle/9b8146edgw1ezal3smihcg206y0ciqv5.gif)![](http://ww3.sinaimg.cn/mw690/9b8146edgw1f1nm3lweg3g207s0dcu0x.gif)![](http://ww2.sinaimg.cn/mw690/9b8146edgw1f23irukb0qg207i0dwu0x.gif)![](http://ww2.sinaimg.cn/bmiddle/9b8146edgw1eya1jv951ig208c0etqv5.gif)
#   ç”¨æ³•简介
## tableview和cell高度自适应:
####普通(简化)版【推荐使用】:tableview é«˜åº¦è‡ªé€‚应设置只需要2æ­¥
    1. >> è®¾ç½®cell高度自适应:
    // cell布局设置好之后调用此方法就可以实现高度自适应(注意:如果用高度自适应则不要再以cell的底边为参照去布局其子view)
    [cell setupAutoHeightWithBottomView:_view4 bottomMargin:10];
    2. >> èŽ·å–è‡ªåŠ¨è®¡ç®—å‡ºçš„cell高度
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        id model = self.modelsArray[indexPath.row];
        // èŽ·å–cell高度
        return [self.tableView cellHeightForIndexPath:indexPath model:model keyPath:@"model" cellClass:[DemoVC9Cell class]  contentViewWidth:cellContentViewWith];
    }
####升级版(适应于cell条数少于100的tableview):tableview é«˜åº¦è‡ªé€‚应设置只需要2æ­¥
    1. >> è®¾ç½®cell高度自适应:
    // cell布局设置好之后调用此方法就可以实现高度自适应(注意:如果用高度自适应则不要再以cell的底边为参照去布局其子view)
    [cell setupAutoHeightWithBottomView:_view4 bottomMargin:10];
    2. >> èŽ·å–è‡ªåŠ¨è®¡ç®—å‡ºçš„cell高度
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    // èŽ·å–cell高度
    return [self cellHeightForIndexPath:indexPath cellContentViewWidth:[UIScreen mainScreen].bounds.size.width];
    }
## æ™®é€šview的自动布局:
#### ç”¨æ³•示例
    /* ç”¨æ³•一 */
    _view.sd_layout
    .leftSpaceToView(self.view, 10)
    .topSpaceToView(self.view, 80)
    .heightIs(130)
    .widthRatioToView(self.view, 0.4);
    /* ç”¨æ³•二 ï¼ˆä¸€è¡Œä»£ç æžå®šï¼Œå…¶å®žç”¨æ³•一也是一行代码) */
    _view.sd_layout.leftSpaceToView(self.view, 10).topSpaceToView(self.view,80).heightIs(130).widthRatioToView(self.view, 0.4);
    >> UILabel文字自适应:
    // autoHeightRatio() ä¼ 0则根据文字自动计算高度(传大于0的值则根据此数值设置高度和宽度的比值)
    _label.sd_layout.autoHeightRatio(0);
    *******************************************************************************
        æ³¨æ„:先把需要自动布局的view加入父view然后在进行自动布局,例:
        UIView *view0 = [UIView new];
        UIView *view1 = [UIView new];
        [self.view addSubview:view0];
        [self.view addSubview:view1];
        view0.sd_layout
        .leftSpaceToView(self.view, 10)
        .topSpaceToView(self.view, 80)
        .heightIs(100)
        .widthRatioToView(self.view, 0.4);
        view1.sd_layout
        .leftSpaceToView(view0, 10)
        .topEqualToView(view0)
        .heightRatioToView(view0, 1)
        .rightSpaceToView(self.view, 10);
    *******************************************************************************
#### è‡ªåŠ¨å¸ƒå±€ç”¨æ³•ç®€æž
![](http://ww1.sinaimg.cn/mw690/9b8146edgw1ex4or5ixkjj20k60gw3zg.jpg)
   1.1 > leftSpaceToView(self.view, 10)
   æ–¹æ³•名中带有“SpaceToView”的方法表示到某个参照view的间距,需要传递2个参数:(UIView)参照view å’Œ ï¼ˆCGFloat)间距数值
   1.2 > widthRatioToView(self.view, 1)
   æ–¹æ³•名中带有“RatioToView”的方法表示view的宽度或者高度等属性相对于参照view的对应属性值的比例,需要传递2个参数:(UIView)参照view å’Œ ï¼ˆCGFloat)倍数
   1.3 > topEqualToView(view)
   æ–¹æ³•名中带有“EqualToView”的方法表示view的某一属性等于参照view的对应的属性值,需要传递1个参数:(UIView)参照view
   1.4 > widthIs(100)
   æ–¹æ³•名中带有“Is”的方法表示view的某一属性值等于参数数值,需要传递1个参数:(CGFloat)数值
# PS
// å¦‚果需要用“断言”调试程序请打开此宏(位于UIView+SDAutoLayout.h)
//#define SDDebugWithAssert
![](http://ww3.sinaimg.cn/bmiddle/9b8146edgw1ex4mukixr6g209g07lhdt.gif)
![](http://upload-images.jianshu.io/upload_images/1157161-07fa43e0f539ebad.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](http://upload-images.jianshu.io/upload_images/1157161-453a5d33d7f3d48d.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
Pods/SDAutoLayout/SDAutoLayoutDemo/SDAutoLayout/SDAutoLayout.h
New file
@@ -0,0 +1,24 @@
//
//  SDAutoLayout.h
//  SDAutoLayoutDemo
//
//  Created by gsd on 16/6/27.
//  Copyright Â© 2016å¹´ gsd. All rights reserved.
//
/*
 SDAutoLayout
 ç‰ˆæœ¬ï¼š2.1.7
 å‘布:2016.08.12
 */
#ifndef SDAutoLayout_h
#define SDAutoLayout_h
#import "UIView+SDAutoLayout.h"
#import "UITableView+SDAutoTableViewCellHeight.h"
#endif
Pods/SDAutoLayout/SDAutoLayoutDemo/SDAutoLayout/UITableView+SDAutoTableViewCellHeight.h
New file
@@ -0,0 +1,169 @@
//
//  UITableView+SDAutoTableViewCellHeight.h
//  SDAutoLayout æµ‹è¯• Demo
//
//  Created by aier on 15/11/1.
//  Copyright Â© 2015å¹´ gsd. All rights reserved.
//
/*
 *********************************************************************************
 *                                                                                *
 * åœ¨æ‚¨ä½¿ç”¨æ­¤è‡ªåŠ¨å¸ƒå±€åº“çš„è¿‡ç¨‹ä¸­å¦‚æžœå‡ºçŽ°bug请及时以以下任意一种方式联系我们,我们会及时修复bugå¹¶  *
 * å¸®æ‚¨è§£å†³é—®é¢˜ã€‚                                                                    *
 * QQ    : 2689718696(gsdios)                                                      *
 * Email : gsdios@126.com                                                          *
 * GitHub: https://github.com/gsdios                                               *
 * æ–°æµªå¾®åš:GSD_iOS                                                                 *
 *                                                                                *
 *********************************************************************************
 */
/*
 PS:cell高度自适应前提>>应该调用cell的“- (void)setupAutoHeightWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin”方法进行cell的自动高度设置
 */
#import <UIKit/UIKit.h>
#import "UIView+SDAutoLayout.h"
@class SDCellAutoHeightManager;
typedef void (^AutoCellHeightDataSettingBlock)(UITableViewCell *cell);
#define kSDModelCellTag 199206
#pragma mark - UITableView æ–¹æ³•,返回自动计算出的cell高度
@interface UITableView (SDAutoTableViewCellHeight)
@property (nonatomic, strong) SDCellAutoHeightManager *cellAutoHeightManager;
/**
 * è¿”回计算出的cell高度(普通简化版方法,同样只需一步设置即可完成)(用法:单cell详见demo5,多cell详见demo7)
 * model              : cell的数据模型实例
 * keyPath            : cell的数据模型属性的属性名字符串(即kvc原理中的key)
 * cellClass          : å½“前的indexPath对应的cell的class
 * contentViewWidth   : cell的contentView的宽度
 */
- (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath cellClass:(Class)cellClass contentViewWidth:(CGFloat)contentViewWidth;
/**
 * è¿”回计算出的cell高度(普通简化版方法,同样只需一步设置即可完成)(用法:见DemoVC14)
 * cellClass          : å½“前的indexPath对应的cell的class
 * contentViewWidth   : cell的contentView的宽度
 * cellDataSetting    : è®¾ç½®cell数据的block
 */
- (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellClass:(Class)cellClass cellContentViewWidth:(CGFloat)width cellDataSetting:(AutoCellHeightDataSettingBlock)cellDataSetting;
/** åˆ·æ–°tableView但不清空之前已经计算好的高度缓存,用于直接将新数据拼接在旧数据之后的tableView刷新 */
- (void)reloadDataWithExistedHeightCache;
/** åˆ·æ–°tableView同时调整已经计算好的高度缓存,用于直接将新数据插在旧数据前面的tableView的刷新 */
- (void)reloadDataWithInsertingDataAtTheBeginingOfSection:(NSInteger)section newDataCount:(NSInteger)count;
/**
 * åˆ·æ–°tableView同时调整已经计算好的高度缓存,用于直接将新数据插在旧数据前面的tableView的刷新(用于刷新多个section)
 * sectionNumsArray : è¦åˆ·æ–°çš„æ‰€æœ‰section序号组成的数组, ä¾‹@[@(0), @(1)]
 * dataCountsArray  : æ¯ä¸ªsection的数据条数组成的数组, ä¾‹@[@(20), @(10)]
 */
- (void)reloadDataWithInsertingDataAtTheBeginingOfSections:(NSArray *)sectionNumsArray newDataCounts:(NSArray *)dataCountsArray;
/** è¿”回所有cell的高度总和  */
- (CGFloat)cellsTotalHeight;
@property (nonatomic, copy) AutoCellHeightDataSettingBlock cellDataSetting;
@end
#pragma mark - UITableViewController æ–¹æ³•,返回自动计算出的cell高度
@interface UITableViewController (SDTableViewControllerAutoCellHeight)
/** (UITableViewController方法)升级版!一行代码(一步设置)搞定tableview的cell高度自适应,同时适用于单cell和多cell,性能比普通版稍微差一些,不建议在数据量大的tableview中使用  */
- (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellContentViewWidth:(CGFloat)width;
@end
#pragma mark - NSObject æ–¹æ³•,返回自动计算出的cell高度
@interface NSObject (SDAnyObjectAutoCellHeight)
/** (NSObject方法)升级版!一行代码(一步设置)搞定tableview的cell高度自适应,同时适用于单cell和多cell,性能比普通版稍微差一些,不建议在数据量大的tableview中使用  */
- (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellContentViewWidth:(CGFloat)width tableView:(UITableView *)tableView;
@end
// ------------------------------- ä»¥ä¸‹ä¸ºåº“内部使用无须了解 --------------------
@interface SDCellAutoHeightManager : NSObject
@property (nonatomic, assign) BOOL shouldKeepHeightCacheWhenReloadingData;
@property (nonatomic, assign) CGFloat contentViewWidth;
@property (nonatomic, assign) Class cellClass;
@property (nonatomic, assign) CGFloat cellHeight;
@property (nonatomic, strong) UITableViewCell *modelCell;
@property (nonatomic, strong) NSMutableDictionary *subviewFrameCacheDict;
@property (nonatomic, strong, readonly) NSDictionary *heightCacheDict;
@property (nonatomic, copy) AutoCellHeightDataSettingBlock cellDataSetting;
- (void)clearHeightCache;
- (void)clearHeightCacheOfIndexPaths:(NSArray *)indexPaths;
- (void)deleteThenResetHeightCache:(NSIndexPath *)indexPathToDelete;
- (void)insertNewDataAtTheBeginingOfSection:(NSInteger)section newDataCount:(NSInteger)count;
- (void)insertNewDataAtIndexPaths:(NSArray *)indexPaths;
- (NSNumber *)heightCacheForIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath;
- (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath cellClass:(Class)cellClass;
- (NSMutableArray *)subviewFrameCachesWithIndexPath:(NSIndexPath *)indexPath;;
- (void)setSubviewFrameCache:(CGRect)rect WithIndexPath:(NSIndexPath *)indexPath;
- (instancetype)initWithCellClass:(Class)cellClass tableView:(UITableView *)tableView;
+ (instancetype)managerWithCellClass:(Class)cellClass tableView:(UITableView *)tableView;
@end
Pods/SDAutoLayout/SDAutoLayoutDemo/SDAutoLayout/UITableView+SDAutoTableViewCellHeight.m
New file
@@ -0,0 +1,537 @@
//
//  UITableView+SDAutoTableViewCellHeight.m
//  SDAutoLayout æµ‹è¯• Demo
//
//  Created by aier on 15/11/1.
//  Copyright Â© 2015å¹´ gsd. All rights reserved.
//
/*
 *********************************************************************************
 *                                                                                *
 * åœ¨æ‚¨ä½¿ç”¨æ­¤è‡ªåŠ¨å¸ƒå±€åº“çš„è¿‡ç¨‹ä¸­å¦‚æžœå‡ºçŽ°bug请及时以以下任意一种方式联系我们,我们会及时修复bugå¹¶  *
 * å¸®æ‚¨è§£å†³é—®é¢˜ã€‚                                                                    *
 * QQ    : 2689718696(gsdios)                                                      *
 * Email : gsdios@126.com                                                          *
 * GitHub: https://github.com/gsdios                                               *
 * æ–°æµªå¾®åš:GSD_iOS                                                                 *
 *                                                                                *
 *********************************************************************************
 */
#import "UITableView+SDAutoTableViewCellHeight.h"
#import <objc/runtime.h>
@interface SDCellAutoHeightManager ()
@property (nonatomic, weak) UITableView *modelTableview;
@end
@implementation SDCellAutoHeightManager
{
    NSMutableDictionary *_cacheDictionary;
    NSMutableDictionary *_modelCellsDict;
}
- (instancetype)init
{
    if (self = [super init]) {
        [self setup];
    }
    return self;
}
- (instancetype)initWithCellClass:(Class)cellClass tableView:(UITableView *)tableView
{
    if (self = [super init]) {
        [self setup];
        self.modelTableview = tableView;
        [self registerCellWithCellClass:cellClass];
    }
    return self;
}
- (instancetype)initWithCellClasses:(NSArray *)cellClassArray tableView:(UITableView *)tableView
{
    if (self = [super init]) {
        [self setup];
        self.modelTableview = tableView;
        [cellClassArray enumerateObjectsUsingBlock:^(Class obj, NSUInteger idx, BOOL *stop) {
            [self registerCellWithCellClass:obj];
        }];
    }
    return self;
}
- (void)setup
{
    _cacheDictionary = [NSMutableDictionary new];
    _modelCellsDict = [NSMutableDictionary new];
}
- (void)registerCellWithCellClass:(Class)cellClass
{
    [_modelTableview registerClass:cellClass forCellReuseIdentifier:NSStringFromClass(cellClass)];
    self.modelCell = [_modelTableview dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass)];
    if (!self.modelCell.contentView.subviews.count) {
        NSString *path = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@.nib", NSStringFromClass(cellClass)] ofType:nil];
        if (path) {
            self.modelCell = nil;
            [_modelTableview registerNib:[UINib nibWithNibName:NSStringFromClass(cellClass) bundle:nil] forCellReuseIdentifier:NSStringFromClass(cellClass)];
            self.modelCell = [_modelTableview dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass)];
        }
    }
    if (self.modelCell) {
        [_modelCellsDict setObject:self.modelCell forKey:NSStringFromClass(cellClass)];
    }
}
+ (instancetype)managerWithCellClass:(Class)cellClass tableView:(UITableView *)tableView
{
    SDCellAutoHeightManager *manager = [[self alloc] initWithCellClass:cellClass tableView:tableView];
    return manager;
}
- (UITableViewCell *)modelCell
{
    if (_modelCell.contentView.tag != kSDModelCellTag) {
        _modelCell.contentView.tag = kSDModelCellTag;
    }
    return _modelCell;
}
- (NSDictionary *)heightCacheDict
{
    return _cacheDictionary;
}
- (void)clearHeightCache
{
    [_cacheDictionary removeAllObjects];
    [_subviewFrameCacheDict removeAllObjects];
}
- (NSString *)cacheKeyForIndexPath:(NSIndexPath *)indexPath
{
    return [NSString stringWithFormat:@"%ld-%ld", (long)indexPath.section, (long)indexPath.row];
}
- (void)clearHeightCacheOfIndexPaths:(NSArray *)indexPaths
{
    [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
        NSString *cacheKey = [self cacheKeyForIndexPath:indexPath];
        [_cacheDictionary removeObjectForKey:cacheKey];
        [_subviewFrameCacheDict removeObjectForKey:cacheKey];
    }];
}
- (void)deleteThenResetHeightCache:(NSIndexPath *)indexPathToDelete
{
    NSString *cacheKey = [self cacheKeyForIndexPath:indexPathToDelete];
    [_cacheDictionary removeObjectForKey:cacheKey];
    [_subviewFrameCacheDict removeObjectForKey:cacheKey];
    long sectionOfToDeleteItem = indexPathToDelete.section;
    long rowOfToDeleteItem = indexPathToDelete.row;
    NSMutableDictionary *tempHeightCacheDict = [NSMutableDictionary new];
    NSMutableDictionary *tempFrameCacheDict = [NSMutableDictionary new];
    for (NSString *key in _cacheDictionary.allKeys) {
        NSArray *res = [key componentsSeparatedByString:@"-"];
        long section = [res.firstObject integerValue];
        long row = [res.lastObject integerValue];
        if (section == sectionOfToDeleteItem && row > rowOfToDeleteItem) {
            NSNumber *heightCache = _cacheDictionary[key];
            NSArray *frameCache = _subviewFrameCacheDict[key];
            NSString *newKey = [NSString stringWithFormat:@"%ld-%ld", section, (row - 1)];
            [tempHeightCacheDict setValue:heightCache forKey:newKey];
            [tempFrameCacheDict setValue:frameCache forKey:newKey];
            [_cacheDictionary removeObjectForKey:key];
            [_subviewFrameCacheDict removeObjectForKey:key];
        }
    }
    [_cacheDictionary addEntriesFromDictionary:tempHeightCacheDict];
    [_subviewFrameCacheDict addEntriesFromDictionary:tempFrameCacheDict];
}
- (void)insertNewDataAtTheBeginingOfSection:(NSInteger)section newDataCount:(NSInteger)count
{
    NSMutableDictionary *tempHeightCacheDict = [NSMutableDictionary new];
    NSMutableDictionary *tempFrameCacheDict = [NSMutableDictionary new];
    for (NSString *key in _cacheDictionary.allKeys) {
        NSArray *res = [key componentsSeparatedByString:@"-"];
        long originalSection = [res.firstObject integerValue];
        long row = [res.lastObject integerValue];
        if (originalSection == section) {
            NSNumber *heightCache = _cacheDictionary[key];
            NSArray *frameCache = _subviewFrameCacheDict[key];
            NSString *newKey = [NSString stringWithFormat:@"%ld-%ld", originalSection, (row + count)];
            [tempHeightCacheDict setValue:heightCache forKey:newKey];
            [tempFrameCacheDict setValue:frameCache forKey:newKey];
            [_cacheDictionary removeObjectForKey:key];
            [_subviewFrameCacheDict removeObjectForKey:key];
        }
    }
    [_cacheDictionary addEntriesFromDictionary:tempHeightCacheDict];
    [_subviewFrameCacheDict addEntriesFromDictionary:tempFrameCacheDict];
}
- (void)insertNewDataAtIndexPaths:(NSArray *)indexPaths
{
    NSMutableDictionary *sectionsdict = [NSMutableDictionary new];
    for (NSIndexPath *indexPath in indexPaths) {
        NSString *sectionkey = [@(indexPath.section) stringValue];
        if (![sectionsdict objectForKey:sectionkey]) {
            [sectionsdict setValue:[NSMutableArray new] forKey:sectionkey];
        }
        NSMutableArray *arr = sectionsdict[sectionkey];
        [arr addObject:indexPath];
    }
    for (NSString *sectionkey in sectionsdict.allKeys) {
        NSMutableArray *tempHeightCaches = [NSMutableArray new];
        NSMutableArray *tempFrameCaches = [NSMutableArray new];
        NSInteger section = [sectionkey integerValue];
        NSInteger rowCount = [self.modelTableview numberOfRowsInSection:section];
        if (rowCount <= 0) {
            continue;
        } else {
            for (int i = 0; i < rowCount; i++) {
                [tempHeightCaches addObject:[NSNull null]];
                [tempFrameCaches addObject:[NSNull null]];
            }
        }
        for (NSString *key in _cacheDictionary.allKeys) {
            NSArray *res = [key componentsSeparatedByString:@"-"];
            long originalSection = [res.firstObject integerValue];
            long row = [res.lastObject integerValue];
            if (originalSection == section) {
                NSNumber *heightCache = _cacheDictionary[key];
                NSArray *frameCache = _subviewFrameCacheDict[key];
                [tempHeightCaches setObject:heightCache atIndexedSubscript:row];
                [tempFrameCaches setObject:frameCache atIndexedSubscript:row];
                [_cacheDictionary removeObjectForKey:key];
                [_subviewFrameCacheDict removeObjectForKey:key];
            }
        }
        NSMutableArray *objsToInsert = [NSMutableArray new];
        NSMutableIndexSet *indexSet = [NSMutableIndexSet new];
        NSArray *indexPaths = sectionsdict[sectionkey];
        [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *obj, NSUInteger idx, BOOL *stop) {
            [objsToInsert addObject:[NSNull null]];
            [indexSet addIndex:obj.row];
        }];
        [tempHeightCaches insertObjects:objsToInsert atIndexes:indexSet];
        [tempFrameCaches insertObjects:objsToInsert atIndexes:indexSet];
        [tempHeightCaches enumerateObjectsUsingBlock:^(NSNumber *heightCache, NSUInteger idx, BOOL *stop) {
            if (![heightCache isKindOfClass:[NSNull class]]) {
                NSString *key = [NSString stringWithFormat:@"%zd-%zd", section, idx];
                [_cacheDictionary setValue:heightCache forKey:key];
                [_subviewFrameCacheDict setValue:[tempFrameCaches objectAtIndex:idx] forKey:key];
            }
        }];
    }
}
- (NSNumber *)heightCacheForIndexPath:(NSIndexPath *)indexPath
{
    /*
     å¦‚果程序卡在了这里很可能是由于你用了“dequeueReusableCellWithIdentifier:forIndexPath:”方法来重用cell,换成““dequeueReusableCellWithIdentifier:”(不带IndexPath)方法即可解决
     */
    NSString *cacheKey = [self cacheKeyForIndexPath:indexPath];
    return (NSNumber *)[_cacheDictionary objectForKey:cacheKey];
}
- (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath
{
    NSNumber *cacheHeight = [self heightCacheForIndexPath:indexPath];
    if (cacheHeight) {
        return [cacheHeight floatValue];
    } else {
        if (!self.modelCell) {
            return 0;
        }
        if (self.modelTableview && self.modelTableview != self.modelCell.sd_tableView) {
            self.modelCell.sd_tableView = self.modelTableview;
        }
        self.modelCell.sd_indexPath = indexPath;
        if (model && keyPath) {
            [self.modelCell setValue:model forKey:keyPath];
        } else if (self.cellDataSetting) {
            self.cellDataSetting(self.modelCell);
        }
#ifdef SDDebugWithAssert
        /*
         å¦‚果程序卡在了这里说明你的cell还没有调用“setupAutoHeightWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin”方法或者你传递的bottomView为nil,请检查并修改。例:
         //注意:bottomView不能为nil
         [cell setupAutoHeightWithBottomView:bottomView bottomMargin:bottomMargin];
         */
        NSAssert(self.modelCell.sd_bottomViewsArray.count, @">>>>>> ä½ çš„cell还没有调用“setupAutoHeightWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin”方法或者你传递的bottomView为nil,请检查并修改");
#endif
        [self.modelCell.contentView layoutSubviews];
        NSString *cacheKey = [self cacheKeyForIndexPath:indexPath];
        [_cacheDictionary setObject:@(self.modelCell.autoHeight) forKey:cacheKey];
        if (self.modelCell.sd_indexPath && self.modelCell.sd_tableView) {
            if (self.modelCell.contentView.shouldReadjustFrameBeforeStoreCache) {
                self.modelCell.contentView.height_sd = self.modelCell.autoHeight;
                [self.modelCell.contentView layoutSubviews];
            }
            [self.modelCell.contentView.autoLayoutModelsArray enumerateObjectsUsingBlock:^(SDAutoLayoutModel *model, NSUInteger idx, BOOL *stop) {
                [self.modelTableview.cellAutoHeightManager setSubviewFrameCache:model.needsAutoResizeView.frame WithIndexPath:self.modelCell.sd_indexPath];
            }];
        }
        return self.modelCell.autoHeight;
    }
}
- (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath cellClass:(Class)cellClass
{
    if (![self.modelCell isKindOfClass:cellClass]) {
        self.modelCell = nil;
        self.modelCell = [_modelCellsDict objectForKey:NSStringFromClass(cellClass)];
        if (!self.modelCell) {
            [self registerCellWithCellClass:cellClass];
        }
        _modelCell.contentView.tag = kSDModelCellTag;
    }
    if (self.modelCell.contentView.width_sd != self.contentViewWidth) {
        _modelCell.contentView.width_sd = self.contentViewWidth;
    }
    return [self cellHeightForIndexPath:indexPath model:model keyPath:keyPath];
}
- (void)setContentViewWidth:(CGFloat)contentViewWidth
{
    if (_contentViewWidth == contentViewWidth) return;
    CGFloat lastContentViewWidth = _contentViewWidth;
    _contentViewWidth = contentViewWidth;
    self.modelCell.contentView.width_sd = self.contentViewWidth;
    if (lastContentViewWidth > 0) {
        [_subviewFrameCacheDict removeAllObjects];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self clearHeightCache];
            [self.modelTableview reloadData];
        });
    }
}
- (void)setSubviewFrameCache:(CGRect)rect WithIndexPath:(NSIndexPath *)indexPath
{
    if (!self.subviewFrameCacheDict) {
        self.subviewFrameCacheDict = [NSMutableDictionary new];
    }
    NSString *cacheKey = [self cacheKeyForIndexPath:indexPath];
    NSMutableArray *caches = [self.subviewFrameCacheDict objectForKey:cacheKey];
    if (!caches) {
        caches = [NSMutableArray new];
        [self.subviewFrameCacheDict setValue:caches forKey:cacheKey];
    }
    [caches addObject:[NSValue valueWithCGRect:rect]];
}
- (NSMutableArray *)subviewFrameCachesWithIndexPath:(NSIndexPath *)indexPath
{
    NSString *cacheKey = [self cacheKeyForIndexPath:indexPath];
    return [self.subviewFrameCacheDict valueForKey:cacheKey];
}
@end
@implementation UITableView (SDAutoTableViewCellHeight)
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSArray *selStringsArray = @[@"reloadData", @"reloadRowsAtIndexPaths:withRowAnimation:", @"deleteRowsAtIndexPaths:withRowAnimation:", @"insertRowsAtIndexPaths:withRowAnimation:"];
        [selStringsArray enumerateObjectsUsingBlock:^(NSString *selString, NSUInteger idx, BOOL *stop) {
            NSString *mySelString = [@"sd_" stringByAppendingString:selString];
            Method originalMethod = class_getInstanceMethod(self, NSSelectorFromString(selString));
            Method myMethod = class_getInstanceMethod(self, NSSelectorFromString(mySelString));
            method_exchangeImplementations(originalMethod, myMethod);
        }];
    });
}
- (void)sd_reloadData
{
    if (!self.cellAutoHeightManager.shouldKeepHeightCacheWhenReloadingData) {
        [self.cellAutoHeightManager clearHeightCache];
    }
    [self sd_reloadData];
    self.cellAutoHeightManager.shouldKeepHeightCacheWhenReloadingData = NO;
}
- (void)sd_reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
{
    [self.cellAutoHeightManager clearHeightCacheOfIndexPaths:indexPaths];
    [self sd_reloadRowsAtIndexPaths:indexPaths withRowAnimation:animation];
}
- (void)sd_deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
{
    for (NSIndexPath *indexPath in indexPaths) {
        [self.cellAutoHeightManager deleteThenResetHeightCache:indexPath];
    }
    [self sd_deleteRowsAtIndexPaths:indexPaths withRowAnimation:animation];
}
- (void)sd_insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
{
    [self.cellAutoHeightManager insertNewDataAtIndexPaths:indexPaths];
    [self sd_insertRowsAtIndexPaths:indexPaths withRowAnimation:animation];
}
/*
 * ä¸‹ä¸€æ­¥å³å°†å®žçŽ°çš„åŠŸèƒ½
 - (void)sd_moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath
 {
 [self sd_moveRowAtIndexPath:indexPath toIndexPath:newIndexPath];
 }
 */
- (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath cellClass:(Class)cellClass contentViewWidth:(CGFloat)contentViewWidth
{
    self.cellAutoHeightManager.modelTableview = self;
    self.cellAutoHeightManager.contentViewWidth = contentViewWidth;
    return [self.cellAutoHeightManager cellHeightForIndexPath:indexPath model:model keyPath:keyPath cellClass:cellClass];
}
- (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellClass:(__unsafe_unretained Class)cellClass cellContentViewWidth:(CGFloat)width cellDataSetting:(AutoCellHeightDataSettingBlock)cellDataSetting
{
    self.cellDataSetting = cellDataSetting;
    return [self cellHeightForIndexPath:indexPath model:nil keyPath:nil cellClass:cellClass contentViewWidth:width];
}
- (void)reloadDataWithExistedHeightCache
{
    self.cellAutoHeightManager.shouldKeepHeightCacheWhenReloadingData = YES;
    [self reloadData];
}
- (void)reloadDataWithInsertingDataAtTheBeginingOfSection:(NSInteger)section newDataCount:(NSInteger)count
{
    self.cellAutoHeightManager.shouldKeepHeightCacheWhenReloadingData = YES;
    [self.cellAutoHeightManager insertNewDataAtTheBeginingOfSection:section newDataCount:count];
    [self reloadData];
}
- (void)reloadDataWithInsertingDataAtTheBeginingOfSections:(NSArray *)sectionNumsArray newDataCounts:(NSArray *)dataCountsArray
{
    self.cellAutoHeightManager.shouldKeepHeightCacheWhenReloadingData = YES;
    [sectionNumsArray enumerateObjectsUsingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop) {
        int section = [num intValue];
        int dataCountForSection = [dataCountsArray[idx] intValue];
        [self.cellAutoHeightManager insertNewDataAtTheBeginingOfSection:section newDataCount:dataCountForSection];
    }];
    [self reloadData];
}
- (CGFloat)cellsTotalHeight
{
    CGFloat h = 0;
    if (!self.cellAutoHeightManager.heightCacheDict.count) {
        [self reloadData];
    }
    NSArray *values = [self.cellAutoHeightManager.heightCacheDict allValues];
    for (NSNumber *number in values) {
        h += [number floatValue];
    }
    return h;
}
- (SDCellAutoHeightManager *)cellAutoHeightManager
{
    SDCellAutoHeightManager *cellAutoHeightManager = objc_getAssociatedObject(self, _cmd);
    if (!cellAutoHeightManager) {
        cellAutoHeightManager = [[SDCellAutoHeightManager alloc] init];
        [self setCellAutoHeightManager:cellAutoHeightManager];
    }
    return cellAutoHeightManager;
}
- (void)setCellAutoHeightManager:(SDCellAutoHeightManager *)cellAutoHeightManager
{
    objc_setAssociatedObject(self, @selector(cellAutoHeightManager), cellAutoHeightManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)setCellDataSetting:(AutoCellHeightDataSettingBlock)cellDataSetting
{
    self.cellAutoHeightManager.cellDataSetting = cellDataSetting;
}
- (AutoCellHeightDataSettingBlock)cellDataSetting
{
    return self.cellAutoHeightManager.cellDataSetting;
}
@end
@implementation UITableViewController (SDTableViewControllerAutoCellHeight)
- (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellContentViewWidth:(CGFloat)width
{
    return [self cellHeightForIndexPath:indexPath cellContentViewWidth:width tableView:self.tableView];
}
@end
@implementation NSObject (SDAnyObjectAutoCellHeight)
- (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellContentViewWidth:(CGFloat)width tableView:(UITableView *)tableView
{
    tableView.cellAutoHeightManager.modelTableview = tableView;
    if (tableView.cellAutoHeightManager.contentViewWidth != width) {
        tableView.cellAutoHeightManager.contentViewWidth = width;
    }
    if ([tableView.cellAutoHeightManager heightCacheForIndexPath:indexPath]) {
        return [[tableView.cellAutoHeightManager heightCacheForIndexPath:indexPath] floatValue];
    }
    UITableViewCell *cell = [tableView.dataSource tableView:tableView cellForRowAtIndexPath:indexPath];
    tableView.cellAutoHeightManager.modelCell = cell;
    if (cell.contentView.width_sd != width) {
        cell.contentView.width_sd = width;
    }
    return [[tableView cellAutoHeightManager] cellHeightForIndexPath:indexPath model:nil keyPath:nil];
}
@end
Pods/SDAutoLayout/SDAutoLayoutDemo/SDAutoLayout/UIView+SDAutoLayout.h
New file
@@ -0,0 +1,484 @@
//
//  UIView+SDAutoLayout.h
//
//  Created by gsd on 15/10/6.
//  Copyright (c) 2015å¹´ gsd. All rights reserved.
//
/*
 *************************************************************************
 --------- INTRODUCTION ---------
 USAGE:
 MODE 1. >>>>>>>>>>>>>>> You can use it in this way:
 Demo.sd_layout
 .topSpaceToView(v1, 100)
 .bottomSpaceToView(v3, 100)
 .leftSpaceToView(v0, 150)
 .rightSpaceToView(v2, 150);
 MODE 2. >>>>>>>>>>>>>>> You can also use it in this way that is more brevity:
 Demo.sd_layout.topSpaceToView(v1, 100).bottomSpaceToView(v3, 100).leftSpaceToView(v0, 150).rightSpaceToView(v2, 150);
 *************************************************************************
 */
/*
 *********************************************************************************
 *
 * åœ¨æ‚¨ä½¿ç”¨æ­¤è‡ªåŠ¨å¸ƒå±€åº“çš„è¿‡ç¨‹ä¸­å¦‚æžœå‡ºçŽ°bug请及时以以下任意一种方式联系我们,我们会及时修复bugå¹¶
 * å¸®æ‚¨è§£å†³é—®é¢˜ã€‚
 * QQ    : 2689718696(gsdios)
 * Email : gsdios@126.com
 * GitHub: https://github.com/gsdios
 * æ–°æµªå¾®åš:GSD_iOS
 *
 * è§†é¢‘教程:http://www.letv.com/ptv/vplay/24038772.html
 * ç”¨æ³•示例:https://github.com/gsdios/SDAutoLayout/blob/master/README.md
 *
 *********************************************************************************
 SDAutoLayout
 ç‰ˆæœ¬ï¼š2.1.7
 å‘布:2016.08.12
 */
// å¦‚果需要用“断言”调试程序请打开此宏
//#define SDDebugWithAssert
#import <UIKit/UIKit.h>
@class SDAutoLayoutModel, SDUIViewCategoryManager;
typedef SDAutoLayoutModel *(^MarginToView)(id viewOrViewsArray, CGFloat value);
typedef SDAutoLayoutModel *(^Margin)(CGFloat value);
typedef SDAutoLayoutModel *(^MarginEqualToView)(UIView *toView);
typedef SDAutoLayoutModel *(^WidthHeight)(CGFloat value);
typedef SDAutoLayoutModel *(^WidthHeightEqualToView)(UIView *toView, CGFloat ratioValue);
typedef SDAutoLayoutModel *(^AutoHeightWidth)(CGFloat ratioValue);
typedef SDAutoLayoutModel *(^SameWidthHeight)();
typedef SDAutoLayoutModel *(^Offset)(CGFloat value);
typedef void (^SpaceToSuperView)(UIEdgeInsets insets);
@interface SDAutoLayoutModel : NSObject
/*
 *************************说明************************
 æ–¹æ³•名中带有“SpaceToView”的需要传递2个参数:(UIView)参照view å’Œ ï¼ˆCGFloat)间距数值
 æ–¹æ³•名中带有“RatioToView”的需要传递2个参数:(UIView)参照view å’Œ ï¼ˆCGFloat)倍数
 æ–¹æ³•名中带有“EqualToView”的需要传递1个参数:(UIView)参照view
 æ–¹æ³•名中带有“Is”的需要传递1个参数:(CGFloat)数值
 *****************************************************
 */
/* è®¾ç½®è·ç¦»å…¶å®ƒview的间距 */
/** å·¦è¾¹åˆ°å…¶å‚ç…§view之间的间距,参数为“(View æˆ–者 view数组, CGFloat)”  */
@property (nonatomic, copy, readonly) MarginToView leftSpaceToView;
/** å³è¾¹åˆ°å…¶å‚ç…§view之间的间距,参数为“(View, CGFloat)”  */
@property (nonatomic, copy, readonly) MarginToView rightSpaceToView;
/** é¡¶éƒ¨åˆ°å…¶å‚ç…§view之间的间距,参数为“(View æˆ–者 view数组, CGFloat)”  */
@property (nonatomic, copy, readonly) MarginToView topSpaceToView;
/** åº•部到其参照view之间的间距,参数为“(View, CGFloat)”  */
@property (nonatomic, copy, readonly) MarginToView bottomSpaceToView;
/* è®¾ç½®x、y、width、height、centerX、centerY å€¼ */
/** x值,参数为“(CGFloat)”  */
@property (nonatomic, copy, readonly) Margin xIs;
/** y值,参数为“(CGFloat)”  */
@property (nonatomic, copy, readonly) Margin yIs;
/** centerX值,参数为“(CGFloat)”  */
@property (nonatomic, copy, readonly) Margin centerXIs;
/** centerY值,参数为“(CGFloat)”  */
@property (nonatomic, copy, readonly) Margin centerYIs;
/** å®½åº¦å€¼ï¼Œå‚数为“(CGFloat)”  */
@property (nonatomic, copy, readonly) WidthHeight widthIs;
/** é«˜åº¦å€¼ï¼Œå‚数为“(CGFloat)”  */
@property (nonatomic, copy, readonly) WidthHeight heightIs;
/* è®¾ç½®æœ€å¤§å®½åº¦å’Œé«˜åº¦ã€æœ€å°å®½åº¦å’Œé«˜åº¦ */
/** æœ€å¤§å®½åº¦å€¼ï¼Œå‚数为“(CGFloat)”  */
@property (nonatomic, copy, readonly) WidthHeight maxWidthIs;
/** æœ€å¤§é«˜åº¦å€¼ï¼Œå‚数为“(CGFloat)”  */
@property (nonatomic, copy, readonly) WidthHeight maxHeightIs;
/** æœ€å°å®½åº¦å€¼ï¼Œå‚数为“(CGFloat)”  */
@property (nonatomic, copy, readonly) WidthHeight minWidthIs;
/** æœ€å°é«˜åº¦å€¼ï¼Œå‚数为“(CGFloat)”  */
@property (nonatomic, copy, readonly) WidthHeight minHeightIs;
/* è®¾ç½®å’ŒæŸä¸ªå‚ç…§view的边距相同 */
/** å·¦é—´è·ä¸Žå‚ç…§view相同,参数为“(View)”  */
@property (nonatomic, copy, readonly) MarginEqualToView leftEqualToView;
/** å³é—´è·ä¸Žå‚ç…§view相同,参数为“(View)”  */
@property (nonatomic, copy, readonly) MarginEqualToView rightEqualToView;
/** é¡¶éƒ¨é—´è·ä¸Žå‚ç…§view相同,参数为“(View)”  */
@property (nonatomic, copy, readonly) MarginEqualToView topEqualToView;
/** åº•部间距与参照view相同,参数为“(View)”  */
@property (nonatomic, copy, readonly) MarginEqualToView bottomEqualToView;
/** centerX与参照view相同,参数为“(View)”  */
@property (nonatomic, copy, readonly) MarginEqualToView centerXEqualToView;
/** centerY与参照view相同,参数为“(View)”  */
@property (nonatomic, copy, readonly) MarginEqualToView centerYEqualToView;
/*  è®¾ç½®å®½åº¦æˆ–者高度等于参照view的多少倍 */
/** å®½åº¦æ˜¯å‚ç…§view宽度的多少倍,参数为“(View, CGFloat)” */
@property (nonatomic, copy, readonly) WidthHeightEqualToView widthRatioToView;
/** é«˜åº¦æ˜¯å‚ç…§view高度的多少倍,参数为“(View, CGFloat)” */
@property (nonatomic, copy, readonly) WidthHeightEqualToView heightRatioToView;
/** è®¾ç½®ä¸€ä¸ªview的宽度和它的高度相同,参数为空“()” */
@property (nonatomic, copy, readonly) SameWidthHeight widthEqualToHeight;
/** è®¾ç½®ä¸€ä¸ªview的高度和它的宽度相同,参数为空“()” */
@property (nonatomic, copy, readonly) SameWidthHeight heightEqualToWidth;
/** è‡ªé€‚应高度,传入高宽比值,label可以传0实现文字高度自适应 */
@property (nonatomic, copy, readonly) AutoHeightWidth autoHeightRatio;
/** è‡ªé€‚应宽度,参数为宽高比值 */
@property (nonatomic, copy, readonly) AutoHeightWidth autoWidthRatio;
/* å¡«å……父view(快捷方法) */
/** ä¼ å…¥UIEdgeInsetsMake(top, left, bottom, right),可以快捷设置view到其父view上左下右的间距  */
@property (nonatomic, copy, readonly) SpaceToSuperView spaceToSuperView;
/** è®¾ç½®åç§»é‡ï¼Œå‚数为“(CGFloat value),目前只有带有equalToView的方法可以设置offset” */
@property (nonatomic, copy, readonly) Offset offset;
@property (nonatomic, weak) UIView *needsAutoResizeView;
@end
#pragma mark - UIView é«˜åº¦ã€å®½åº¦è‡ªé€‚应相关方法
@interface UIView (SDAutoHeightWidth)
/** è®¾ç½®Cell的高度自适应,也可用于设置普通view内容高度自适应 */
- (void)setupAutoHeightWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin;
/** ç”¨äºŽè®¾ç½®æ™®é€šview内容宽度自适应 */
- (void)setupAutoWidthWithRightView:(UIView *)rightView rightMargin:(CGFloat)rightMargin;
/** è®¾ç½®Cell的高度自适应,也可用于设置普通view内容自适应(应用于当你不确定哪个view在自动布局之后会排布在最下方最为bottomView的时候可以调用次方法将所有可能在最下方的view都传过去) */
- (void)setupAutoHeightWithBottomViewsArray:(NSArray *)bottomViewsArray bottomMargin:(CGFloat)bottomMargin;
/** æ›´æ–°å¸ƒå±€ï¼ˆä¸»åŠ¨åˆ·æ–°å¸ƒå±€ï¼Œå¦‚æžœä½ éœ€è¦è®¾ç½®å®Œå¸ƒå±€ä»£ç å°±èŽ·å¾—view的frame请调用此方法) */
- (void)updateLayout;
/** æ›´æ–°cell内部的控件的布局(cell内部控件专属的更新约束方法,如果启用了cell frame缓存则会自动清除缓存再更新约束) */
- (void)updateLayoutWithCellContentView:(UIView *)cellContentView;
/** æ¸…空高度自适应设置  */
- (void)clearAutoHeigtSettings;
/** æ¸…空宽度自适应设置  */
- (void)clearAutoWidthSettings;
@property (nonatomic) CGFloat autoHeight;
@property (nonatomic, readonly) SDUIViewCategoryManager *sd_categoryManager;
@property (nonatomic, readonly) NSMutableArray *sd_bottomViewsArray;
@property (nonatomic) CGFloat sd_bottomViewBottomMargin;
@property (nonatomic) NSArray *sd_rightViewsArray;
@property (nonatomic) CGFloat sd_rightViewRightMargin;
@end
#pragma mark - UIView è®¾ç½®åœ†è§’半径、自动布局回调block等相关方法
@interface UIView (SDLayoutExtention)
/** è‡ªåŠ¨å¸ƒå±€å®ŒæˆåŽçš„å›žè°ƒblock,可以在这里获取到view的真实frame  */
@property (nonatomic) void (^didFinishAutoLayoutBlock)(CGRect frame);
/** æ·»åŠ ä¸€ç»„å­view  */
- (void)sd_addSubviews:(NSArray *)subviews;
/* è®¾ç½®åœ†è§’ */
/** è®¾ç½®åœ†è§’半径值  */
@property (nonatomic, strong) NSNumber *sd_cornerRadius;
/** è®¾ç½®åœ†è§’半径值为view宽度的多少倍  */
@property (nonatomic, strong) NSNumber *sd_cornerRadiusFromWidthRatio;
/** è®¾ç½®åœ†è§’半径值为view高度的多少倍  */
@property (nonatomic, strong) NSNumber *sd_cornerRadiusFromHeightRatio;
/** è®¾ç½®ç­‰å®½å­view(子view需要在同一水平方向) */
@property (nonatomic, strong) NSArray *sd_equalWidthSubviews;
@end
#pragma mark - UIView ä¹å®«æ ¼æµ®åŠ¨å¸ƒå±€æ•ˆæžœ
@interface UIView (SDAutoFlowItems)
/**
 * è®¾ç½®ç±»ä¼¼collectionView效果的固定间距自动宽度浮动子view
 * viewsArray       : éœ€è¦æµ®åŠ¨å¸ƒå±€çš„æ‰€æœ‰è§†å›¾
 * perRowItemsCount : æ¯è¡Œæ˜¾ç¤ºçš„视图个数
 * verticalMargin   : è§†å›¾ä¹‹é—´çš„垂直间距
 * horizontalMargin : è§†å›¾ä¹‹é—´çš„æ°´å¹³é—´è·
 * vInset           : ä¸Šä¸‹ç¼©è¿›å€¼
 * hInset           : å·¦å³ç¼©è¿›å€¼
 */
- (void)setupAutoWidthFlowItems:(NSArray *)viewsArray withPerRowItemsCount:(NSInteger)perRowItemsCount verticalMargin:(CGFloat)verticalMargin horizontalMargin:(CGFloat)horizontalMagin verticalEdgeInset:(CGFloat)vInset horizontalEdgeInset:(CGFloat)hInset;
/** æ¸…除固定间距自动宽度浮动子view设置 */
- (void)clearAutoWidthFlowItemsSettings;
/**
 * è®¾ç½®ç±»ä¼¼collectionView效果的固定宽带自动间距浮动子view
 * viewsArray       : éœ€è¦æµ®åŠ¨å¸ƒå±€çš„æ‰€æœ‰è§†å›¾
 * perRowItemsCount : æ¯è¡Œæ˜¾ç¤ºçš„视图个数
 * verticalMargin   : è§†å›¾ä¹‹é—´çš„垂直间距
 * vInset           : ä¸Šä¸‹ç¼©è¿›å€¼
 * hInset           : å·¦å³ç¼©è¿›å€¼
 */
- (void)setupAutoMarginFlowItems:(NSArray *)viewsArray withPerRowItemsCount:(NSInteger)perRowItemsCount itemWidth:(CGFloat)itemWidth verticalMargin:(CGFloat)verticalMargin verticalEdgeInset:(CGFloat)vInset horizontalEdgeInset:(CGFloat)hInset;
/** æ¸…除固定宽带自动间距浮动子view设置 */
- (void)clearAutoMarginFlowItemsSettings;
@end
#pragma mark - UIView è®¾ç½®çº¦æŸã€æ›´æ–°çº¦æŸã€æ¸…空约束、从父view移除并清空约束、开启cell的frame缓存等相关方法
@interface UIView (SDAutoLayout)
/** å¼€å§‹è‡ªåŠ¨å¸ƒå±€  */
- (SDAutoLayoutModel *)sd_layout;
/** æ¸…空之前的自动布局设置,重新开始自动布局(重新生成布局约束并使其在父view的布局序列数组中位置保持不变)  */
- (SDAutoLayoutModel *)sd_resetLayout;
/** æ¸…空之前的自动布局设置,重新开始自动布局(重新生成布局约束并添加到父view布局序列数组中的最后一个位置)  */
- (SDAutoLayoutModel *)sd_resetNewLayout;
/** æ˜¯å¦å…³é—­è‡ªåŠ¨å¸ƒå±€  */
@property (nonatomic, getter = sd_isClosingAutoLayout) BOOL sd_closeAutoLayout;
/** ä»Žçˆ¶view移除并清空约束  */
- (void)removeFromSuperviewAndClearAutoLayoutSettings;
/** æ¸…空之前的自动布局设置  */
- (void)sd_clearAutoLayoutSettings;
/** å°†è‡ªèº«frame清零(一般在cell内部控件重用前调用)  */
- (void)sd_clearViewFrameCache;
/** å°†è‡ªå·±çš„需要自动布局的subviews的frame(或者frame缓存)清零  */
- (void)sd_clearSubviewsAutoLayoutFrameCaches;
/** è®¾ç½®å›ºå®šå®½åº¦ä¿è¯å®½åº¦ä¸åœ¨è‡ªåŠ¨å¸ƒå±€è¿‡ç¨‹å†åšä¸­è°ƒæ•´  */
@property (nonatomic, strong) NSNumber *fixedWidth;
/** è®¾ç½®å›ºå®šé«˜åº¦ä¿è¯é«˜åº¦ä¸åœ¨è‡ªåŠ¨å¸ƒå±€è¿‡ç¨‹ä¸­å†åšè°ƒæ•´  */
@property (nonatomic, strong) NSNumber *fixedHeight;
/** å¯ç”¨cell frame缓存(可以提高cell滚动的流畅度, ç›®å‰ä¸ºcell专用方法,后期会扩展到其他view) */
- (void)useCellFrameCacheWithIndexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableview;
/** æ‰€å±žtableview(目前为cell专用属性,后期会扩展到其他view) */
@property (nonatomic) UITableView *sd_tableView;
/** cell的indexPath(目前为cell专用属性,后期会扩展到cell的其他子view) */
@property (nonatomic) NSIndexPath *sd_indexPath;
- (NSMutableArray *)autoLayoutModelsArray;
- (void)addAutoLayoutModel:(SDAutoLayoutModel *)model;
@property (nonatomic) SDAutoLayoutModel *ownLayoutModel;
@property (nonatomic, strong) NSNumber *sd_maxWidth;
@property (nonatomic, strong) NSNumber *autoHeightRatioValue;
@property (nonatomic, strong) NSNumber *autoWidthRatioValue;
@end
#pragma mark - UIScrollView å†…容竖向自适应、内容横向自适应方法
@interface UIScrollView (SDAutoContentSize)
/** è®¾ç½®scrollview内容竖向自适应 */
- (void)setupAutoContentSizeWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin;
/** è®¾ç½®scrollview内容横向自适应 */
- (void)setupAutoContentSizeWithRightView:(UIView *)rightView rightMargin:(CGFloat)rightMargin;
@end
#pragma mark - UILabel å¼€å¯å¯Œæ–‡æœ¬å¸ƒå±€ã€è®¾ç½®å•行文本label宽度自适应、 è®¾ç½®label最多可以显示的行数
@interface UILabel (SDLabelAutoResize)
/** æ˜¯å¦æ˜¯attributedString */
@property (nonatomic) BOOL isAttributedContent;
/** è®¾ç½®å•行文本label宽度自适应 */
- (void)setSingleLineAutoResizeWithMaxWidth:(CGFloat)maxWidth;
/** è®¾ç½®label最多可以显示多少行,如果传0则显示所有行文字 */
- (void)setMaxNumberOfLinesToShow:(NSInteger)lineCount;
@end
#pragma mark - UIButton è®¾ç½®button根据单行文字自适应
@interface UIButton (SDExtention)
/*
 * è®¾ç½®button根据单行文字自适应
 * hPadding:左右边距
 */
- (void)setupAutoSizeWithHorizontalPadding:(CGFloat)hPadding buttonHeight:(CGFloat)buttonHeight;
@end
#pragma mark - å…¶ä»–方法(如果有需要可以自己利用以下接口拓展更多功能)
@interface SDAutoLayoutModelItem : NSObject
@property (nonatomic, strong) NSNumber *value;
@property (nonatomic, weak) UIView *refView;
@property (nonatomic, assign) CGFloat offset;
@property (nonatomic, strong) NSArray *refViewsArray;
@end
@interface UIView (SDChangeFrame)
@property (nonatomic) BOOL shouldReadjustFrameBeforeStoreCache;
@property (nonatomic) CGFloat left_sd;
@property (nonatomic) CGFloat top_sd;
@property (nonatomic) CGFloat right_sd;
@property (nonatomic) CGFloat bottom_sd;
@property (nonatomic) CGFloat centerX_sd;
@property (nonatomic) CGFloat centerY_sd;
@property (nonatomic) CGFloat width_sd;
@property (nonatomic) CGFloat height_sd;
@property (nonatomic) CGPoint origin_sd;
@property (nonatomic) CGSize size_sd;
// å…¼å®¹æ—§ç‰ˆæœ¬
@property (nonatomic) CGFloat left;
@property (nonatomic) CGFloat top;
@property (nonatomic) CGFloat right;
@property (nonatomic) CGFloat bottom;
@property (nonatomic) CGFloat centerX;
@property (nonatomic) CGFloat centerY;
@property (nonatomic) CGFloat width;
@property (nonatomic) CGFloat height;
@property (nonatomic) CGPoint origin;
@property (nonatomic) CGSize size;
@end
@interface SDUIViewCategoryManager : NSObject
@property (nonatomic, strong) NSArray *rightViewsArray;
@property (nonatomic, assign) CGFloat rightViewRightMargin;
@property (nonatomic, weak) UITableView *sd_tableView;
@property (nonatomic, strong) NSIndexPath *sd_indexPath;
@property (nonatomic, assign) BOOL hasSetFrameWithCache;
@property (nonatomic) BOOL shouldReadjustFrameBeforeStoreCache;
@property (nonatomic, assign, getter = sd_isClosingAutoLayout) BOOL sd_closeAutoLayout;
/** è®¾ç½®ç±»ä¼¼collectionView效果的固定间距自动宽度浮动子view */
@property (nonatomic, strong) NSArray *flowItems;
@property (nonatomic, assign) CGFloat verticalMargin;
@property (nonatomic, assign) CGFloat horizontalMargin;
@property (nonatomic, assign) NSInteger perRowItemsCount;
@property (nonatomic, assign) CGFloat lastWidth;
/** è®¾ç½®ç±»ä¼¼collectionView效果的固定宽带自动间距浮动子view */
@property (nonatomic, assign) CGFloat flowItemWidth;
@property (nonatomic, assign) BOOL shouldShowAsAutoMarginViews;
@property (nonatomic) CGFloat horizontalEdgeInset;
@property (nonatomic) CGFloat verticalEdgeInset;
@end
Pods/SDAutoLayout/SDAutoLayoutDemo/SDAutoLayout/UIView+SDAutoLayout.m
New file
@@ -0,0 +1,1825 @@
//
//  UIView+SDAutoLayout.m
//
//  Created by gsd on 15/10/6.
//  Copyright (c) 2015å¹´ gsd. All rights reserved.
//
/*
 *********************************************************************************
 *                                                                                *
 * åœ¨æ‚¨ä½¿ç”¨æ­¤è‡ªåŠ¨å¸ƒå±€åº“çš„è¿‡ç¨‹ä¸­å¦‚æžœå‡ºçŽ°bug请及时以以下任意一种方式联系我们,我们会及时修复bugå¹¶  *
 * å¸®æ‚¨è§£å†³é—®é¢˜ã€‚                                                                    *
 * QQ    : 2689718696(gsdios)                                                      *
 * Email : gsdios@126.com                                                          *
 * GitHub: https://github.com/gsdios                                               *
 * æ–°æµªå¾®åš:GSD_iOS                                                                 *
 *                                                                                *
 *********************************************************************************
 */
#import "UIView+SDAutoLayout.h"
#import "UITableView+SDAutoTableViewCellHeight.h"
#import <objc/runtime.h>
Class cellContVClass()
{
    // ä¸ºäº†åº”付SB审核的SB条款 The use of non-public APIs is not permitted on the App Store because it can lead to a poor user experience should these APIs change.
    static UITableViewCell *tempCell;
    if (!tempCell) {
        tempCell = [UITableViewCell new];
    }
    return [tempCell.contentView class];
}
@interface SDAutoLayoutModel ()
@property (nonatomic, strong) SDAutoLayoutModelItem *width;
@property (nonatomic, strong) SDAutoLayoutModelItem *height;
@property (nonatomic, strong) SDAutoLayoutModelItem *left;
@property (nonatomic, strong) SDAutoLayoutModelItem *top;
@property (nonatomic, strong) SDAutoLayoutModelItem *right;
@property (nonatomic, strong) SDAutoLayoutModelItem *bottom;
@property (nonatomic, strong) NSNumber *centerX;
@property (nonatomic, strong) NSNumber *centerY;
@property (nonatomic, strong) NSNumber *maxWidth;
@property (nonatomic, strong) NSNumber *maxHeight;
@property (nonatomic, strong) NSNumber *minWidth;
@property (nonatomic, strong) NSNumber *minHeight;
@property (nonatomic, strong) SDAutoLayoutModelItem *ratio_width;
@property (nonatomic, strong) SDAutoLayoutModelItem *ratio_height;
@property (nonatomic, strong) SDAutoLayoutModelItem *ratio_left;
@property (nonatomic, strong) SDAutoLayoutModelItem *ratio_top;
@property (nonatomic, strong) SDAutoLayoutModelItem *ratio_right;
@property (nonatomic, strong) SDAutoLayoutModelItem *ratio_bottom;
@property (nonatomic, strong) SDAutoLayoutModelItem *equalLeft;
@property (nonatomic, strong) SDAutoLayoutModelItem *equalRight;
@property (nonatomic, strong) SDAutoLayoutModelItem *equalTop;
@property (nonatomic, strong) SDAutoLayoutModelItem *equalBottom;
@property (nonatomic, strong) SDAutoLayoutModelItem *equalCenterX;
@property (nonatomic, strong) SDAutoLayoutModelItem *equalCenterY;
@property (nonatomic, strong) SDAutoLayoutModelItem *widthEqualHeight;
@property (nonatomic, strong) SDAutoLayoutModelItem *heightEqualWidth;
@property (nonatomic, strong) SDAutoLayoutModelItem *lastModelItem;
@end
@implementation SDAutoLayoutModel
@synthesize leftSpaceToView = _leftSpaceToView;
@synthesize rightSpaceToView = _rightSpaceToView;
@synthesize topSpaceToView = _topSpaceToView;
@synthesize bottomSpaceToView = _bottomSpaceToView;
@synthesize widthIs = _widthIs;
@synthesize heightIs = _heightIs;
@synthesize widthRatioToView = _widthRatioToView;
@synthesize heightRatioToView = _heightRatioToView;
@synthesize leftEqualToView = _leftEqualToView;
@synthesize rightEqualToView = _rightEqualToView;
@synthesize topEqualToView = _topEqualToView;
@synthesize bottomEqualToView = _bottomEqualToView;
@synthesize centerXEqualToView = _centerXEqualToView;
@synthesize centerYEqualToView = _centerYEqualToView;
@synthesize xIs = _xIs;
@synthesize yIs = _yIs;
@synthesize centerXIs = _centerXIs;
@synthesize centerYIs = _centerYIs;
@synthesize autoHeightRatio = _autoHeightRatio;
@synthesize autoWidthRatio = _autoWidthRatio;
@synthesize spaceToSuperView = _spaceToSuperView;
@synthesize maxWidthIs = _maxWidthIs;
@synthesize maxHeightIs = _maxHeightIs;
@synthesize minWidthIs = _minWidthIs;
@synthesize minHeightIs = _minHeightIs;
@synthesize widthEqualToHeight = _widthEqualToHeight;
@synthesize heightEqualToWidth = _heightEqualToWidth;
@synthesize offset = _offset;
- (MarginToView)leftSpaceToView
{
    if (!_leftSpaceToView) {
        _leftSpaceToView = [self marginToViewblockWithKey:@"left"];
    }
    return _leftSpaceToView;
}
- (MarginToView)rightSpaceToView
{
    if (!_rightSpaceToView) {
        _rightSpaceToView = [self marginToViewblockWithKey:@"right"];
    }
    return _rightSpaceToView;
}
- (MarginToView)topSpaceToView
{
    if (!_topSpaceToView) {
        _topSpaceToView = [self marginToViewblockWithKey:@"top"];
    }
    return _topSpaceToView;
}
- (MarginToView)bottomSpaceToView
{
    if (!_bottomSpaceToView) {
        _bottomSpaceToView = [self marginToViewblockWithKey:@"bottom"];
    }
    return _bottomSpaceToView;
}
- (MarginToView)marginToViewblockWithKey:(NSString *)key
{
    __weak typeof(self) weakSelf = self;
    return ^(id viewOrViewsArray, CGFloat value) {
        SDAutoLayoutModelItem *item = [SDAutoLayoutModelItem new];
        item.value = @(value);
        if ([viewOrViewsArray isKindOfClass:[UIView class]]) {
            item.refView = viewOrViewsArray;
        } else if ([viewOrViewsArray isKindOfClass:[NSArray class]]) {
            item.refViewsArray = [viewOrViewsArray copy];
        }
        [weakSelf setValue:item forKey:key];
        return weakSelf;
    };
}
- (WidthHeight)widthIs
{
    if (!_widthIs) {
        __weak typeof(self) weakSelf = self;
        _widthIs = ^(CGFloat value) {
            weakSelf.needsAutoResizeView.fixedWidth = @(value);
            SDAutoLayoutModelItem *widthItem = [SDAutoLayoutModelItem new];
            widthItem.value = @(value);
            weakSelf.width = widthItem;
            return weakSelf;
        };
    }
    return _widthIs;
}
- (WidthHeight)heightIs
{
    if (!_heightIs) {
        __weak typeof(self) weakSelf = self;
        _heightIs = ^(CGFloat value) {
            weakSelf.needsAutoResizeView.fixedHeight = @(value);
            SDAutoLayoutModelItem *heightItem = [SDAutoLayoutModelItem new];
            heightItem.value = @(value);
            weakSelf.height = heightItem;
            return weakSelf;
        };
    }
    return _heightIs;
}
- (WidthHeightEqualToView)widthRatioToView
{
    if (!_widthRatioToView) {
        __weak typeof(self) weakSelf = self;
        _widthRatioToView = ^(UIView *view, CGFloat value) {
            weakSelf.ratio_width = [SDAutoLayoutModelItem new];
            weakSelf.ratio_width.value = @(value);
            weakSelf.ratio_width.refView = view;
            return weakSelf;
        };
    }
    return _widthRatioToView;
}
- (WidthHeightEqualToView)heightRatioToView
{
    if (!_heightRatioToView) {
        __weak typeof(self) weakSelf = self;
        _heightRatioToView = ^(UIView *view, CGFloat value) {
            weakSelf.ratio_height = [SDAutoLayoutModelItem new];
            weakSelf.ratio_height.refView = view;
            weakSelf.ratio_height.value = @(value);
            return weakSelf;
        };
    }
    return _heightRatioToView;
}
- (WidthHeight)maxWidthIs
{
    if (!_maxWidthIs) {
        _maxWidthIs = [self limitingWidthHeightWithKey:@"maxWidth"];
    }
    return _maxWidthIs;
}
- (WidthHeight)maxHeightIs
{
    if (!_maxHeightIs) {
        _maxHeightIs = [self limitingWidthHeightWithKey:@"maxHeight"];
    }
    return _maxHeightIs;
}
- (WidthHeight)minWidthIs
{
    if (!_minWidthIs) {
        _minWidthIs = [self limitingWidthHeightWithKey:@"minWidth"];
    }
    return _minWidthIs;
}
- (WidthHeight)minHeightIs
{
    if (!_minHeightIs) {
        _minHeightIs = [self limitingWidthHeightWithKey:@"minHeight"];
    }
    return _minHeightIs;
}
- (WidthHeight)limitingWidthHeightWithKey:(NSString *)key
{
    __weak typeof(self) weakSelf = self;
    return ^(CGFloat value) {
        [weakSelf setValue:@(value) forKey:key];
        return weakSelf;
    };
}
- (MarginEqualToView)marginEqualToViewBlockWithKey:(NSString *)key
{
    __weak typeof(self) weakSelf = self;
    return ^(UIView *view) {
        SDAutoLayoutModelItem *item = [SDAutoLayoutModelItem new];
        item.refView = view;
        [weakSelf setValue:item forKey:key];
        weakSelf.lastModelItem = item;
        if ([view isKindOfClass:cellContVClass()] && ([key isEqualToString:@"equalCenterY"] || [key isEqualToString:@"equalBottom"])) {
            view.shouldReadjustFrameBeforeStoreCache = YES;
        }
        return weakSelf;
    };
}
- (MarginEqualToView)leftEqualToView
{
    if (!_leftEqualToView) {
        _leftEqualToView = [self marginEqualToViewBlockWithKey:@"equalLeft"];
    }
    return _leftEqualToView;
}
- (MarginEqualToView)rightEqualToView
{
    if (!_rightEqualToView) {
        _rightEqualToView = [self marginEqualToViewBlockWithKey:@"equalRight"];
    }
    return _rightEqualToView;
}
- (MarginEqualToView)topEqualToView
{
    if (!_topEqualToView) {
        _topEqualToView = [self marginEqualToViewBlockWithKey:@"equalTop"];
    }
    return _topEqualToView;
}
- (MarginEqualToView)bottomEqualToView
{
    if (!_bottomEqualToView) {
        _bottomEqualToView = [self marginEqualToViewBlockWithKey:@"equalBottom"];
    }
    return _bottomEqualToView;
}
- (MarginEqualToView)centerXEqualToView
{
    if (!_centerXEqualToView) {
        _centerXEqualToView = [self marginEqualToViewBlockWithKey:@"equalCenterX"];
    }
    return _centerXEqualToView;
}
- (MarginEqualToView)centerYEqualToView
{
    if (!_centerYEqualToView) {
        _centerYEqualToView = [self marginEqualToViewBlockWithKey:@"equalCenterY"];
    }
    return _centerYEqualToView;
}
- (Margin)marginBlockWithKey:(NSString *)key
{
    __weak typeof(self) weakSelf = self;
    return ^(CGFloat value) {
        if ([key isEqualToString:@"x"]) {
            weakSelf.needsAutoResizeView.left_sd = value;
        } else if ([key isEqualToString:@"y"]) {
            weakSelf.needsAutoResizeView.top_sd = value;
        } else if ([key isEqualToString:@"centerX"]) {
            weakSelf.centerX = @(value);
        } else if ([key isEqualToString:@"centerY"]) {
            weakSelf.centerY = @(value);
        }
        return weakSelf;
    };
}
- (Margin)xIs
{
    if (!_xIs) {
        _xIs = [self marginBlockWithKey:@"x"];
    }
    return _xIs;
}
- (Margin)yIs
{
    if (!_yIs) {
        _yIs = [self marginBlockWithKey:@"y"];
    }
    return _yIs;
}
- (Margin)centerXIs
{
    if (!_centerXIs) {
        _centerXIs = [self marginBlockWithKey:@"centerX"];
    }
    return _centerXIs;
}
- (Margin)centerYIs
{
    if (!_centerYIs) {
        _centerYIs = [self marginBlockWithKey:@"centerY"];
    }
    return _centerYIs;
}
- (AutoHeightWidth)autoHeightRatio
{
    __weak typeof(self) weakSelf = self;
    if (!_autoHeightRatio) {
        _autoHeightRatio = ^(CGFloat ratioaValue) {
            weakSelf.needsAutoResizeView.autoHeightRatioValue = @(ratioaValue);
            return weakSelf;
        };
    }
    return _autoHeightRatio;
}
- (AutoHeightWidth)autoWidthRatio
{
    __weak typeof(self) weakSelf = self;
    if (!_autoWidthRatio) {
        _autoWidthRatio = ^(CGFloat ratioaValue) {
            weakSelf.needsAutoResizeView.autoWidthRatioValue = @(ratioaValue);
            return weakSelf;
        };
    }
    return _autoWidthRatio;
}
- (SpaceToSuperView)spaceToSuperView
{
    __weak typeof(self) weakSelf = self;
    if (!_spaceToSuperView) {
        _spaceToSuperView = ^(UIEdgeInsets insets) {
            UIView *superView = weakSelf.needsAutoResizeView.superview;
            if (superView) {
                weakSelf.needsAutoResizeView.sd_layout
                .leftSpaceToView(superView, insets.left)
                .topSpaceToView(superView, insets.top)
                .rightSpaceToView(superView, insets.right)
                .bottomSpaceToView(superView, insets.bottom);
            }
        };
    }
    return _spaceToSuperView;
}
- (SameWidthHeight)widthEqualToHeight
{
    __weak typeof(self) weakSelf = self;
    if (!_widthEqualToHeight) {
        _widthEqualToHeight = ^() {
            weakSelf.widthEqualHeight = [SDAutoLayoutModelItem new];
            weakSelf.lastModelItem = weakSelf.widthEqualHeight;
            // ä¸»åŠ¨è§¦å‘ä¸€æ¬¡èµ‹å€¼æ“ä½œ
            weakSelf.needsAutoResizeView.height_sd = weakSelf.needsAutoResizeView.height_sd;
            return weakSelf;
        };
    }
    return _widthEqualToHeight;
}
- (SameWidthHeight)heightEqualToWidth
{
    __weak typeof(self) weakSelf = self;
    if (!_heightEqualToWidth) {
        _heightEqualToWidth = ^() {
            weakSelf.heightEqualWidth = [SDAutoLayoutModelItem new];
            weakSelf.lastModelItem = weakSelf.heightEqualWidth;
            // ä¸»åŠ¨è§¦å‘ä¸€æ¬¡èµ‹å€¼æ“ä½œ
            weakSelf.needsAutoResizeView.width_sd = weakSelf.needsAutoResizeView.width_sd;
            return weakSelf;
        };
    }
    return _heightEqualToWidth;
}
- (SDAutoLayoutModel *(^)(CGFloat))offset
{
    __weak typeof(self) weakSelf = self;
    if (!_offset) {
        _offset = ^(CGFloat offset) {
            weakSelf.lastModelItem.offset = offset;
            return weakSelf;
        };
    }
    return _offset;
}
@end
@implementation UIView (SDAutoHeightWidth)
- (SDUIViewCategoryManager *)sd_categoryManager
{
    SDUIViewCategoryManager *manager = objc_getAssociatedObject(self, _cmd);
    if (!manager) {
        objc_setAssociatedObject(self, _cmd, [SDUIViewCategoryManager new], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return objc_getAssociatedObject(self, _cmd);
}
- (void)setupAutoHeightWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin
{
    if (!bottomView) return;
    [self setupAutoHeightWithBottomViewsArray:@[bottomView] bottomMargin:bottomMargin];
}
- (void)setupAutoWidthWithRightView:(UIView *)rightView rightMargin:(CGFloat)rightMargin
{
    if (!rightView) return;
    self.sd_rightViewsArray = @[rightView];
    self.sd_rightViewRightMargin = rightMargin;
}
- (void)setupAutoHeightWithBottomViewsArray:(NSArray *)bottomViewsArray bottomMargin:(CGFloat)bottomMargin
{
    if (!bottomViewsArray) return;
    // æ¸…空之前的view
    [self.sd_bottomViewsArray removeAllObjects];
    [self.sd_bottomViewsArray addObjectsFromArray:bottomViewsArray];
    self.sd_bottomViewBottomMargin = bottomMargin;
}
- (void)clearAutoHeigtSettings
{
    [self.sd_bottomViewsArray removeAllObjects];
}
- (void)clearAutoWidthSettings
{
    self.sd_rightViewsArray = nil;
}
- (void)updateLayout
{
    [self.superview layoutSubviews];
}
- (void)updateLayoutWithCellContentView:(UIView *)cellContentView
{
    if (cellContentView.sd_indexPath) {
        [cellContentView sd_clearSubviewsAutoLayoutFrameCaches];
    }
    [self updateLayout];
}
- (CGFloat)autoHeight
{
    return [objc_getAssociatedObject(self, _cmd) floatValue];
}
- (void)setAutoHeight:(CGFloat)autoHeight
{
    objc_setAssociatedObject(self, @selector(autoHeight), @(autoHeight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSMutableArray *)sd_bottomViewsArray
{
    NSMutableArray *array = objc_getAssociatedObject(self, _cmd);
    if (!array) {
        objc_setAssociatedObject(self, _cmd, [NSMutableArray new], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return objc_getAssociatedObject(self, _cmd);
}
- (NSArray *)sd_rightViewsArray
{
    return [[self sd_categoryManager] rightViewsArray];
}
- (void)setSd_rightViewsArray:(NSArray *)sd_rightViewsArray
{
    [[self sd_categoryManager] setRightViewsArray:sd_rightViewsArray];
}
- (CGFloat)sd_bottomViewBottomMargin
{
    return [objc_getAssociatedObject(self, _cmd) floatValue];
}
- (void)setSd_bottomViewBottomMargin:(CGFloat)sd_bottomViewBottomMargin
{
    objc_setAssociatedObject(self, @selector(sd_bottomViewBottomMargin), @(sd_bottomViewBottomMargin), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)setSd_rightViewRightMargin:(CGFloat)sd_rightViewRightMargin
{
    [[self sd_categoryManager] setRightViewRightMargin:sd_rightViewRightMargin];
}
- (CGFloat)sd_rightViewRightMargin
{
    return [[self sd_categoryManager] rightViewRightMargin];
}
@end
@implementation UIView (SDLayoutExtention)
- (void (^)(CGRect))didFinishAutoLayoutBlock
{
    return objc_getAssociatedObject(self, _cmd);
}
- (void)setDidFinishAutoLayoutBlock:(void (^)(CGRect))didFinishAutoLayoutBlock
{
    objc_setAssociatedObject(self, @selector(didFinishAutoLayoutBlock), didFinishAutoLayoutBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSNumber *)sd_cornerRadius
{
    return objc_getAssociatedObject(self, _cmd);
}
- (void)setSd_cornerRadius:(NSNumber *)sd_cornerRadius
{
    objc_setAssociatedObject(self, @selector(sd_cornerRadius), sd_cornerRadius, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSNumber *)sd_cornerRadiusFromWidthRatio
{
    return objc_getAssociatedObject(self, _cmd);
}
- (void)setSd_cornerRadiusFromWidthRatio:(NSNumber *)sd_cornerRadiusFromWidthRatio
{
    objc_setAssociatedObject(self, @selector(sd_cornerRadiusFromWidthRatio), sd_cornerRadiusFromWidthRatio, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSNumber *)sd_cornerRadiusFromHeightRatio
{
    return objc_getAssociatedObject(self, _cmd);
}
- (void)setSd_cornerRadiusFromHeightRatio:(NSNumber *)sd_cornerRadiusFromHeightRatio
{
    objc_setAssociatedObject(self, @selector(sd_cornerRadiusFromHeightRatio), sd_cornerRadiusFromHeightRatio, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSArray *)sd_equalWidthSubviews
{
    return objc_getAssociatedObject(self, _cmd);
}
- (void)setSd_equalWidthSubviews:(NSArray *)sd_equalWidthSubviews
{
    objc_setAssociatedObject(self, @selector(sd_equalWidthSubviews), sd_equalWidthSubviews, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)sd_addSubviews:(NSArray *)subviews
{
    [subviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) {
        if ([view isKindOfClass:[UIView class]]) {
            [self addSubview:view];
        }
    }];
}
@end
@implementation UIView (SDAutoFlowItems)
- (void)setupAutoWidthFlowItems:(NSArray *)viewsArray withPerRowItemsCount:(NSInteger)perRowItemsCount verticalMargin:(CGFloat)verticalMargin horizontalMargin:(CGFloat)horizontalMagin verticalEdgeInset:(CGFloat)vInset horizontalEdgeInset:(CGFloat)hInset
{
    self.sd_categoryManager.flowItems = viewsArray;
    self.sd_categoryManager.perRowItemsCount = perRowItemsCount;
    self.sd_categoryManager.verticalMargin = verticalMargin;
    self.sd_categoryManager.horizontalMargin = horizontalMagin;
    self.verticalEdgeInset = vInset;
    self.horizontalEdgeInset = hInset;
    self.sd_categoryManager.lastWidth = 0;
    if (viewsArray.count) {
        [self setupAutoHeightWithBottomView:viewsArray.lastObject bottomMargin:vInset];
    } else {
        [self clearAutoHeigtSettings];
    }
}
- (void)clearAutoWidthFlowItemsSettings
{
    [self setupAutoWidthFlowItems:nil withPerRowItemsCount:0 verticalMargin:0 horizontalMargin:0 verticalEdgeInset:0 horizontalEdgeInset:0];
}
- (void)setupAutoMarginFlowItems:(NSArray *)viewsArray withPerRowItemsCount:(NSInteger)perRowItemsCount itemWidth:(CGFloat)itemWidth verticalMargin:(CGFloat)verticalMargin verticalEdgeInset:(CGFloat)vInset horizontalEdgeInset:(CGFloat)hInset
{
    self.sd_categoryManager.shouldShowAsAutoMarginViews = YES;
    self.sd_categoryManager.flowItemWidth = itemWidth;
    [self setupAutoWidthFlowItems:viewsArray withPerRowItemsCount:perRowItemsCount verticalMargin:verticalMargin horizontalMargin:0 verticalEdgeInset:vInset horizontalEdgeInset:hInset];
}
- (void)clearAutoMarginFlowItemsSettings
{
    [self setupAutoMarginFlowItems:nil withPerRowItemsCount:0 itemWidth:0 verticalMargin:0 verticalEdgeInset:0 horizontalEdgeInset:0];
}
- (void)setHorizontalEdgeInset:(CGFloat)horizontalEdgeInset
{
    self.sd_categoryManager.horizontalEdgeInset = horizontalEdgeInset;
}
- (CGFloat)horizontalEdgeInset
{
    return self.sd_categoryManager.horizontalEdgeInset;
}
- (void)setVerticalEdgeInset:(CGFloat)verticalEdgeInset
{
    self.sd_categoryManager.verticalEdgeInset = verticalEdgeInset;
}
- (CGFloat)verticalEdgeInset
{
    return self.sd_categoryManager.verticalEdgeInset;
}
@end
@implementation UIScrollView (SDAutoContentSize)
- (void)setupAutoContentSizeWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin
{
    [self setupAutoHeightWithBottomView:bottomView bottomMargin:bottomMargin];
}
- (void)setupAutoContentSizeWithRightView:(UIView *)rightView rightMargin:(CGFloat)rightMargin
{
    if (!rightView) return;
    self.sd_rightViewsArray = @[rightView];
    self.sd_rightViewRightMargin = rightMargin;
}
@end
@implementation UILabel (SDLabelAutoResize)
+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSArray *selStringsArray = @[@"setText:"];
        [selStringsArray enumerateObjectsUsingBlock:^(NSString *selString, NSUInteger idx, BOOL *stop) {
            NSString *mySelString = [@"sd_" stringByAppendingString:selString];
            Method originalMethod = class_getInstanceMethod(self, NSSelectorFromString(selString));
            Method myMethod = class_getInstanceMethod(self, NSSelectorFromString(mySelString));
            method_exchangeImplementations(originalMethod, myMethod);
        }];
    });
}
- (void)sd_setText:(NSString *)text
{
    // å¦‚果程序崩溃在这行代码说明是你的label在执行“setText”方法时出了问题而不是在此自动布局库内部出现了问题,请检查你的“setText”方法
    [self sd_setText:text];
    if (self.sd_maxWidth) {
        [self sizeToFit];
    } else if (self.autoHeightRatioValue) {
        self.size_sd = CGSizeZero;
    }
}
- (BOOL)isAttributedContent
{
    return [objc_getAssociatedObject(self, _cmd) boolValue];
}
- (void)setIsAttributedContent:(BOOL)isAttributedContent
{
    objc_setAssociatedObject(self, @selector(isAttributedContent), @(isAttributedContent), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)setSingleLineAutoResizeWithMaxWidth:(CGFloat)maxWidth
{
    self.sd_maxWidth = @(maxWidth);
}
- (void)setMaxNumberOfLinesToShow:(NSInteger)lineCount
{
    NSAssert(self.ownLayoutModel, @"请在布局完成之后再做此步设置!");
    if (lineCount > 0) {
        self.sd_layout.maxHeightIs(self.font.lineHeight * lineCount + 0.1);
    } else {
        self.sd_layout.maxHeightIs(MAXFLOAT);
    }
}
@end
@implementation UIButton (SDExtention)
- (void)setupAutoSizeWithHorizontalPadding:(CGFloat)hPadding buttonHeight:(CGFloat)buttonHeight
{
    self.fixedHeight = @(buttonHeight);
    self.titleLabel.sd_layout
    .leftSpaceToView(self, hPadding)
    .topEqualToView(self)
    .heightIs(buttonHeight);
    [self.titleLabel setSingleLineAutoResizeWithMaxWidth:MAXFLOAT];
    [self setupAutoWidthWithRightView:self.titleLabel rightMargin:hPadding];
}
@end
@implementation SDAutoLayoutModelItem
- (instancetype)init
{
    if (self = [super init]) {
        _offset = 0;
    }
    return self;
}
@end
@implementation UIView (SDAutoLayout)
+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSArray *selStringsArray = @[@"layoutSubviews"];
        [selStringsArray enumerateObjectsUsingBlock:^(NSString *selString, NSUInteger idx, BOOL *stop) {
            NSString *mySelString = [@"sd_" stringByAppendingString:selString];
            Method originalMethod = class_getInstanceMethod(self, NSSelectorFromString(selString));
            Method myMethod = class_getInstanceMethod(self, NSSelectorFromString(mySelString));
            method_exchangeImplementations(originalMethod, myMethod);
        }];
    });
}
#pragma mark - properties
- (NSMutableArray *)autoLayoutModelsArray
{
    if (!objc_getAssociatedObject(self, _cmd)) {
        objc_setAssociatedObject(self, _cmd, [NSMutableArray array], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return objc_getAssociatedObject(self, _cmd);
}
- (NSNumber *)fixedWidth
{
    return objc_getAssociatedObject(self, _cmd);
}
- (void)setFixedWidth:(NSNumber *)fixedWidth
{
    if (fixedWidth) {
        self.width_sd = [fixedWidth floatValue];
    }
    objc_setAssociatedObject(self, @selector(fixedWidth), fixedWidth, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSNumber *)fixedHeight
{
    return objc_getAssociatedObject(self, _cmd);
}
- (void)setFixedHeight:(NSNumber *)fixedHeight
{
    if (fixedHeight) {
        self.height_sd = [fixedHeight floatValue];
    }
    objc_setAssociatedObject(self, @selector(fixedHeight), fixedHeight, OBJC_ASSOCIATION_RETAIN);
}
- (NSNumber *)autoHeightRatioValue
{
    return objc_getAssociatedObject(self, _cmd);
}
- (void)setAutoHeightRatioValue:(NSNumber *)autoHeightRatioValue
{
    objc_setAssociatedObject(self, @selector(autoHeightRatioValue), autoHeightRatioValue, OBJC_ASSOCIATION_RETAIN);
}
- (NSNumber *)autoWidthRatioValue
{
    return objc_getAssociatedObject(self, _cmd);
}
- (void)setAutoWidthRatioValue:(NSNumber *)autoWidthRatioValue
{
    objc_setAssociatedObject(self, @selector(autoWidthRatioValue), autoWidthRatioValue, OBJC_ASSOCIATION_RETAIN);
}
- (NSNumber *)sd_maxWidth
{
    return objc_getAssociatedObject(self, _cmd);
}
- (void)setSd_maxWidth:(NSNumber *)sd_maxWidth
{
    objc_setAssociatedObject(self, @selector(sd_maxWidth), sd_maxWidth, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)useCellFrameCacheWithIndexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableview
{
    self.sd_indexPath = indexPath;
    self.sd_tableView = tableview;
}
- (UITableView *)sd_tableView
{
    return self.sd_categoryManager.sd_tableView;
}
- (void)setSd_tableView:(UITableView *)sd_tableView
{
    if ([self isKindOfClass:[UITableViewCell class]]) {
        [(UITableViewCell *)self contentView].sd_tableView = sd_tableView;
    }
    self.sd_categoryManager.sd_tableView = sd_tableView;
}
- (NSIndexPath *)sd_indexPath
{
    return self.sd_categoryManager.sd_indexPath;
}
- (void)setSd_indexPath:(NSIndexPath *)sd_indexPath
{
    if ([self isKindOfClass:[UITableViewCell class]]) {
        [(UITableViewCell *)self contentView].sd_indexPath = sd_indexPath;
    }
    self.sd_categoryManager.sd_indexPath = sd_indexPath;
}
- (SDAutoLayoutModel *)ownLayoutModel
{
    return objc_getAssociatedObject(self, _cmd);
}
- (void)setOwnLayoutModel:(SDAutoLayoutModel *)ownLayoutModel
{
    objc_setAssociatedObject(self, @selector(ownLayoutModel), ownLayoutModel, OBJC_ASSOCIATION_RETAIN);
}
- (SDAutoLayoutModel *)sd_layout
{
#ifdef SDDebugWithAssert
    /*
     å¡åœ¨è¿™é‡Œè¯´æ˜Žä½ çš„要自动布局的view在没有添加到父view的情况下就开始设置布局,你需要这样:
     1.  UIView *view = [UIView new];
     2.  [superView addSubview:view];
     3.  view.sd_layout
     .leftEqualToView()...
     */
    NSAssert(self.superview, @">>>>>>>>>在加入父view之后才可以做自动布局设置");
#endif
    SDAutoLayoutModel *model = [self ownLayoutModel];
    if (!model) {
        model = [SDAutoLayoutModel new];
        model.needsAutoResizeView = self;
        [self setOwnLayoutModel:model];
        [self.superview.autoLayoutModelsArray addObject:model];
    }
    return model;
}
- (SDAutoLayoutModel *)sd_resetLayout
{
    /*
     * æ–¹æ¡ˆå¾…定
     [self sd_clearAutoLayoutSettings];
     return [self sd_layout];
     */
    SDAutoLayoutModel *model = [self ownLayoutModel];
    SDAutoLayoutModel *newModel = [SDAutoLayoutModel new];
    newModel.needsAutoResizeView = self;
    [self sd_clearViewFrameCache];
    NSInteger index = 0;
    if (model) {
        index = [self.superview.autoLayoutModelsArray indexOfObject:model];
        [self.superview.autoLayoutModelsArray replaceObjectAtIndex:index withObject:newModel];
    } else {
        [self.superview.autoLayoutModelsArray addObject:newModel];
    }
    [self setOwnLayoutModel:newModel];
    [self sd_clearExtraAutoLayoutItems];
    return newModel;
}
- (SDAutoLayoutModel *)sd_resetNewLayout
{
    [self sd_clearAutoLayoutSettings];
    [self sd_clearExtraAutoLayoutItems];
    return [self sd_layout];
}
- (BOOL)sd_isClosingAutoLayout
{
    return self.sd_categoryManager.sd_isClosingAutoLayout;
}
- (void)setSd_closeAutoLayout:(BOOL)sd_closeAutoLayout
{
    self.sd_categoryManager.sd_closeAutoLayout = sd_closeAutoLayout;
}
- (void)removeFromSuperviewAndClearAutoLayoutSettings
{
    [self sd_clearAutoLayoutSettings];
    [self removeFromSuperview];
}
- (void)sd_clearAutoLayoutSettings
{
    SDAutoLayoutModel *model = [self ownLayoutModel];
    if (model) {
        [self.superview.autoLayoutModelsArray removeObject:model];
        [self setOwnLayoutModel:nil];
    }
    [self sd_clearExtraAutoLayoutItems];
}
- (void)sd_clearExtraAutoLayoutItems
{
    if (self.autoHeightRatioValue) {
        self.autoHeightRatioValue = nil;
    }
    self.fixedHeight = nil;
    self.fixedWidth = nil;
}
- (void)sd_clearViewFrameCache
{
    self.frame = CGRectZero;
}
- (void)sd_clearSubviewsAutoLayoutFrameCaches
{
    if (self.sd_tableView && self.sd_indexPath) {
        [self.sd_tableView.cellAutoHeightManager clearHeightCacheOfIndexPaths:@[self.sd_indexPath]];
        return;
    }
    if (self.autoLayoutModelsArray.count == 0) return;
    [self.autoLayoutModelsArray enumerateObjectsUsingBlock:^(SDAutoLayoutModel *model, NSUInteger idx, BOOL *stop) {
        model.needsAutoResizeView.frame = CGRectZero;
    }];
}
- (void)sd_layoutSubviews
{
    // å¦‚果程序崩溃在这行代码说明是你的view在执行“layoutSubvies”方法时出了问题而不是在此自动布局库内部出现了问题,请检查你的“layoutSubvies”方法
    [self sd_layoutSubviews];
    [self sd_layoutSubviewsHandle];
}
- (void)sd_layoutSubviewsHandle{
    if (self.sd_equalWidthSubviews.count) {
        __block CGFloat totalMargin = 0;
        [self.sd_equalWidthSubviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) {
            SDAutoLayoutModel *model = view.sd_layout;
            CGFloat left = model.left ? [model.left.value floatValue] : model.needsAutoResizeView.left_sd;
            totalMargin += (left + [model.right.value floatValue]);
        }];
        CGFloat averageWidth = (self.width_sd - totalMargin) / self.sd_equalWidthSubviews.count;
        [self.sd_equalWidthSubviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) {
            view.width_sd = averageWidth;
            view.fixedWidth = @(averageWidth);
        }];
    }
    if (self.sd_categoryManager.flowItems.count && (self.sd_categoryManager.lastWidth != self.width_sd)) {
        self.sd_categoryManager.lastWidth = self.width_sd;
        NSInteger perRowItemsCount = self.sd_categoryManager.perRowItemsCount;
        CGFloat horizontalMargin = 0;
        CGFloat w = 0;
        if (self.sd_categoryManager.shouldShowAsAutoMarginViews) {
            w = self.sd_categoryManager.flowItemWidth;
            long itemsCount = self.sd_categoryManager.perRowItemsCount;
            if (itemsCount > 1) {
                horizontalMargin = (self.width_sd - (self.horizontalEdgeInset * 2) - itemsCount * w) / (itemsCount - 1);
            }
        } else {
            horizontalMargin = self.sd_categoryManager.horizontalMargin;
            w = (self.width_sd - (self.horizontalEdgeInset * 2) - (perRowItemsCount - 1) * horizontalMargin) / perRowItemsCount;
        }
        CGFloat verticalMargin = self.sd_categoryManager.verticalMargin;
        __block UIView *referencedView = self;
        [self.sd_categoryManager.flowItems enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) {
            if (idx < perRowItemsCount) {
                if (idx == 0) {
                    /* ä¿ç•™
                    BOOL shouldShowAsAutoMarginViews = self.sd_categoryManager.shouldShowAsAutoMarginViews;
                     */
                    view.sd_layout
                    .leftSpaceToView(referencedView, self.horizontalEdgeInset)
                    .topSpaceToView(referencedView, self.verticalEdgeInset)
                    .widthIs(w);
                } else {
                    view.sd_layout
                    .leftSpaceToView(referencedView, horizontalMargin)
                    .topEqualToView(referencedView)
                    .widthIs(w);
                }
                referencedView = view;
            } else {
                referencedView = self.sd_categoryManager.flowItems[idx - perRowItemsCount];
                view.sd_layout
                .leftEqualToView(referencedView)
                .widthIs(w)
                .topSpaceToView(referencedView, verticalMargin);
            }
        }];
    }
    if (self.autoLayoutModelsArray.count) {
        NSMutableArray *caches = nil;
        if ([self isKindOfClass:cellContVClass()] && self.sd_tableView) {
            caches = [self.sd_tableView.cellAutoHeightManager subviewFrameCachesWithIndexPath:self.sd_indexPath];
        }
        [self.autoLayoutModelsArray enumerateObjectsUsingBlock:^(SDAutoLayoutModel *model, NSUInteger idx, BOOL *stop) {
            if (idx < caches.count) {
                CGRect originalFrame = model.needsAutoResizeView.frame;
                CGRect newFrame = [[caches objectAtIndex:idx] CGRectValue];
                if (CGRectEqualToRect(originalFrame, newFrame)) {
                    [model.needsAutoResizeView setNeedsLayout];
                } else {
                    model.needsAutoResizeView.frame = newFrame;
                }
                [self setupCornerRadiusWithView:model.needsAutoResizeView model:model];
                model.needsAutoResizeView.sd_categoryManager.hasSetFrameWithCache = YES;
            } else {
                if (model.needsAutoResizeView.sd_categoryManager.hasSetFrameWithCache) {
                    model.needsAutoResizeView.sd_categoryManager.hasSetFrameWithCache = NO;
                }
                [self sd_resizeWithModel:model];
            }
        }];
    }
    if (self.tag == kSDModelCellTag && [self isKindOfClass:cellContVClass()]) {
        UITableViewCell *cell = (UITableViewCell *)(self.superview);
        while (cell && ![cell isKindOfClass:[UITableViewCell class]]) {
            cell = (UITableViewCell *)cell.superview;
        }
        if ([cell isKindOfClass:[UITableViewCell class]]) {
            CGFloat height = 0;
            for (UIView *view in cell.sd_bottomViewsArray) {
                height = MAX(height, view.bottom_sd);
            }
            cell.autoHeight = height + cell.sd_bottomViewBottomMargin;
        }
    } else if (![self isKindOfClass:[UITableViewCell class]] && (self.sd_bottomViewsArray.count || self.sd_rightViewsArray.count)) {
        if (self.sd_categoryManager.hasSetFrameWithCache) {
            self.sd_categoryManager.hasSetFrameWithCache = NO;
            return;
        }
        CGFloat contentHeight = 0;
        CGFloat contentWidth = 0;
        if (self.sd_bottomViewsArray) {
            CGFloat height = 0;
            for (UIView *view in self.sd_bottomViewsArray) {
                height = MAX(height, view.bottom_sd);
            }
            contentHeight = height + self.sd_bottomViewBottomMargin;
        }
        if (self.sd_rightViewsArray) {
            CGFloat width = 0;
            for (UIView *view in self.sd_rightViewsArray) {
                width = MAX(width, view.right_sd);
            }
            contentWidth = width + self.sd_rightViewRightMargin;
        }
        if ([self isKindOfClass:[UIScrollView class]]) {
            UIScrollView *scrollView = (UIScrollView *)self;
            CGSize contentSize = scrollView.contentSize;
            if (contentHeight > 0) {
                contentSize.height = contentHeight;
            }
            if (contentWidth > 0) {
                contentSize.width = contentWidth;
            }
            if (contentSize.width <= 0) {
                contentSize.width = scrollView.width_sd;
            }
            if (!CGSizeEqualToSize(contentSize, scrollView.contentSize)) {
                scrollView.contentSize = contentSize;
            }
        } else {
            // å¦‚果这里出现循环调用情况请把demo发送到gsdios@126.com,谢谢配合。
            if (self.sd_bottomViewsArray.count && (floorf(contentHeight) != floorf(self.height_sd))) {
                self.height_sd = contentHeight;
                self.fixedHeight = @(self.height_sd);
            }
            if (self.sd_rightViewsArray.count && (floorf(contentWidth) != floorf(self.width_sd))) {
                self.width_sd = contentWidth;
                self.fixedWidth = @(self.width_sd);
            }
        }
        SDAutoLayoutModel *model = self.ownLayoutModel;
        if (![self isKindOfClass:[UIScrollView class]] && self.sd_rightViewsArray.count && (model.right || model.equalRight || model.centerX || model.equalCenterX)) {
            self.fixedWidth = @(self.width);
            if (model.right || model.equalRight) {
                [self layoutRightWithView:self model:model];
            } else {
                [self layoutLeftWithView:self model:model];
            }
            self.fixedWidth = nil;
        }
        if (![self isKindOfClass:[UIScrollView class]] && self.sd_bottomViewsArray.count && (model.bottom || model.equalBottom || model.centerY || model.equalCenterY)) {
            self.fixedHeight = @(self.height);
            if (model.bottom || model.equalBottom) {
                [self layoutBottomWithView:self model:model];
            } else {
                [self layoutTopWithView:self model:model];
            }
            self.fixedHeight = nil;
        }
        if (self.didFinishAutoLayoutBlock) {
            self.didFinishAutoLayoutBlock(self.frame);
        }
    }
}
- (void)sd_resizeWithModel:(SDAutoLayoutModel *)model
{
    UIView *view = model.needsAutoResizeView;
    if (!view || view.sd_isClosingAutoLayout) return;
    if (view.sd_maxWidth && (model.rightSpaceToView || model.rightEqualToView)) { // é å³å¸ƒå±€å‰æè®¾ç½®
        [self layoutAutoWidthWidthView:view model:model];
        view.fixedWidth = @(view.width_sd);
    }
    [self layoutWidthWithView:view model:model];
    [self layoutHeightWithView:view model:model];
    [self layoutLeftWithView:view model:model];
    [self layoutRightWithView:view model:model];
    if (view.autoHeightRatioValue && view.width_sd > 0 && (model.bottomEqualToView || model.bottomSpaceToView)) { // åº•部布局前提设置
        [self layoutAutoHeightWidthView:view model:model];
        view.fixedHeight = @(view.height_sd);
    }
    if (view.autoWidthRatioValue) {
        view.fixedWidth = @(view.height_sd * [view.autoWidthRatioValue floatValue]);
    }
    [self layoutTopWithView:view model:model];
    [self layoutBottomWithView:view model:model];
    if (view.sd_maxWidth) {
        [self layoutAutoWidthWidthView:view model:model];
    }
    if (model.maxWidth && [model.maxWidth floatValue] < view.width_sd) {
        view.width_sd = [model.maxWidth floatValue];
    }
    if (model.minWidth && [model.minWidth floatValue] > view.width_sd) {
        view.width_sd = [model.minWidth floatValue];
    }
    if (view.autoHeightRatioValue && view.width_sd > 0) {
        [self layoutAutoHeightWidthView:view model:model];
    }
    if (model.maxHeight && [model.maxHeight floatValue] < view.height_sd) {
        view.height_sd = [model.maxHeight floatValue];
    }
    if (model.minHeight && [model.minHeight floatValue] > view.height_sd) {
        view.height_sd = [model.minHeight floatValue];
    }
    if (model.widthEqualHeight) {
        view.width_sd = view.height_sd;
    }
    if (model.heightEqualWidth) {
        view.height_sd = view.width_sd;
    }
    if (view.didFinishAutoLayoutBlock) {
        view.didFinishAutoLayoutBlock(view.frame);
    }
    if (view.sd_bottomViewsArray.count || view.sd_rightViewsArray.count) {
        [view layoutSubviews];
    }
    [self setupCornerRadiusWithView:view model:model];
}
- (void)layoutAutoHeightWidthView:(UIView *)view model:(SDAutoLayoutModel *)model
{
    if ([view.autoHeightRatioValue floatValue] > 0) {
        view.height_sd = view.width_sd * [view.autoHeightRatioValue floatValue];
    } else {
        if ([view isKindOfClass:[UILabel class]]) {
            UILabel *label = (UILabel *)view;
            label.numberOfLines = 0;
            if (label.text.length) {
                if (!label.isAttributedContent) {
                    CGRect rect = [label.text boundingRectWithSize:CGSizeMake(label.width_sd, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName : label.font} context:nil];
                    label.height_sd = rect.size.height + 0.1;
                } else {
                    [label sizeToFit];
                }
            } else {
                label.height_sd = 0;
            }
        } else {
            view.height_sd = 0;
        }
    }
}
- (void)layoutAutoWidthWidthView:(UIView *)view model:(SDAutoLayoutModel *)model
{
    if ([view isKindOfClass:[UILabel class]]) {
        UILabel *label = (UILabel *)view;
        CGFloat width = [view.sd_maxWidth floatValue] > 0 ? [view.sd_maxWidth floatValue] : MAXFLOAT;
        label.numberOfLines = 1;
        if (label.text.length) {
            if (!label.isAttributedContent) {
                CGRect rect = [label.text boundingRectWithSize:CGSizeMake(MAXFLOAT, label.height_sd) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName : label.font} context:nil];
                if (rect.size.width > width) {
                    rect.size.width = width;
                }
                label.width_sd = rect.size.width + 0.1;
            } else{
                [label sizeToFit];
                if (label.width_sd > width) {
                    label.width_sd = width;
                }
            }
        } else {
            label.size_sd = CGSizeZero;
        }
    }
}
- (void)layoutWidthWithView:(UIView *)view model:(SDAutoLayoutModel *)model
{
    if (model.width) {
        view.width_sd = [model.width.value floatValue];
        view.fixedWidth = @(view.width_sd);
    } else if (model.ratio_width) {
        view.width_sd = model.ratio_width.refView.width_sd * [model.ratio_width.value floatValue];
        view.fixedWidth = @(view.width_sd);
    }
}
- (void)layoutHeightWithView:(UIView *)view model:(SDAutoLayoutModel *)model
{
    if (model.height) {
        view.height_sd = [model.height.value floatValue];
        view.fixedHeight = @(view.height_sd);
    } else if (model.ratio_height) {
        view.height_sd = [model.ratio_height.value floatValue] * model.ratio_height.refView.height_sd;
        view.fixedHeight = @(view.height_sd);
    }
}
- (void)layoutLeftWithView:(UIView *)view model:(SDAutoLayoutModel *)model
{
    if (model.left) {
        if (view.superview == model.left.refView) {
            if (!view.fixedWidth) { // view.autoLeft && view.autoRight
                view.width_sd = view.right_sd - [model.left.value floatValue];
            }
            view.left_sd = [model.left.value floatValue];
        } else {
            if (model.left.refViewsArray.count) {
                CGFloat lastRefRight = 0;
                for (UIView *ref in model.left.refViewsArray) {
                    if ([ref isKindOfClass:[UIView class]] && ref.right_sd > lastRefRight) {
                        model.left.refView = ref;
                        lastRefRight = ref.right_sd;
                    }
                }
            }
            if (!view.fixedWidth) { // view.autoLeft && view.autoRight
                view.width_sd = view.right_sd - model.left.refView.right_sd - [model.left.value floatValue];
            }
            view.left_sd = model.left.refView.right_sd + [model.left.value floatValue];
        }
    } else if (model.equalLeft) {
        if (!view.fixedWidth) {
            if (model.needsAutoResizeView == view.superview) {
                view.width_sd = view.right_sd - (0 + model.equalLeft.offset);
            } else {
                view.width_sd = view.right_sd  - (model.equalLeft.refView.left_sd + model.equalLeft.offset);
            }
        }
        if (view.superview == model.equalLeft.refView) {
            view.left_sd = 0 + model.equalLeft.offset;
        } else {
            view.left_sd = model.equalLeft.refView.left_sd + model.equalLeft.offset;
        }
    } else if (model.equalCenterX) {
        if (view.superview == model.equalCenterX.refView) {
            view.centerX_sd = model.equalCenterX.refView.width_sd * 0.5 + model.equalCenterX.offset;
        } else {
            view.centerX_sd = model.equalCenterX.refView.centerX_sd + model.equalCenterX.offset;
        }
    } else if (model.centerX) {
        view.centerX_sd = [model.centerX floatValue];
    }
}
- (void)layoutRightWithView:(UIView *)view model:(SDAutoLayoutModel *)model
{
    if (model.right) {
        if (view.superview == model.right.refView) {
            if (!view.fixedWidth) { // view.autoLeft && view.autoRight
                view.width_sd = model.right.refView.width_sd - view.left_sd - [model.right.value floatValue];
            }
            view.right_sd = model.right.refView.width_sd - [model.right.value floatValue];
        } else {
            if (!view.fixedWidth) { // view.autoLeft && view.autoRight
                view.width_sd =  model.right.refView.left_sd - view.left_sd - [model.right.value floatValue];
            }
            view.right_sd = model.right.refView.left_sd - [model.right.value floatValue];
        }
    } else if (model.equalRight) {
        if (!view.fixedWidth) {
            if (model.equalRight.refView == view.superview) {
                view.width_sd = model.equalRight.refView.width_sd - view.left_sd + model.equalRight.offset;
            } else {
                view.width_sd = model.equalRight.refView.right_sd - view.left_sd + model.equalRight.offset;
            }
        }
        view.right_sd = model.equalRight.refView.right_sd + model.equalRight.offset;
        if (view.superview == model.equalRight.refView) {
            view.right_sd = model.equalRight.refView.width_sd + model.equalRight.offset;
        }
    }
}
- (void)layoutTopWithView:(UIView *)view model:(SDAutoLayoutModel *)model
{
    if (model.top) {
        if (view.superview == model.top.refView) {
            if (!view.fixedHeight) { // view.autoTop && view.autoBottom && view.bottom
                view.height_sd = view.bottom_sd - [model.top.value floatValue];
            }
            view.top_sd = [model.top.value floatValue];
        } else {
            if (model.top.refViewsArray.count) {
                CGFloat lastRefBottom = 0;
                for (UIView *ref in model.top.refViewsArray) {
                    if ([ref isKindOfClass:[UIView class]] && ref.bottom_sd > lastRefBottom) {
                        model.top.refView = ref;
                        lastRefBottom = ref.bottom_sd;
                    }
                }
            }
            if (!view.fixedHeight) { // view.autoTop && view.autoBottom && view.bottom
                view.height_sd = view.bottom_sd - model.top.refView.bottom_sd - [model.top.value floatValue];
            }
            view.top_sd = model.top.refView.bottom_sd + [model.top.value floatValue];
        }
    } else if (model.equalTop) {
        if (view.superview == model.equalTop.refView) {
            if (!view.fixedHeight) {
                view.height_sd = view.bottom_sd - model.equalTop.offset;
            }
            view.top_sd = 0 + model.equalTop.offset;
        } else {
            if (!view.fixedHeight) {
                view.height_sd = view.bottom_sd - (model.equalTop.refView.top_sd + model.equalTop.offset);
            }
            view.top_sd = model.equalTop.refView.top_sd + model.equalTop.offset;
        }
    } else if (model.equalCenterY) {
        if (view.superview == model.equalCenterY.refView) {
            view.centerY_sd = model.equalCenterY.refView.height_sd * 0.5 + model.equalCenterY.offset;
        } else {
            view.centerY_sd = model.equalCenterY.refView.centerY_sd + model.equalCenterY.offset;
        }
    } else if (model.centerY) {
        view.centerY_sd = [model.centerY floatValue];
    }
}
- (void)layoutBottomWithView:(UIView *)view model:(SDAutoLayoutModel *)model
{
    if (model.bottom) {
        if (view.superview == model.bottom.refView) {
            if (!view.fixedHeight) {
                view.height_sd = view.superview.height_sd - view.top_sd - [model.bottom.value floatValue];
            }
            view.bottom_sd = model.bottom.refView.height_sd - [model.bottom.value floatValue];
        } else {
            if (!view.fixedHeight) {
                view.height_sd = model.bottom.refView.top_sd - view.top_sd - [model.bottom.value floatValue];
            }
            view.bottom_sd = model.bottom.refView.top_sd - [model.bottom.value floatValue];
        }
    } else if (model.equalBottom) {
        if (view.superview == model.equalBottom.refView) {
            if (!view.fixedHeight) {
                view.height_sd = view.superview.height_sd - view.top_sd + model.equalBottom.offset;
            }
            view.bottom_sd = model.equalBottom.refView.height_sd + model.equalBottom.offset;
        } else {
            if (!view.fixedHeight) {
                view.height_sd = model.equalBottom.refView.bottom_sd - view.top_sd + model.equalBottom.offset;
            }
            view.bottom_sd = model.equalBottom.refView.bottom_sd + model.equalBottom.offset;
        }
    }
    if (model.widthEqualHeight && !view.fixedHeight) {
        [self layoutRightWithView:view model:model];
    }
}
- (void)setupCornerRadiusWithView:(UIView *)view model:(SDAutoLayoutModel *)model
{
    CGFloat cornerRadius = view.layer.cornerRadius;
    CGFloat newCornerRadius = 0;
    if (view.sd_cornerRadius && (cornerRadius != [view.sd_cornerRadius floatValue])) {
        newCornerRadius = [view.sd_cornerRadius floatValue];
    } else if (view.sd_cornerRadiusFromWidthRatio && (cornerRadius != [view.sd_cornerRadiusFromWidthRatio floatValue] * view.width_sd)) {
        newCornerRadius = view.width_sd * [view.sd_cornerRadiusFromWidthRatio floatValue];
    } else if (view.sd_cornerRadiusFromHeightRatio && (cornerRadius != view.height_sd * [view.sd_cornerRadiusFromHeightRatio floatValue])) {
        newCornerRadius = view.height_sd * [view.sd_cornerRadiusFromHeightRatio floatValue];
    }
    if (newCornerRadius > 0) {
        view.layer.cornerRadius = newCornerRadius;
        view.clipsToBounds = YES;
    }
}
- (void)addAutoLayoutModel:(SDAutoLayoutModel *)model
{
    [self.autoLayoutModelsArray addObject:model];
}
@end
@implementation UIButton (SDAutoLayoutButton)
+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSString *selString = @"layoutSubviews";
        NSString *mySelString = [@"sd_button_" stringByAppendingString:selString];
        Method originalMethod = class_getInstanceMethod(self, NSSelectorFromString(selString));
        Method myMethod = class_getInstanceMethod(self, NSSelectorFromString(mySelString));
        method_exchangeImplementations(originalMethod, myMethod);
    });
}
- (void)sd_button_layoutSubviews
{
    // å¦‚果程序崩溃在这行代码说明是你的view在执行“layoutSubvies”方法时出了问题而不是在此自动布局库内部出现了问题,请检查你的“layoutSubvies”方法
    [self sd_button_layoutSubviews];
    [self sd_layoutSubviewsHandle];
}
@end
@implementation UIView (SDChangeFrame)
- (BOOL)shouldReadjustFrameBeforeStoreCache
{
    return self.sd_categoryManager.shouldReadjustFrameBeforeStoreCache;
}
- (void)setShouldReadjustFrameBeforeStoreCache:(BOOL)shouldReadjustFrameBeforeStoreCache
{
    self.sd_categoryManager.shouldReadjustFrameBeforeStoreCache = shouldReadjustFrameBeforeStoreCache;
}
- (CGFloat)left_sd {
    return self.frame.origin.x;
}
- (void)setLeft_sd:(CGFloat)x_sd {
    CGRect frame = self.frame;
    frame.origin.x = x_sd;
    self.frame = frame;
}
- (CGFloat)top_sd {
    return self.frame.origin.y;
}
- (void)setTop_sd:(CGFloat)y_sd {
    CGRect frame = self.frame;
    frame.origin.y = y_sd;
    self.frame = frame;
}
- (CGFloat)right_sd {
    return self.frame.origin.x + self.frame.size.width;
}
- (void)setRight_sd:(CGFloat)right_sd {
    CGRect frame = self.frame;
    frame.origin.x = right_sd - frame.size.width;
    self.frame = frame;
}
- (CGFloat)bottom_sd {
    return self.frame.origin.y + self.frame.size.height;
}
- (void)setBottom_sd:(CGFloat)bottom_sd {
    CGRect frame = self.frame;
    frame.origin.y = bottom_sd - frame.size.height;
    self.frame = frame;
}
- (CGFloat)centerX_sd
{
    return self.left_sd + self.width_sd * 0.5;
}
- (void)setCenterX_sd:(CGFloat)centerX_sd
{
    self.left_sd = centerX_sd - self.width_sd * 0.5;
}
- (CGFloat)centerY_sd
{
    return self.top_sd + self.height_sd * 0.5;
}
- (void)setCenterY_sd:(CGFloat)centerY_sd
{
    self.top_sd = centerY_sd - self.height_sd * 0.5;
}
- (CGFloat)width_sd {
    return self.frame.size.width;
}
- (void)setWidth_sd:(CGFloat)width_sd {
    if (self.ownLayoutModel.widthEqualHeight) {
        if (width_sd != self.height_sd) return;
    }
    [self setWidth:width_sd];
    if (self.ownLayoutModel.heightEqualWidth) {
        self.height_sd = width_sd;
    }
}
- (CGFloat)height_sd {
    return self.frame.size.height;
}
- (void)setHeight_sd:(CGFloat)height_sd {
    if (self.ownLayoutModel.heightEqualWidth) {
        if (height_sd != self.width_sd) return;
    }
    [self setHeight:height_sd];
    if (self.ownLayoutModel.widthEqualHeight) {
        self.width_sd = height_sd;
    }
}
- (CGPoint)origin_sd {
    return self.frame.origin;
}
- (void)setOrigin_sd:(CGPoint)origin_sd {
    CGRect frame = self.frame;
    frame.origin = origin_sd;
    self.frame = frame;
}
- (CGSize)size_sd {
    return self.frame.size;
}
- (void)setSize_sd:(CGSize)size_sd {
    [self setSize:size_sd];
}
- (void)setWidth:(CGFloat)width
{
    CGRect frame = self.frame;
    frame.size.width = width;
    self.frame = frame;
}
- (void)setHeight:(CGFloat)height {
    CGRect frame = self.frame;
    frame.size.height = height;
    self.frame = frame;
}
- (void)setSize:(CGSize)size {
    CGRect frame = self.frame;
    frame.size = size;
    self.frame = frame;
}
// å…¼å®¹æ—§ç‰ˆæœ¬
- (CGFloat)left
{
    return self.left_sd;
}
- (void)setLeft:(CGFloat)left
{
    self.left_sd = left;
}
- (CGFloat)right
{
    return self.right_sd;
}
- (void)setRight:(CGFloat)right
{
    self.right_sd = right;
}
- (CGFloat)width
{
    return self.width_sd;
}
- (CGFloat)height
{
    return self.height_sd;
}
- (CGFloat)top
{
    return self.top_sd;
}
- (void)setTop:(CGFloat)top
{
    self.top_sd = top;
}
- (CGFloat)bottom
{
    return self.bottom_sd;
}
- (void)setBottom:(CGFloat)bottom
{
    self.bottom_sd = bottom;
}
- (CGFloat)centerX
{
    return self.centerX_sd;
}
- (void)setCenterX:(CGFloat)centerX
{
    self.centerX_sd = centerX;
}
- (CGFloat)centerY
{
    return self.centerY_sd;
}
- (void)setCenterY:(CGFloat)centerY
{
    self.centerY_sd = centerY;
}
- (CGPoint)origin
{
    return self.origin_sd;
}
- (void)setOrigin:(CGPoint)origin
{
    self.origin_sd = origin;
}
- (CGSize)size
{
    return self.size_sd;
}
@end
@implementation SDUIViewCategoryManager
@end
Diff truncated after the above file
Pods/Target Support Files/Pods-MIduo/Pods-MIduo-acknowledgements.markdown Pods/Target Support Files/Pods-MIduo/Pods-MIduo-acknowledgements.plist Pods/Target Support Files/Pods-MIduo/Pods-MIduo-frameworks.sh Pods/Target Support Files/Pods-MIduo/Pods-MIduo.debug.xcconfig Pods/Target Support Files/Pods-MIduo/Pods-MIduo.release.xcconfig Pods/Target Support Files/ReactiveCocoa/Info.plist Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa-dummy.m Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa-prefix.pch Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa-umbrella.h Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa.modulemap Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa.xcconfig Pods/Target Support Files/SDAutoLayout/Info.plist Pods/Target Support Files/SDAutoLayout/SDAutoLayout-dummy.m Pods/Target Support Files/SDAutoLayout/SDAutoLayout-prefix.pch Pods/Target Support Files/SDAutoLayout/SDAutoLayout-umbrella.h Pods/Target Support Files/SDAutoLayout/SDAutoLayout.modulemap Pods/Target Support Files/SDAutoLayout/SDAutoLayout.xcconfig