提交
This commit is contained in:
19
Pods/ReactiveObjC/LICENSE.md
generated
Normal file
19
Pods/ReactiveObjC/LICENSE.md
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
**Copyright (c) 2012 - 2016, 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.
|
||||
547
Pods/ReactiveObjC/README.md
generated
Normal file
547
Pods/ReactiveObjC/README.md
generated
Normal file
@@ -0,0 +1,547 @@
|
||||
# ReactiveObjC
|
||||
|
||||
_NOTE: This is legacy introduction to the Objective-C ReactiveCocoa, which is
|
||||
now known as ReactiveObjC. For the updated version that uses Swift, please see
|
||||
[ReactiveCocoa][] or [ReactiveSwift][]_
|
||||
|
||||
ReactiveObjC (formally ReactiveCocoa or 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 ReactiveObjC, check out the other documentation in this folder for a
|
||||
framework overview and more in-depth information about how it all works in practice.
|
||||
|
||||
## New to ReactiveObjC?
|
||||
|
||||
ReactiveObjC 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 ReactiveObjC](#when-to-use-reactiveobjc)
|
||||
1. [Framework Overview][]
|
||||
1. [Basic Operators][]
|
||||
1. [Header documentation](ReactiveObjC/)
|
||||
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 this 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/ReactiveObjC/issues/new).
|
||||
|
||||
## Introduction
|
||||
|
||||
ReactiveObjC 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 ReactiveObjC. Additional information about RAC can be found
|
||||
in this folder.
|
||||
|
||||
## When to use ReactiveObjC
|
||||
|
||||
Upon first glance, ReactiveObjC 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];
|
||||
}];
|
||||
```
|
||||
|
||||
ReactiveObjC 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
|
||||
|
||||
ReactiveObjC supports OS X 10.8+ and iOS 8.0+.
|
||||
|
||||
## Importing ReactiveObjC
|
||||
|
||||
To add RAC to your application:
|
||||
|
||||
1. Add the ReactiveObjC repository as a submodule of your application's
|
||||
repository.
|
||||
1. Run `git submodule update --init --recursive` from within the ReactiveObjC folder.
|
||||
1. Drag and drop `ReactiveObjC.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.
|
||||
1. Add `ReactiveObjC.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.
|
||||
|
||||
To see a project already set up with RAC, check out [C-41][] or [GroceryList][],
|
||||
which are real iOS apps written using ReactiveObjC.
|
||||
|
||||
## More Info
|
||||
|
||||
ReactiveObjC is inspired by .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)
|
||||
* [Principles of Reactive Programming on Coursera](https://www.coursera.org/course/reactive)
|
||||
|
||||
[ReactiveCocoa]: https://github.com/ReactiveCocoa/ReactiveCocoa
|
||||
[ReactiveSwift]: https://github.com/ReactiveCocoa/ReactiveSwift
|
||||
[Basic Operators]: Documentation/BasicOperators.md
|
||||
[Framework Overview]: Documentation/FrameworkOverview.md
|
||||
[Functional Reactive Programming]: http://en.wikipedia.org/wiki/Functional_reactive_programming
|
||||
[GroceryList]: https://github.com/jspahrsummers/GroceryList
|
||||
[RACSequence]: ReactiveObjC/RACSequence.h
|
||||
[RACSignal]: ReactiveOjC/RACSignal.h
|
||||
[futures and promises]: http://en.wikipedia.org/wiki/Futures_and_promises
|
||||
[C-41]: https://github.com/AshFurrow/C-41
|
||||
34
Pods/ReactiveObjC/ReactiveObjC/MKAnnotationView+RACSignalSupport.h
generated
Normal file
34
Pods/ReactiveObjC/ReactiveObjC/MKAnnotationView+RACSignalSupport.h
generated
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// MKAnnotationView+RACSignalSupport.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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<__covariant ValueType>;
|
||||
@class RACUnit;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@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<RACUnit *> *rac_prepareForReuseSignal;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
31
Pods/ReactiveObjC/ReactiveObjC/MKAnnotationView+RACSignalSupport.m
generated
Normal file
31
Pods/ReactiveObjC/ReactiveObjC/MKAnnotationView+RACSignalSupport.m
generated
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// MKAnnotationView+RACSignalSupport.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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", RACDescription(self)];
|
||||
|
||||
objc_setAssociatedObject(self, _cmd, signal, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
return signal;
|
||||
}
|
||||
|
||||
@end
|
||||
24
Pods/ReactiveObjC/ReactiveObjC/NSArray+RACSequenceAdditions.h
generated
Normal file
24
Pods/ReactiveObjC/ReactiveObjC/NSArray+RACSequenceAdditions.h
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// NSArray+RACSequenceAdditions.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Justin Spahr-Summers on 2012-10-29.
|
||||
// Copyright (c) 2012 GitHub. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACSequence<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSArray<__covariant ObjectType> (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<ObjectType> *rac_sequence;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
18
Pods/ReactiveObjC/ReactiveObjC/NSArray+RACSequenceAdditions.m
generated
Normal file
18
Pods/ReactiveObjC/ReactiveObjC/NSArray+RACSequenceAdditions.m
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// NSArray+RACSequenceAdditions.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
26
Pods/ReactiveObjC/ReactiveObjC/NSData+RACSupport.h
generated
Normal file
26
Pods/ReactiveObjC/ReactiveObjC/NSData+RACSupport.h
generated
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// NSData+RACSupport.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 5/11/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACScheduler;
|
||||
@class RACSignal<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@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<NSData *> *)rac_readContentsOfURL:(nullable NSURL *)URL options:(NSDataReadingOptions)options scheduler:(RACScheduler *)scheduler;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
35
Pods/ReactiveObjC/ReactiveObjC/NSData+RACSupport.m
generated
Normal file
35
Pods/ReactiveObjC/ReactiveObjC/NSData+RACSupport.m
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// NSData+RACSupport.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
35
Pods/ReactiveObjC/ReactiveObjC/NSDictionary+RACSequenceAdditions.h
generated
Normal file
35
Pods/ReactiveObjC/ReactiveObjC/NSDictionary+RACSequenceAdditions.h
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// NSDictionary+RACSequenceAdditions.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Justin Spahr-Summers on 2012-10-29.
|
||||
// Copyright (c) 2012 GitHub. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACSequence<__covariant ValueType>;
|
||||
@class RACTwoTuple<__covariant First, __covariant Second>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSDictionary<__covariant KeyType, __covariant ObjectType> (RACSequenceAdditions)
|
||||
|
||||
/// Creates and returns a sequence of key/value tuples.
|
||||
///
|
||||
/// Mutating the receiver will not affect the sequence after it's been created.
|
||||
@property (nonatomic, copy, readonly) RACSequence<RACTwoTuple<KeyType, ObjectType> *> *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<KeyType> *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<ObjectType> *rac_valueSequence;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
34
Pods/ReactiveObjC/ReactiveObjC/NSDictionary+RACSequenceAdditions.m
generated
Normal file
34
Pods/ReactiveObjC/ReactiveObjC/NSDictionary+RACSequenceAdditions.m
generated
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// NSDictionary+RACSequenceAdditions.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
24
Pods/ReactiveObjC/ReactiveObjC/NSEnumerator+RACSequenceAdditions.h
generated
Normal file
24
Pods/ReactiveObjC/ReactiveObjC/NSEnumerator+RACSequenceAdditions.h
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// NSEnumerator+RACSequenceAdditions.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Uri Baghin on 07/01/2013.
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACSequence<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSEnumerator<ObjectType> (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<ObjectType> *rac_sequence;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
22
Pods/ReactiveObjC/ReactiveObjC/NSEnumerator+RACSequenceAdditions.m
generated
Normal file
22
Pods/ReactiveObjC/ReactiveObjC/NSEnumerator+RACSequenceAdditions.m
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// NSEnumerator+RACSequenceAdditions.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
23
Pods/ReactiveObjC/ReactiveObjC/NSFileHandle+RACSupport.h
generated
Normal file
23
Pods/ReactiveObjC/ReactiveObjC/NSFileHandle+RACSupport.h
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// NSFileHandle+RACSupport.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 5/10/12.
|
||||
// Copyright (c) 2012 GitHub. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACSignal<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSFileHandle (RACSupport)
|
||||
|
||||
// Read any available data in the background and send it. Completes when data
|
||||
// length is <= 0.
|
||||
- (RACSignal<NSData *> *)rac_readInBackground;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
40
Pods/ReactiveObjC/ReactiveObjC/NSFileHandle+RACSupport.m
generated
Normal file
40
Pods/ReactiveObjC/ReactiveObjC/NSFileHandle+RACSupport.m
generated
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// NSFileHandle+RACSupport.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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", RACDescription(self)];
|
||||
|
||||
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
|
||||
25
Pods/ReactiveObjC/ReactiveObjC/NSIndexSet+RACSequenceAdditions.h
generated
Normal file
25
Pods/ReactiveObjC/ReactiveObjC/NSIndexSet+RACSequenceAdditions.h
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// NSIndexSet+RACSequenceAdditions.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Sergey Gavrilyuk on 12/17/13.
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACSequence<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@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<NSNumber *> *rac_sequence;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
18
Pods/ReactiveObjC/ReactiveObjC/NSIndexSet+RACSequenceAdditions.m
generated
Normal file
18
Pods/ReactiveObjC/ReactiveObjC/NSIndexSet+RACSequenceAdditions.m
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// NSIndexSet+RACSequenceAdditions.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
56
Pods/ReactiveObjC/ReactiveObjC/NSInvocation+RACTypeParsing.h
generated
Normal file
56
Pods/ReactiveObjC/ReactiveObjC/NSInvocation+RACTypeParsing.h
generated
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// NSInvocation+RACTypeParsing.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
232
Pods/ReactiveObjC/ReactiveObjC/NSInvocation+RACTypeParsing.m
generated
Normal file
232
Pods/ReactiveObjC/ReactiveObjC/NSInvocation+RACTypeParsing.m
generated
Normal file
@@ -0,0 +1,232 @@
|
||||
//
|
||||
// NSInvocation+RACTypeParsing.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
22
Pods/ReactiveObjC/ReactiveObjC/NSNotificationCenter+RACSupport.h
generated
Normal file
22
Pods/ReactiveObjC/ReactiveObjC/NSNotificationCenter+RACSupport.h
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// NSNotificationCenter+RACSupport.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 5/10/12.
|
||||
// Copyright (c) 2012 GitHub. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACSignal<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSNotificationCenter (RACSupport)
|
||||
|
||||
// Sends the NSNotification every time the notification is posted.
|
||||
- (RACSignal<NSNotification *> *)rac_addObserverForName:(nullable NSString *)notificationName object:(nullable id)object;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
31
Pods/ReactiveObjC/ReactiveObjC/NSNotificationCenter+RACSupport.m
generated
Normal file
31
Pods/ReactiveObjC/ReactiveObjC/NSNotificationCenter+RACSupport.m
generated
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// NSNotificationCenter+RACSupport.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 5/10/12.
|
||||
// Copyright (c) 2012 GitHub. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSNotificationCenter+RACSupport.h"
|
||||
#import <ReactiveObjC/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
|
||||
30
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACDeallocating.h
generated
Normal file
30
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACDeallocating.h
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// NSObject+RACDeallocating.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@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
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
103
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACDeallocating.m
generated
Normal file
103
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACDeallocating.m
generated
Normal file
@@ -0,0 +1,103 @@
|
||||
//
|
||||
// NSObject+RACDeallocating.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
16
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACDescription.h
generated
Normal file
16
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACDescription.h
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// NSObject+RACDescription.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Justin Spahr-Summers on 2013-05-13.
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// A simplified description of the object, 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 *RACDescription(id object);
|
||||
50
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACDescription.m
generated
Normal file
50
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACDescription.m
generated
Normal file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// NSObject+RACDescription.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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 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
|
||||
|
||||
NSString *RACDescription(id object) {
|
||||
if (getenv("RAC_DEBUG_SIGNAL_NAMES") != NULL) {
|
||||
if ([object respondsToSelector:@selector(rac_description)]) {
|
||||
return [object rac_description];
|
||||
} else {
|
||||
return [[NSString alloc] initWithFormat:@"<%@: %p>", [object class], object];
|
||||
}
|
||||
} else {
|
||||
return @"(description skipped)";
|
||||
}
|
||||
}
|
||||
46
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACKVOWrapper.h
generated
Normal file
46
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACKVOWrapper.h
generated
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// NSObject+RACKVOWrapper.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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 (RACUnavailableKVOWrapper)
|
||||
|
||||
- (RACKVOTrampoline *)rac_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block __attribute((unavailable("Use rac_observeKeyPath:options:observer:block: instead.")));
|
||||
|
||||
@end
|
||||
200
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACKVOWrapper.m
generated
Normal file
200
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACKVOWrapper.m
generated
Normal file
@@ -0,0 +1,200 @@
|
||||
//
|
||||
// NSObject+RACKVOWrapper.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 10/11/11.
|
||||
// Copyright (c) 2011 GitHub. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+RACKVOWrapper.h"
|
||||
#import <ReactiveObjC/RACEXTRuntimeExtensions.h>
|
||||
#import <ReactiveObjC/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(^)(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
|
||||
51
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACLifting.h
generated
Normal file
51
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACLifting.h
generated
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// NSObject+RACLifting.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 10/13/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACSignal<__covariant ValueType>;
|
||||
@class RACTuple;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@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<RACSignal *> *)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<RACTuple *> *)arguments;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
78
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACLifting.m
generated
Normal file
78
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACLifting.m
generated
Normal file
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// NSObject+RACLifting.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 10/13/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+RACLifting.h"
|
||||
#import <ReactiveObjC/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: %@", RACDescription(self), 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: %@", RACDescription(self), 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: %@", RACDescription(self), sel_getName(selector), signals];
|
||||
}
|
||||
|
||||
@end
|
||||
120
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACPropertySubscribing.h
generated
Normal file
120
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACPropertySubscribing.h
generated
Normal file
@@ -0,0 +1,120 @@
|
||||
//
|
||||
// NSObject+RACPropertySubscribing.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 3/2/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <ReactiveObjC/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]; \
|
||||
})
|
||||
|
||||
#if __clang__ && (__clang_major__ >= 8)
|
||||
#define RACObserve(TARGET, KEYPATH) _RACObserve(TARGET, KEYPATH)
|
||||
#else
|
||||
#define RACObserve(TARGET, KEYPATH) \
|
||||
({ \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wreceiver-is-weak\"") \
|
||||
_RACObserve(TARGET, KEYPATH) \
|
||||
_Pragma("clang diagnostic pop") \
|
||||
})
|
||||
#endif
|
||||
|
||||
@class RACDisposable;
|
||||
@class RACTwoTuple<__covariant First, __covariant Second>;
|
||||
@class RACSignal<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@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.
|
||||
#if OS_OBJECT_HAVE_OBJC_SUPPORT
|
||||
- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer;
|
||||
#else
|
||||
// Swift builds with OS_OBJECT_HAVE_OBJC_SUPPORT=0 for Playgrounds and LLDB :(
|
||||
- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(NSObject *)observer;
|
||||
#endif
|
||||
|
||||
/// Creates a signal to observe the changes of the given key path.
|
||||
///
|
||||
/// The initial value is sent on subscription if `NSKeyValueObservingOptionInitial` is set.
|
||||
/// 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.
|
||||
#if OS_OBJECT_HAVE_OBJC_SUPPORT
|
||||
- (RACSignal<RACTwoTuple<id, NSDictionary *> *> *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)observer;
|
||||
#else
|
||||
- (RACSignal<RACTwoTuple<id, NSDictionary *> *> *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(NSObject *)observer;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_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]
|
||||
84
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACPropertySubscribing.m
generated
Normal file
84
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACPropertySubscribing.m
generated
Normal file
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// NSObject+RACPropertySubscribing.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 3/2/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+RACPropertySubscribing.h"
|
||||
#import <ReactiveObjC/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(%@, %@)", RACDescription(self), 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.ReactiveObjC.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: %@", RACDescription(self), keyPath, (unsigned long)options, RACDescription(strongObserver)];
|
||||
}
|
||||
|
||||
@end
|
||||
86
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACSelectorSignal.h
generated
Normal file
86
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACSelectorSignal.h
generated
Normal file
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// NSObject+RACSelectorSignal.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 3/18/13.
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACTuple;
|
||||
@class RACSignal<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// The domain for any errors originating from -rac_signalForSelector:.
|
||||
extern NSErrorDomain const RACSelectorSignalErrorDomain;
|
||||
|
||||
typedef NS_ERROR_ENUM(RACSelectorSignalErrorDomain, RACSelectorSignalError) {
|
||||
/// -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.
|
||||
RACSelectorSignalErrorMethodSwizzlingRace = 1,
|
||||
};
|
||||
|
||||
@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<RACTuple *> *)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<RACTuple *> *)rac_signalForSelector:(SEL)selector fromProtocol:(Protocol *)protocol;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
328
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACSelectorSignal.m
generated
Normal file
328
Pods/ReactiveObjC/ReactiveObjC/NSObject+RACSelectorSignal.m
generated
Normal file
@@ -0,0 +1,328 @@
|
||||
//
|
||||
// NSObject+RACSelectorSignal.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 3/18/13.
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+RACSelectorSignal.h"
|
||||
#import <ReactiveObjC/RACEXTRuntimeExtensions.h>
|
||||
#import "NSInvocation+RACTypeParsing.h"
|
||||
#import "NSObject+RACDeallocating.h"
|
||||
#import "RACCompoundDisposable.h"
|
||||
#import "RACDisposable.h"
|
||||
#import "RACSubject.h"
|
||||
#import "RACTuple.h"
|
||||
#import "NSObject+RACDescription.h"
|
||||
#import <objc/message.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
NSErrorDomain const RACSelectorSignalErrorDomain = @"RACSelectorSignalErrorDomain";
|
||||
|
||||
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", RACDescription(self), 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 = objc_allocateClassPair(baseClass, subclassName, 0);
|
||||
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
|
||||
24
Pods/ReactiveObjC/ReactiveObjC/NSOrderedSet+RACSequenceAdditions.h
generated
Normal file
24
Pods/ReactiveObjC/ReactiveObjC/NSOrderedSet+RACSequenceAdditions.h
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// NSOrderedSet+RACSequenceAdditions.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Justin Spahr-Summers on 2012-10-29.
|
||||
// Copyright (c) 2012 GitHub. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACSequence<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSOrderedSet<__covariant ObjectType> (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<ObjectType> *rac_sequence;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
19
Pods/ReactiveObjC/ReactiveObjC/NSOrderedSet+RACSequenceAdditions.m
generated
Normal file
19
Pods/ReactiveObjC/ReactiveObjC/NSOrderedSet+RACSequenceAdditions.m
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// NSOrderedSet+RACSequenceAdditions.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
24
Pods/ReactiveObjC/ReactiveObjC/NSSet+RACSequenceAdditions.h
generated
Normal file
24
Pods/ReactiveObjC/ReactiveObjC/NSSet+RACSequenceAdditions.h
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// NSSet+RACSequenceAdditions.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Justin Spahr-Summers on 2012-10-29.
|
||||
// Copyright (c) 2012 GitHub. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACSequence<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSSet<__covariant ObjectType> (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<ObjectType> *rac_sequence;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
19
Pods/ReactiveObjC/ReactiveObjC/NSSet+RACSequenceAdditions.m
generated
Normal file
19
Pods/ReactiveObjC/ReactiveObjC/NSSet+RACSequenceAdditions.m
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// NSSet+RACSequenceAdditions.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
34
Pods/ReactiveObjC/ReactiveObjC/NSString+RACKeyPathUtilities.h
generated
Normal file
34
Pods/ReactiveObjC/ReactiveObjC/NSString+RACKeyPathUtilities.h
generated
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// NSString+RACKeyPathUtilities.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
36
Pods/ReactiveObjC/ReactiveObjC/NSString+RACKeyPathUtilities.m
generated
Normal file
36
Pods/ReactiveObjC/ReactiveObjC/NSString+RACKeyPathUtilities.m
generated
Normal file
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// NSString+RACKeyPathUtilities.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
25
Pods/ReactiveObjC/ReactiveObjC/NSString+RACSequenceAdditions.h
generated
Normal file
25
Pods/ReactiveObjC/ReactiveObjC/NSString+RACSequenceAdditions.h
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// NSString+RACSequenceAdditions.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Justin Spahr-Summers on 2012-10-29.
|
||||
// Copyright (c) 2012 GitHub. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACSequence<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@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<NSString *> *rac_sequence;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
18
Pods/ReactiveObjC/ReactiveObjC/NSString+RACSequenceAdditions.m
generated
Normal file
18
Pods/ReactiveObjC/ReactiveObjC/NSString+RACSequenceAdditions.m
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// NSString+RACSequenceAdditions.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
26
Pods/ReactiveObjC/ReactiveObjC/NSString+RACSupport.h
generated
Normal file
26
Pods/ReactiveObjC/ReactiveObjC/NSString+RACSupport.h
generated
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// NSString+RACSupport.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 5/11/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACScheduler;
|
||||
@class RACSignal<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@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<NSString *> *)rac_readContentsOfURL:(NSURL *)URL usedEncoding:(NSStringEncoding *)encoding scheduler:(RACScheduler *)scheduler;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
37
Pods/ReactiveObjC/ReactiveObjC/NSString+RACSupport.m
generated
Normal file
37
Pods/ReactiveObjC/ReactiveObjC/NSString+RACSupport.m
generated
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// NSString+RACSupport.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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(URL != nil);
|
||||
NSCParameterAssert(encoding != nil);
|
||||
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
|
||||
30
Pods/ReactiveObjC/ReactiveObjC/NSURLConnection+RACSupport.h
generated
Normal file
30
Pods/ReactiveObjC/ReactiveObjC/NSURLConnection+RACSupport.h
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// NSURLConnection+RACSupport.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Justin Spahr-Summers on 2013-10-01.
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACTwoTuple<__covariant First, __covariant Second>;
|
||||
@class RACSignal<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@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 tuple of the received response and downloaded data, and complete
|
||||
/// on a background thread. If any errors occur, the returned signal will error
|
||||
/// out.
|
||||
+ (RACSignal<RACTwoTuple<NSURLResponse *, NSData *> *> *)rac_sendAsynchronousRequest:(NSURLRequest *)request;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
54
Pods/ReactiveObjC/ReactiveObjC/NSURLConnection+RACSupport.m
generated
Normal file
54
Pods/ReactiveObjC/ReactiveObjC/NSURLConnection+RACSupport.m
generated
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// NSURLConnection+RACSupport.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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.ReactiveObjC.NSURLConnectionRACSupport";
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[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];
|
||||
}
|
||||
}];
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
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
|
||||
31
Pods/ReactiveObjC/ReactiveObjC/NSUserDefaults+RACSupport.h
generated
Normal file
31
Pods/ReactiveObjC/ReactiveObjC/NSUserDefaults+RACSupport.h
generated
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// NSUserDefaults+RACSupport.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Matt Diephouse on 12/19/13.
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACChannelTerminal;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@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
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
58
Pods/ReactiveObjC/ReactiveObjC/NSUserDefaults+RACSupport.m
generated
Normal file
58
Pods/ReactiveObjC/ReactiveObjC/NSUserDefaults+RACSupport.m
generated
Normal file
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// NSUserDefaults+RACSupport.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Matt Diephouse on 12/19/13.
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSUserDefaults+RACSupport.h"
|
||||
#import <ReactiveObjC/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 {
|
||||
NSParameterAssert(key != nil);
|
||||
|
||||
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
|
||||
11
Pods/ReactiveObjC/ReactiveObjC/RACAnnotations.h
generated
Normal file
11
Pods/ReactiveObjC/ReactiveObjC/RACAnnotations.h
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// RACAnnotations.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Eric Horacek on 3/31/17.
|
||||
// Copyright © 2017 GitHub. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef RAC_WARN_UNUSED_RESULT
|
||||
#define RAC_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#endif
|
||||
18
Pods/ReactiveObjC/ReactiveObjC/RACArraySequence.h
generated
Normal file
18
Pods/ReactiveObjC/ReactiveObjC/RACArraySequence.h
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// RACArraySequence.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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.
|
||||
+ (RACSequence *)sequenceWithArray:(NSArray *)array offset:(NSUInteger)offset;
|
||||
|
||||
@end
|
||||
125
Pods/ReactiveObjC/ReactiveObjC/RACArraySequence.m
generated
Normal file
125
Pods/ReactiveObjC/ReactiveObjC/RACArraySequence.m
generated
Normal file
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// RACArraySequence.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
|
||||
+ (RACSequence *)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
|
||||
|
||||
- (instancetype)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
|
||||
22
Pods/ReactiveObjC/ReactiveObjC/RACBehaviorSubject.h
generated
Normal file
22
Pods/ReactiveObjC/ReactiveObjC/RACBehaviorSubject.h
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// RACBehaviorSubject.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 3/16/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACSubject.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// A behavior subject sends the last value it received when it is subscribed to.
|
||||
@interface RACBehaviorSubject<ValueType> : RACSubject<ValueType>
|
||||
|
||||
/// 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:(nullable ValueType)value;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
56
Pods/ReactiveObjC/ReactiveObjC/RACBehaviorSubject.m
generated
Normal file
56
Pods/ReactiveObjC/ReactiveObjC/RACBehaviorSubject.m
generated
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// RACBehaviorSubject.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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<ValueType> ()
|
||||
|
||||
// This property should only be used while synchronized on self.
|
||||
@property (nonatomic, strong) ValueType 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
|
||||
30
Pods/ReactiveObjC/ReactiveObjC/RACBlockTrampoline.h
generated
Normal file
30
Pods/ReactiveObjC/ReactiveObjC/RACBlockTrampoline.h
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// RACBlockTrampoline.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
155
Pods/ReactiveObjC/ReactiveObjC/RACBlockTrampoline.m
generated
Normal file
155
Pods/ReactiveObjC/ReactiveObjC/RACBlockTrampoline.m
generated
Normal file
@@ -0,0 +1,155 @@
|
||||
//
|
||||
// RACBlockTrampoline.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
|
||||
- (instancetype)initWithBlock:(id)block {
|
||||
self = [super init];
|
||||
|
||||
_block = [block copy];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)invokeBlock:(id)block withArguments:(RACTuple *)arguments {
|
||||
NSCParameterAssert(block != NULL);
|
||||
|
||||
RACBlockTrampoline *trampoline = [(RACBlockTrampoline *)[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
|
||||
77
Pods/ReactiveObjC/ReactiveObjC/RACChannel.h
generated
Normal file
77
Pods/ReactiveObjC/ReactiveObjC/RACChannel.h
generated
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// RACChannel.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Uri Baghin on 01/01/2013.
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACSignal.h"
|
||||
#import "RACSubscriber.h"
|
||||
|
||||
@class RACChannelTerminal<ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 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<ValueType> : 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<ValueType> *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<ValueType> *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<ValueType> : RACSignal<ValueType> <RACSubscriber>
|
||||
|
||||
- (instancetype)init __attribute__((unavailable("Instantiate a RACChannel instead")));
|
||||
|
||||
// Redeclaration of the RACSubscriber method. Made in order to specify a generic type.
|
||||
- (void)sendNext:(nullable ValueType)value;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
88
Pods/ReactiveObjC/ReactiveObjC/RACChannel.m
generated
Normal file
88
Pods/ReactiveObjC/ReactiveObjC/RACChannel.m
generated
Normal file
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// RACChannel.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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<ValueType> ()
|
||||
|
||||
/// The values for this terminal.
|
||||
@property (nonatomic, strong, readonly) RACSignal<ValueType> *values;
|
||||
|
||||
/// A subscriber will will send values to the other terminal.
|
||||
@property (nonatomic, strong, readonly) id<RACSubscriber> otherTerminal;
|
||||
|
||||
- (instancetype)initWithValues:(RACSignal<ValueType> *)values otherTerminal:(id<RACSubscriber>)otherTerminal;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RACChannel
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
|
||||
// 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
|
||||
|
||||
- (instancetype)initWithValues:(RACSignal *)values otherTerminal:(id<RACSubscriber>)otherTerminal {
|
||||
NSCParameterAssert(values != nil);
|
||||
NSCParameterAssert(otherTerminal != nil);
|
||||
|
||||
self = [super init];
|
||||
|
||||
_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
|
||||
118
Pods/ReactiveObjC/ReactiveObjC/RACCommand.h
generated
Normal file
118
Pods/ReactiveObjC/ReactiveObjC/RACCommand.h
generated
Normal file
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// RACCommand.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 3/3/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACSignal<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// The domain for errors originating within `RACCommand`.
|
||||
extern NSErrorDomain const RACCommandErrorDomain;
|
||||
|
||||
typedef NS_ERROR_ENUM(RACCommandErrorDomain, RACCommandError) {
|
||||
/// -execute: was invoked while the command was disabled.
|
||||
RACCommandErrorNotEnabled = 1,
|
||||
};
|
||||
|
||||
/// 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<__contravariant InputType, __covariant ValueType> : 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<RACSignal<ValueType> *> *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<NSNumber *> *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<NSNumber *> *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<NSError *> *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`.
|
||||
- (instancetype)initWithSignalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable 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.
|
||||
- (instancetype)initWithEnabled:(nullable RACSignal<NSNumber *> *)enabledSignal signalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable 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<ValueType> *)execute:(nullable InputType)input;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
200
Pods/ReactiveObjC/ReactiveObjC/RACCommand.m
generated
Normal file
200
Pods/ReactiveObjC/ReactiveObjC/RACCommand.m
generated
Normal file
@@ -0,0 +1,200 @@
|
||||
//
|
||||
// RACCommand.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 3/3/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACCommand.h"
|
||||
#import <ReactiveObjC/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>
|
||||
|
||||
NSErrorDomain const RACCommandErrorDomain = @"RACCommandErrorDomain";
|
||||
NSString * const RACUnderlyingCommandErrorKey = @"RACUnderlyingCommandErrorKey";
|
||||
|
||||
@interface RACCommand () {
|
||||
// Atomic backing variable for `allowsConcurrentExecution`.
|
||||
volatile uint32_t _allowsConcurrentExecution;
|
||||
}
|
||||
|
||||
/// A subject that sends added execution signals.
|
||||
@property (nonatomic, strong, readonly) RACSubject *addedExecutionSignalsSubject;
|
||||
|
||||
/// A subject that sends the new value of `allowsConcurrentExecution` whenever it changes.
|
||||
@property (nonatomic, strong, readonly) RACSubject *allowsConcurrentExecutionSubject;
|
||||
|
||||
// `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);
|
||||
|
||||
@end
|
||||
|
||||
@implementation RACCommand
|
||||
|
||||
#pragma mark Properties
|
||||
|
||||
- (BOOL)allowsConcurrentExecution {
|
||||
return _allowsConcurrentExecution != 0;
|
||||
}
|
||||
|
||||
- (void)setAllowsConcurrentExecution:(BOOL)allowed {
|
||||
if (allowed) {
|
||||
OSAtomicOr32Barrier(1, &_allowsConcurrentExecution);
|
||||
} else {
|
||||
OSAtomicAnd32Barrier(0, &_allowsConcurrentExecution);
|
||||
}
|
||||
|
||||
[self.allowsConcurrentExecutionSubject sendNext:@(_allowsConcurrentExecution)];
|
||||
}
|
||||
|
||||
#pragma mark Lifecycle
|
||||
|
||||
- (instancetype)init {
|
||||
NSCAssert(NO, @"Use -initWithSignalBlock: instead");
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (instancetype)initWithSignalBlock:(RACSignal<id> * (^)(id input))signalBlock {
|
||||
return [self initWithEnabled:nil signalBlock:signalBlock];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_addedExecutionSignalsSubject sendCompleted];
|
||||
[_allowsConcurrentExecutionSubject sendCompleted];
|
||||
}
|
||||
|
||||
- (instancetype)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal<id> * (^)(id input))signalBlock {
|
||||
NSCParameterAssert(signalBlock != nil);
|
||||
|
||||
self = [super init];
|
||||
|
||||
_addedExecutionSignalsSubject = [RACSubject new];
|
||||
_allowsConcurrentExecutionSubject = [RACSubject new];
|
||||
_signalBlock = [signalBlock copy];
|
||||
|
||||
_executionSignals = [[[self.addedExecutionSignalsSubject
|
||||
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 = [[[self.addedExecutionSignalsSubject
|
||||
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 = [[[[self.addedExecutionSignalsSubject
|
||||
flattenMap:^(RACSignal *signal) {
|
||||
return [[[signal
|
||||
catchTo:[RACSignal empty]]
|
||||
then:^{
|
||||
return [RACSignal return:@-1];
|
||||
}]
|
||||
startWith:@1];
|
||||
}]
|
||||
scanWithStart:@0 reduce:^(NSNumber *running, NSNumber *next) {
|
||||
return @(running.integerValue + next.integerValue);
|
||||
}]
|
||||
map:^(NSNumber *count) {
|
||||
return @(count.integerValue > 0);
|
||||
}]
|
||||
startWith:@NO];
|
||||
|
||||
_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:[self.allowsConcurrentExecutionSubject startWith:@NO]
|
||||
then:[RACSignal return:@YES]
|
||||
else:[immediateExecuting not]];
|
||||
|
||||
if (enabledSignal == nil) {
|
||||
enabledSignal = [RACSignal return:@YES];
|
||||
} else {
|
||||
enabledSignal = [enabledSignal startWith:@YES];
|
||||
}
|
||||
|
||||
_immediateEnabled = [[[[RACSignal
|
||||
combineLatest:@[ enabledSignal, moreExecutionsAllowed ]]
|
||||
and]
|
||||
takeUntil:self.rac_willDeallocSignal]
|
||||
replayLast];
|
||||
|
||||
_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]];
|
||||
|
||||
[self.addedExecutionSignalsSubject sendNext:connection.signal];
|
||||
|
||||
[connection connect];
|
||||
return [connection.signal setNameWithFormat:@"%@ -execute: %@", self, RACDescription(input)];
|
||||
}
|
||||
|
||||
@end
|
||||
52
Pods/ReactiveObjC/ReactiveObjC/RACCompoundDisposable.h
generated
Normal file
52
Pods/ReactiveObjC/ReactiveObjC/RACCompoundDisposable.h
generated
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// RACCompoundDisposable.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 11/30/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACDisposable.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 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:(nullable 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:(nullable 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:(nullable RACDisposable *)disposable;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
250
Pods/ReactiveObjC/ReactiveObjC/RACCompoundDisposable.m
generated
Normal file
250
Pods/ReactiveObjC/ReactiveObjC/RACCompoundDisposable.m
generated
Normal file
@@ -0,0 +1,250 @@
|
||||
//
|
||||
// RACCompoundDisposable.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 11/30/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACCompoundDisposable.h"
|
||||
#import "RACCompoundDisposableProvider.h"
|
||||
#import <pthread/pthread.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.
|
||||
pthread_mutex_t _mutex;
|
||||
|
||||
#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 _mutex is held.
|
||||
RACDisposable *_inlineDisposables[RACCompoundDisposableInlineCount];
|
||||
#endif
|
||||
|
||||
// Contains the receiver's disposables.
|
||||
//
|
||||
// This array should only be manipulated while _mutex 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 _mutex is held.
|
||||
BOOL _disposed;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RACCompoundDisposable
|
||||
|
||||
#pragma mark Properties
|
||||
|
||||
- (BOOL)isDisposed {
|
||||
pthread_mutex_lock(&_mutex);
|
||||
BOOL disposed = _disposed;
|
||||
pthread_mutex_unlock(&_mutex);
|
||||
|
||||
return disposed;
|
||||
}
|
||||
|
||||
#pragma mark Lifecycle
|
||||
|
||||
+ (instancetype)compoundDisposable {
|
||||
return [[self alloc] initWithDisposables:nil];
|
||||
}
|
||||
|
||||
+ (instancetype)compoundDisposableWithDisposables:(NSArray *)disposables {
|
||||
return [[self alloc] initWithDisposables:disposables];
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
|
||||
const int result __attribute__((unused)) = pthread_mutex_init(&_mutex, NULL);
|
||||
NSCAssert(0 == result, @"Failed to initialize mutex with error %d.", result);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithDisposables:(NSArray *)otherDisposables {
|
||||
self = [self init];
|
||||
|
||||
#if RACCompoundDisposableInlineCount
|
||||
[otherDisposables enumerateObjectsUsingBlock:^(RACDisposable *disposable, NSUInteger index, BOOL *stop) {
|
||||
self->_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;
|
||||
}
|
||||
|
||||
- (instancetype)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;
|
||||
}
|
||||
|
||||
const int result __attribute__((unused)) = pthread_mutex_destroy(&_mutex);
|
||||
NSCAssert(0 == result, @"Failed to destroy mutex with error %d.", result);
|
||||
}
|
||||
|
||||
#pragma mark Addition and Removal
|
||||
|
||||
- (void)addDisposable:(RACDisposable *)disposable {
|
||||
NSCParameterAssert(disposable != self);
|
||||
if (disposable == nil || disposable.disposed) return;
|
||||
|
||||
BOOL shouldDispose = NO;
|
||||
|
||||
pthread_mutex_lock(&_mutex);
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&_mutex);
|
||||
|
||||
// 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;
|
||||
|
||||
pthread_mutex_lock(&_mutex);
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&_mutex);
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
pthread_mutex_lock(&_mutex);
|
||||
{
|
||||
_disposed = YES;
|
||||
|
||||
#if RACCompoundDisposableInlineCount
|
||||
for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
|
||||
inlineCopy[i] = _inlineDisposables[i];
|
||||
_inlineDisposables[i] = nil;
|
||||
}
|
||||
#endif
|
||||
|
||||
remainingDisposables = _disposables;
|
||||
_disposables = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&_mutex);
|
||||
|
||||
#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
|
||||
4
Pods/ReactiveObjC/ReactiveObjC/RACCompoundDisposableProvider.d
generated
Normal file
4
Pods/ReactiveObjC/ReactiveObjC/RACCompoundDisposableProvider.d
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
provider RACCompoundDisposable {
|
||||
probe added(char *compoundDisposable, char *disposable, long newTotal);
|
||||
probe removed(char *compoundDisposable, char *disposable, long newTotal);
|
||||
};
|
||||
32
Pods/ReactiveObjC/ReactiveObjC/RACDelegateProxy.h
generated
Normal file
32
Pods/ReactiveObjC/ReactiveObjC/RACDelegateProxy.h
generated
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// RACDelegateProxy.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Cody Krieger on 5/19/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACSignal<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// 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
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
75
Pods/ReactiveObjC/ReactiveObjC/RACDelegateProxy.m
generated
Normal file
75
Pods/ReactiveObjC/ReactiveObjC/RACDelegateProxy.m
generated
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// RACDelegateProxy.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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];
|
||||
|
||||
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
|
||||
39
Pods/ReactiveObjC/ReactiveObjC/RACDisposable.h
generated
Normal file
39
Pods/ReactiveObjC/ReactiveObjC/RACDisposable.h
generated
Normal file
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// RACDisposable.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 3/16/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class RACScopedDisposable;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 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
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
90
Pods/ReactiveObjC/ReactiveObjC/RACDisposable.m
generated
Normal file
90
Pods/ReactiveObjC/ReactiveObjC/RACDisposable.m
generated
Normal file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// RACDisposable.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
|
||||
_disposeBlock = (__bridge void *)self;
|
||||
OSMemoryBarrier();
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBlock:(void (^)(void))block {
|
||||
NSCParameterAssert(block != nil);
|
||||
|
||||
self = [super init];
|
||||
|
||||
_disposeBlock = (void *)CFBridgingRetain([block copy]);
|
||||
OSMemoryBarrier();
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)disposableWithBlock:(void (^)(void))block {
|
||||
return [(RACDisposable *)[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
|
||||
20
Pods/ReactiveObjC/ReactiveObjC/RACDynamicSequence.h
generated
Normal file
20
Pods/ReactiveObjC/ReactiveObjC/RACDynamicSequence.h
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// RACDynamicSequence.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
197
Pods/ReactiveObjC/ReactiveObjC/RACDynamicSequence.m
generated
Normal file
197
Pods/ReactiveObjC/ReactiveObjC/RACDynamicSequence.m
generated
Normal file
@@ -0,0 +1,197 @@
|
||||
//
|
||||
// RACDynamicSequence.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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<id> *(^)(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
|
||||
17
Pods/ReactiveObjC/ReactiveObjC/RACDynamicSignal.h
generated
Normal file
17
Pods/ReactiveObjC/ReactiveObjC/RACDynamicSignal.h
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// RACDynamicSignal.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
54
Pods/ReactiveObjC/ReactiveObjC/RACDynamicSignal.m
generated
Normal file
54
Pods/ReactiveObjC/ReactiveObjC/RACDynamicSignal.m
generated
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// RACDynamicSignal.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Justin Spahr-Summers on 2013-10-10.
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACDynamicSignal.h"
|
||||
#import <ReactiveObjC/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
|
||||
14
Pods/ReactiveObjC/ReactiveObjC/RACEagerSequence.h
generated
Normal file
14
Pods/ReactiveObjC/ReactiveObjC/RACEagerSequence.h
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// RACEagerSequence.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
66
Pods/ReactiveObjC/ReactiveObjC/RACEagerSequence.m
generated
Normal file
66
Pods/ReactiveObjC/ReactiveObjC/RACEagerSequence.m
generated
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// RACEagerSequence.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
|
||||
+ (RACSequence *)return:(id)value {
|
||||
return [[self sequenceWithArray:@[ value ] offset:0] setNameWithFormat:@"+return: %@", RACDescription(value)];
|
||||
}
|
||||
|
||||
- (RACSequence *)bind:(RACSequenceBindBlock (^)(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];
|
||||
}
|
||||
|
||||
- (RACSequence *)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
|
||||
16
Pods/ReactiveObjC/ReactiveObjC/RACEmptySequence.h
generated
Normal file
16
Pods/ReactiveObjC/ReactiveObjC/RACEmptySequence.h
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// RACEmptySequence.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
|
||||
+ (RACEmptySequence *)empty;
|
||||
|
||||
@end
|
||||
71
Pods/ReactiveObjC/ReactiveObjC/RACEmptySequence.m
generated
Normal file
71
Pods/ReactiveObjC/ReactiveObjC/RACEmptySequence.m
generated
Normal file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// RACEmptySequence.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
|
||||
- (instancetype)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
|
||||
17
Pods/ReactiveObjC/ReactiveObjC/RACEmptySignal.h
generated
Normal file
17
Pods/ReactiveObjC/ReactiveObjC/RACEmptySignal.h
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// RACEmptySignal.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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<__covariant ValueType> : RACSignal<ValueType>
|
||||
|
||||
+ (RACSignal<ValueType> *)empty;
|
||||
|
||||
@end
|
||||
62
Pods/ReactiveObjC/ReactiveObjC/RACEmptySignal.m
generated
Normal file
62
Pods/ReactiveObjC/ReactiveObjC/RACEmptySignal.m
generated
Normal file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// RACEmptySignal.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
17
Pods/ReactiveObjC/ReactiveObjC/RACErrorSignal.h
generated
Normal file
17
Pods/ReactiveObjC/ReactiveObjC/RACErrorSignal.h
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// RACErrorSignal.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Justin Spahr-Summers on 2013-10-10.
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACSignal.h"
|
||||
|
||||
// A private `RACSignal` subclass that synchronously sends an error to any
|
||||
// subscriber.
|
||||
@interface RACErrorSignal : RACSignal
|
||||
|
||||
+ (RACSignal *)error:(NSError *)error;
|
||||
|
||||
@end
|
||||
47
Pods/ReactiveObjC/ReactiveObjC/RACErrorSignal.m
generated
Normal file
47
Pods/ReactiveObjC/ReactiveObjC/RACErrorSignal.m
generated
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// RACErrorSignal.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
55
Pods/ReactiveObjC/ReactiveObjC/RACEvent.h
generated
Normal file
55
Pods/ReactiveObjC/ReactiveObjC/RACEvent.h
generated
Normal file
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// RACEvent.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Justin Spahr-Summers on 2013-01-07.
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// Describes the type of a RACEvent.
|
||||
///
|
||||
/// RACEventTypeCompleted - A `completed` event.
|
||||
/// RACEventTypeError - An `error` event.
|
||||
/// RACEventTypeNext - A `next` event.
|
||||
typedef NS_ENUM(NSUInteger, RACEventType) {
|
||||
RACEventTypeCompleted,
|
||||
RACEventTypeError,
|
||||
RACEventTypeNext
|
||||
};
|
||||
|
||||
/// Represents an event sent by a RACSignal.
|
||||
///
|
||||
/// This corresponds to the `Notification` class in Rx.
|
||||
@interface RACEvent<__covariant ValueType> : NSObject <NSCopying>
|
||||
|
||||
/// Returns a singleton RACEvent representing the `completed` event.
|
||||
+ (RACEvent<ValueType> *)completedEvent;
|
||||
|
||||
/// Returns a new event of type RACEventTypeError, containing the given error.
|
||||
+ (RACEvent<ValueType> *)eventWithError:(nullable NSError *)error;
|
||||
|
||||
/// Returns a new event of type RACEventTypeNext, containing the given value.
|
||||
+ (RACEvent<ValueType> *)eventWithValue:(nullable ValueType)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, nullable) NSError *error;
|
||||
|
||||
/// The value associated with an event of type RACEventTypeNext. This will be
|
||||
/// nil for all other event types.
|
||||
@property (nonatomic, strong, readonly, nullable) ValueType value;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
112
Pods/ReactiveObjC/ReactiveObjC/RACEvent.m
generated
Normal file
112
Pods/ReactiveObjC/ReactiveObjC/RACEvent.m
generated
Normal file
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// RACEvent.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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.
|
||||
- (instancetype)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];
|
||||
}
|
||||
|
||||
- (instancetype)initWithEventType:(RACEventType)type object:(id)object {
|
||||
self = [super init];
|
||||
|
||||
_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
|
||||
23
Pods/ReactiveObjC/ReactiveObjC/RACGroupedSignal.h
generated
Normal file
23
Pods/ReactiveObjC/ReactiveObjC/RACGroupedSignal.h
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// RACGroupedSignal.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 5/2/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACSubject.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 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
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
25
Pods/ReactiveObjC/ReactiveObjC/RACGroupedSignal.m
generated
Normal file
25
Pods/ReactiveObjC/ReactiveObjC/RACGroupedSignal.m
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// RACGroupedSignal.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
14
Pods/ReactiveObjC/ReactiveObjC/RACImmediateScheduler.h
generated
Normal file
14
Pods/ReactiveObjC/ReactiveObjC/RACImmediateScheduler.h
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// RACImmediateScheduler.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
54
Pods/ReactiveObjC/ReactiveObjC/RACImmediateScheduler.m
generated
Normal file
54
Pods/ReactiveObjC/ReactiveObjC/RACImmediateScheduler.m
generated
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// RACImmediateScheduler.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
|
||||
- (instancetype)init {
|
||||
return [super initWithName:@"org.reactivecocoa.ReactiveObjC.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
|
||||
16
Pods/ReactiveObjC/ReactiveObjC/RACIndexSetSequence.h
generated
Normal file
16
Pods/ReactiveObjC/ReactiveObjC/RACIndexSetSequence.h
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// RACIndexSetSequence.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
|
||||
+ (RACSequence *)sequenceWithIndexSet:(NSIndexSet *)indexSet;
|
||||
|
||||
@end
|
||||
111
Pods/ReactiveObjC/ReactiveObjC/RACIndexSetSequence.m
generated
Normal file
111
Pods/ReactiveObjC/ReactiveObjC/RACIndexSetSequence.m
generated
Normal file
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// RACIndexSetSequence.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
|
||||
+ (RACSequence *)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
|
||||
107
Pods/ReactiveObjC/ReactiveObjC/RACKVOChannel.h
generated
Normal file
107
Pods/ReactiveObjC/ReactiveObjC/RACKVOChannel.h
generated
Normal file
@@ -0,0 +1,107 @@
|
||||
//
|
||||
// RACKVOChannel.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Uri Baghin on 27/12/2012.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACChannel.h"
|
||||
#import <ReactiveObjC/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)]
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// A RACChannel that observes a KVO-compliant key path for changes.
|
||||
@interface RACKVOChannel<ValueType> : RACChannel<ValueType>
|
||||
|
||||
/// 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`).
|
||||
#if OS_OBJECT_HAVE_OBJC_SUPPORT
|
||||
- (instancetype)initWithTarget:(__weak NSObject *)target keyPath:(NSString *)keyPath nilValue:(nullable ValueType)nilValue;
|
||||
#else
|
||||
// Swift builds with OS_OBJECT_HAVE_OBJC_SUPPORT=0 for Playgrounds and LLDB :(
|
||||
- (instancetype)initWithTarget:(NSObject *)target keyPath:(NSString *)keyPath nilValue:(nullable ValueType)nilValue;
|
||||
#endif
|
||||
|
||||
- (instancetype)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
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
207
Pods/ReactiveObjC/ReactiveObjC/RACKVOChannel.m
generated
Normal file
207
Pods/ReactiveObjC/ReactiveObjC/RACKVOChannel.m
generated
Normal file
@@ -0,0 +1,207 @@
|
||||
//
|
||||
// RACKVOChannel.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Uri Baghin on 27/12/2012.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACKVOChannel.h"
|
||||
#import <ReactiveObjC/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
|
||||
|
||||
- (instancetype)initWithTarget:(__weak NSObject *)target keyPath:(NSString *)keyPath nilValue:(id)nilValue {
|
||||
NSCParameterAssert(keyPath.rac_keyPathComponents.count > 0);
|
||||
|
||||
NSObject *strongTarget = target;
|
||||
|
||||
self = [super init];
|
||||
|
||||
_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
|
||||
34
Pods/ReactiveObjC/ReactiveObjC/RACKVOProxy.h
generated
Normal file
34
Pods/ReactiveObjC/ReactiveObjC/RACKVOProxy.h
generated
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// RACKVOProxy.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
69
Pods/ReactiveObjC/ReactiveObjC/RACKVOProxy.m
generated
Normal file
69
Pods/ReactiveObjC/ReactiveObjC/RACKVOProxy.m
generated
Normal file
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// RACKVOProxy.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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];
|
||||
|
||||
_queue = dispatch_queue_create("org.reactivecocoa.ReactiveObjC.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
|
||||
31
Pods/ReactiveObjC/ReactiveObjC/RACKVOTrampoline.h
generated
Normal file
31
Pods/ReactiveObjC/ReactiveObjC/RACKVOTrampoline.h
generated
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// RACKVOTrampoline.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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.
|
||||
- (instancetype)initWithTarget:(__weak NSObject *)target observer:(__weak NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block;
|
||||
|
||||
@end
|
||||
109
Pods/ReactiveObjC/ReactiveObjC/RACKVOTrampoline.m
generated
Normal file
109
Pods/ReactiveObjC/ReactiveObjC/RACKVOTrampoline.m
generated
Normal file
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// RACKVOTrampoline.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
|
||||
- (instancetype)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];
|
||||
|
||||
_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
|
||||
17
Pods/ReactiveObjC/ReactiveObjC/RACMulticastConnection+Private.h
generated
Normal file
17
Pods/ReactiveObjC/ReactiveObjC/RACMulticastConnection+Private.h
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// RACMulticastConnection+Private.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 4/11/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACMulticastConnection.h"
|
||||
|
||||
@class RACSubject;
|
||||
|
||||
@interface RACMulticastConnection<__covariant ValueType> ()
|
||||
|
||||
- (instancetype)initWithSourceSignal:(RACSignal<ValueType> *)source subject:(RACSubject *)subject;
|
||||
|
||||
@end
|
||||
53
Pods/ReactiveObjC/ReactiveObjC/RACMulticastConnection.h
generated
Normal file
53
Pods/ReactiveObjC/ReactiveObjC/RACMulticastConnection.h
generated
Normal file
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// RACMulticastConnection.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 4/11/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "RACAnnotations.h"
|
||||
|
||||
@class RACDisposable;
|
||||
@class RACSignal<__covariant ValueType>;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 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<__covariant ValueType> : NSObject
|
||||
|
||||
/// The multicasted signal.
|
||||
@property (nonatomic, strong, readonly) RACSignal<ValueType> *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<ValueType> *)autoconnect RAC_WARN_UNUSED_RESULT;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
84
Pods/ReactiveObjC/ReactiveObjC/RACMulticastConnection.m
generated
Normal file
84
Pods/ReactiveObjC/ReactiveObjC/RACMulticastConnection.m
generated
Normal file
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// RACMulticastConnection.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
|
||||
- (instancetype)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject {
|
||||
NSCParameterAssert(source != nil);
|
||||
NSCParameterAssert(subject != nil);
|
||||
|
||||
self = [super init];
|
||||
|
||||
_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
|
||||
29
Pods/ReactiveObjC/ReactiveObjC/RACPassthroughSubscriber.h
generated
Normal file
29
Pods/ReactiveObjC/ReactiveObjC/RACPassthroughSubscriber.h
generated
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// RACPassthroughSubscriber.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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<__covariant ValueType>;
|
||||
|
||||
// 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
|
||||
106
Pods/ReactiveObjC/ReactiveObjC/RACPassthroughSubscriber.m
generated
Normal file
106
Pods/ReactiveObjC/ReactiveObjC/RACPassthroughSubscriber.m
generated
Normal file
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// RACPassthroughSubscriber.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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"
|
||||
|
||||
#if !defined(DTRACE_PROBES_DISABLED) || !DTRACE_PROBES_DISABLED
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@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];
|
||||
|
||||
_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
|
||||
44
Pods/ReactiveObjC/ReactiveObjC/RACQueueScheduler+Subclass.h
generated
Normal file
44
Pods/ReactiveObjC/ReactiveObjC/RACQueueScheduler+Subclass.h
generated
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// RACQueueScheduler+Subclass.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 6/6/13.
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACQueueScheduler.h"
|
||||
#import "RACScheduler+Subclass.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 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_USE_OBJC
|
||||
@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.
|
||||
- (instancetype)initWithName:(nullable 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
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
22
Pods/ReactiveObjC/ReactiveObjC/RACQueueScheduler.h
generated
Normal file
22
Pods/ReactiveObjC/ReactiveObjC/RACQueueScheduler.h
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// RACQueueScheduler.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 11/30/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACScheduler.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 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
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
106
Pods/ReactiveObjC/ReactiveObjC/RACQueueScheduler.m
generated
Normal file
106
Pods/ReactiveObjC/ReactiveObjC/RACQueueScheduler.m
generated
Normal file
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// RACQueueScheduler.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name queue:(dispatch_queue_t)queue {
|
||||
NSCParameterAssert(queue != NULL);
|
||||
|
||||
self = [super initWithName:name];
|
||||
|
||||
_queue = queue;
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
dispatch_retain(_queue);
|
||||
#endif
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
|
||||
- (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
|
||||
26
Pods/ReactiveObjC/ReactiveObjC/RACReplaySubject.h
generated
Normal file
26
Pods/ReactiveObjC/ReactiveObjC/RACReplaySubject.h
generated
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// RACReplaySubject.h
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Josh Abernathy on 3/14/12.
|
||||
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACSubject.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
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<ValueType> : RACSubject<ValueType>
|
||||
|
||||
/// Creates a new replay subject with the given capacity. A capacity of
|
||||
/// RACReplaySubjectUnlimitedCapacity means values are never trimmed.
|
||||
+ (instancetype)replaySubjectWithCapacity:(NSUInteger)capacity;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
112
Pods/ReactiveObjC/ReactiveObjC/RACReplaySubject.m
generated
Normal file
112
Pods/ReactiveObjC/ReactiveObjC/RACReplaySubject.m
generated
Normal file
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// RACReplaySubject.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// 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];
|
||||
|
||||
_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];
|
||||
|
||||
if (self.capacity != RACReplaySubjectUnlimitedCapacity && self.valuesReceived.count > self.capacity) {
|
||||
[self.valuesReceived removeObjectsInRange:NSMakeRange(0, self.valuesReceived.count - self.capacity)];
|
||||
}
|
||||
|
||||
[super sendNext:value];
|
||||
}
|
||||
}
|
||||
|
||||
- (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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user