Reactive extensions to Cocoa frameworks, built on top of ReactiveSwift.
ReactiveSwift offers composable, declarative and flexible primitives that are built around the grand concept of streams of values over time. These primitives can be used to uniformly represent common Cocoa and generic programming patterns that are fundamentally an act of observation.
For more information about the core primitives, see ReactiveSwift.
ReactiveCocoa wraps various aspects of Cocoa frameworks with the declarative ReactiveSwift primitives.
-
UI Bindings
UI components expose
BindingTarget
s, which accept bindings from any kind of streams of values via the<~
operator.// Bind the `name` property of `person` to the text value of an `UILabel`. nameLabel.reactive.text <~ person.name
Note: You'll need to import ReactiveSwift as well to make use of the
<~
operator.Controls and User Interactions
Interactive UI components expose
Signal
s for control events and updates in the control value upon user interactions.A selected set of controls provide a convenience, expressive binding API for
Action
s.// Update `allowsCookies` whenever the toggle is flipped. preferences.allowsCookies <~ toggle.reactive.isOnValues // Compute live character counts from the continuous stream of user initiated // changes in the text. textField.reactive.continuousTextValues.map { $0.characters.count } // Trigger `commit` whenever the button is pressed. button.reactive.pressed = CocoaAction(viewModel.commit)
Declarative Objective-C Dynamism
Create signals that are sourced by intercepting Objective-C objects, e.g. method call interception and object deinitialization.
// Notify after every time `viewWillAppear(_:)` is called. let appearing = viewController.reactive.trigger(for: #selector(UIViewController.viewWillAppear(_:))) // Observe the lifetime of `object`. object.reactive.lifetime.ended.observeCompleted(doCleanup)
Expressive, Safe Key Path Observation
Establish key-value observations in the form of
SignalProducer
s andDynamicProperty
s, and enjoy the inherited composability.// A producer that sends the current value of `keyPath`, followed by // subsequent changes. // // Terminate the KVO observation if the lifetime of `self` ends. let producer = object.reactive.producer(forKeyPath: #keyPath(key)) .take(during: self.reactive.lifetime) // A parameterized property that represents the supplied key path of the // wrapped object. It holds a weak reference to the wrapped object. let property = DynamicProperty<String>(object: person, keyPath: #keyPath(person.name))
But there are still more to be discovered and introduced. Read our in-code documentations and release notes to find out more.
ReactiveCocoa supports macOS 10.9+, iOS 8.0+, watchOS 2.0+, and tvOS 9.0+.
If you use Carthage to manage your dependencies, simply add ReactiveCocoa to your
Cartfile
:github "ReactiveCocoa/ReactiveCocoa" ~> 10.1
If you use Carthage to build your dependencies, make sure you have added
ReactiveCocoa.framework
andReactiveSwift.framework
to the "Linked Frameworks and Libraries" section of your target, and have included them in your Carthage framework copying build phase.If you use CocoaPods to manage your dependencies, simply add ReactiveCocoa to your
Podfile
:pod 'ReactiveCocoa', '~> 10.1'
If you use Swift Package Manager, simply add ReactiveCocoa as a dependency of your package in
Package.swift
:.package(url: "https://github.com/ReactiveCocoa/ReactiveCocoa.git", branch: "master")
- Add the ReactiveCocoa repository as a submodule of your application’s repository.
- Run
git submodule update --init --recursive
from within the ReactiveCocoa folder. - Drag and drop
ReactiveCocoa.xcodeproj
andCarthage/Checkouts/ReactiveSwift/ReactiveSwift.xcodeproj
into your application’s Xcode project or workspace. - On the “General” tab of your application target’s settings, add
ReactiveCocoa.framework
andReactiveSwift.framework
to the “Embedded Binaries” section. - If your application target does not contain Swift code at all, you should also
set the
EMBEDDED_CONTENT_CONTAINS_SWIFT
build setting to “Yes”.
If you need any help, please visit our GitHub issues or Stack Overflow. Feel free to file an issue if you do not manage to find any solution from the archives.
ReactiveCocoa is expected to declare library ABI stability when Swift rolls out resilience support in Swift 5. Until then, ReactiveCocoa will incrementally adopt new language features.
reactivecocoa's People
Forkers
jwang maheshbabu langford fabiopelosin jonchui kingofbrian smaky xmjw jparishy jonas8 jonsterling fblumenberg mpeltonen g-p-s adeasismont joechin pilky enthusiasticcode xiaonuogantan cvertex sephiria sam-splat unixcrh steveswing nickynick bvanderveen xxhp tezheng tonyarnold aral evadne scriptease develomentionalllc melisa71 nerdsrob glebd dseredinov hankbao patgdut samback machx sarahhodne andrask claudot mdiep mokerjoke danielctull-forks sg7 getmixxd js boredzo arnihermann cocoaplayground decklord joshvera sleepingking syndeca grzywack dmitrym0 kkazuo catufunwa kyleleneau hyacinth chendo ikesyo vdone215 chuntangwang erikprice brush51 andreasschacherbauer adriantofan apparentsoft kwarter mcpoet shouryuuken travisjeffery edison0951 yishuiliunian eric-shim javisoto webdevotion zenniepix lsavino heltons oier hpique marcammann kingyosteven mayankc janak-nirmal lnsoso ashfurrow yosit milancermak milker90 bawerd mackross codeguru85 xiebohui2013 jacksonhreactivecocoa's Issues
Linking issues?
Hey everyone,
I added ReactiveCocoa to my iOS project but Im having issues.
Attempting to test with a canonical example:
[RACAble(self.someProperty) subscribeNext:^(id x) { NSLog(@"%@",x); }];
I get the following:
2012-11-05 15:04:09.988 ASDF[77632:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ACRootViewController rac_subscribableForKeyPath:onObject:]: unrecognized selector sent to instance 0x817a2d0'
It looks to me like maybe my project isn't being linked against libReactiveCocoa-iOS.a properly? Can you guys suggest anything I could try?
-repeat doesn't stop after being disposed of
Noted in #93:
RACReplaySubject *subject = [RACReplaySubject subject]; [subject sendNext:@(1)]; [subject sendCompleted]; [[[subject repeat] take:1] subscribeNext:^(id x) { ... }];
Loops indefinitely.
Help with chaining async operations
Hello ladies and gentlemen,
I'm actually trying to implement the following example from the original blog post:
[[[[client loginUser] selectMany:^(id _) { return [client loadCachedMessages]; }] selectMany:^(id _) { return [client fetchMessages]; }] subscribeCompleted:^{ NSLog(@"Fetched all messages."); }]
Is there anywhere where this example is live? I'm having a tough time wrapping my mind around the different RAC objects. Are these functions defined as follows?
-(RACAsyncSubject*)loginUser -(loadCachedMessages*)loginUser
What I'm trying to achieve is a synchronous
loginUser
, followed byloadCachedMessages
and so on, in strict order.Thanks!
external/expecta submodule reference is broken
Hey guys, I can't do a clean checkout of RAC at the moment, as the expecta submodule appears to have come unhinged:
➜ ReactiveCocoa git submodule update --init --recursive Submodule path 'external/expecta': checked out '4cee0c92acc4fad2c908a49bee910d408ed43199' fatal: reference is not a tree: 58126ef0ee2d9dcc515bf1697ea4ac225bc57397 Unable to checkout '58126ef0ee2d9dcc515bf1697ea4ac225bc57397' in submodule path 'external/specta'
Is this something I can fix, or is it something that needs to be addressed in the repo?
Design guidelines and framework overview
I've been reading the Rx Design Guidelines, and it occurred to me that RAC doesn't have any equivalent documentation about how to use and extend it.
Normally the method and class documentation fulfills this, but there are some edge cases, #138 for example, that aren't covered.A general framework-level design guideline rather than a class-level explanation of specific behaviors would be clearer and easier to consult in these cases.
Not necessarily a 30+ page document like the Rx one, but a couple of notes about how the various parts fit together and what they do and don't guarantee regarding thread safety, concurrency, memory management etc.
Remove NSArray+RACExtensions
rac_select:
,rac_where:
, andrac_any:
duplicate functionality provided in Mantle, and can also be expressed using<RACStream>
(throughNSArray.rac_sequence
).Combine RACTuple with RACSequence
If
RACSequence
supported indexing and hadfirst
,second
, etc. convenience methods likeRACTuple
, we could effectively get rid of the latter and be left with much more flexible tuples.GHAPIDemo does not work
Hi there,
I checked out latest commit (c8a9a90), made a git submodule update --recursive --init and opened GHAPIDemo.
Typing into the username textfield gives every char in double, so typing a test shows tteesstt in the text field. Theres also a lot of output in the console, starting with2012-11-12 10:34:20.258 GHAPIDemo[10448:303] *** Enabling asynchronous backtraces 2012-11-12 10:34:20.409 GHAPIDemo[10448:303] Active requests: 0 2012-11-12 10:34:27.310 GHAPIDemo[10448:303] -[__NSCFConstantString objectAtIndex:]: unrecognized selector sent to instance 0x7fff7ab73930 2012-11-12 10:34:27.310 GHAPIDemo[10448:303] An uncaught exception was raised 2012-11-12 10:34:27.311 GHAPIDemo[10448:303] -[__NSCFConstantString objectAtIndex:]: unrecognized selector sent to instance 0x7fff7ab73930 2012-11-12 10:34:27.314 GHAPIDemo[10448:303] (
Any ideas?
whenAll: always yields [RACUnit defaultUnit]
The implementation of
whenAll:
:+ (RACSubscribable *)whenAll:(NSArray *)subscribables { return [self combineLatest:subscribables reduce:^(RACTuple *xs) { return [RACUnit defaultUnit]; }]; }
The call to
sendNext:
withincombineLatest:reduce:
[subscriber sendNext:reduceBlock([RACTuple tupleWithObjectsFromArray:orderedValues])];
The result is that subscribers to the subscribable returned by
whenAll:
always receive[RACUnit defaultUnit]
. Unless I'm missing something obvious.A possible fix would be:
+ (RACSubscribable *)whenAll:(NSArray *)subscribables { return [self combineLatest:subscribables reduce:^(RACTuple *xs) { return xs; }]; }
Thoughts?
Is ReactiveCocoa App Store friendly?
Has anyone had an app accepted in the iOS or Mac App Stores that uses ReactiveCocoa? I only ask because of it's use of method swizzling (seems to only be an issue when swizzling base methods on Apple's classes). Just looking for confirmation that at least one person has gotten approval before I start using this all over the place.
Add 'do' syntax for <RACStream>
It'd be totally possible to add a
do
syntax for the<RACStream>
monad, though it'd have to work a bit more like Clojure's domonad than Haskell'sdo
statement.But I'm wondering whether this would even be useful. How often would people be repeatedly binding in a way that this would be valuable?
The New Xcode Dun' Broke RAC!
A cough interesting preview of Xcode version-that-shall-not-be-named complains of RAC creating a block retain-cycle in
RACSequence
's bind: method. Upon returnnextSequence()
is captured strongly.Exception: -[RACSubject rac_performBlock:afterDelay:]: unrecognized selector
I've had success using the
RACAble
macro to create an observable/subscribable, but I keep getting the following exception some time after sending[RACSubject subject]
on iOS simulator:-[RACSubject rac_performBlock:afterDelay:]: unrecognized selector sent to instance 0x812d3f0
I'd assume I'd just be able to create a subject outright, but somewhere down the line something blows up. Not sure if I've got a something configured incorrectly in my project, or if I'm just using the API incorrectly.
Add method prefixes to NSObject+RACAppKitBindings
It's a little weird that RAC even provides this category, but I could see an argument for it.
In any case, it should be prefixed like every other category.
RACSubject => RACMutableSignal?
When we talked about renaming
RACSubscribable
, @jspahrsummers also brought up thatRACSubject
, too, is terrible but we struggled to come up with a not-awful alternative.But how about
RACMutableSignal
? They're mutable in the sense that users can change things about them after they're created, and they tend to be an implementation detail likeNSMutableArray
vs.NSArray
.The downside is that
RACReplayMutableSignal
/RACMutableReplaySignal
is a pretty ridiculous name.Instructions for using the library in a project in Xcode
I'm sort of a newbie to Xcode, but it's not obvious how to include this library in your project. Some other libraries I have been able to drag and drop into the Frameworks section. This one seems like you have to install it as a subproject. When I followed these instructions, however, I got errors: http://yannickloriot.com/2011/04/how-to-install-zxing-in-xcode-4/. Some instructions in the README.md would be great.
Thanks.Concurrent RACSchedulers can result in delivery race conditions
If two nexts, or a next and a completed, etc., get sent to a concurrent GCD or operation queue, they might be processed simultaneously. Most
<RACSignal>
and<RACStream>
methods are not written to accommodate this.<RACScheduler>
should serialize scheduled blocks, even when ultimately delivering to a concurrent queue. The deferredScheduler is also extremely dangerous, because it seems like we can't make the same guarantees there.Remove NSObject+RACFastEnumeration
The
rac_toSubscribable
method is pretty similar to therac_sequence
functionality provided on the built-in collection classes. Arguably, the laziness ofrac_sequence
also leads to a better API.Why is a separate version of EXTKeyPathCoding used for OS X?
This is causing problems with CocoaPods. CocoaPods/Specs#804
Submodule 'specta' not updating
Hi Guys,
I'm getting the following error when doing a fresh clone/submodule update:
Submodule path 'GHAPIDemo/external/AFNetworking': checked out '553e1d7e6b7373e79d14ad71a4e67e6513d1b09a' Submodule path 'external/expecta': checked out 'ed36c2a75c5b811837ee9dd0194066c8c53b6c76' Submodule path 'external/jrswizzle': checked out '315b2f01688f828eec262ca80be5d853c4d00d03' fatal: reference is not a tree: 948bfa115a0a422f1d254797e49bcc1468f03606 Submodule path 'external/xcconfigs': checked out '73f4162d29dcb6c8711248b43398f72d821bf917' Unable to checkout '948bfa115a0a422f1d254797e49bcc1468f03606' in submodule path 'external/specta'
Build failure for iOS projects in Xcode 4.5
Steps to reproduce:
- Create a new git repo
git init
- Add ReactiveCocoa as a submodule
git submodule add git://github.com/github/ReactiveCocoa.git Dependencies/ReactiveCocoa
- Pull in ReactiveCocoa's dependencies with
git submodule update --init --recursive
- Create a new Xcode iPhone project in the repo.
- Drag the
ReactiveCocoaFramework/ReactiveCocoa.xcodeproj
project file into the new project's project navigator. - Add the
ReactiveCocoa-iOS
static library target as a dependency of the iPhone project's application target under Target Dependencies. - Link against the
libReactiveCocoa-iOS.a
library by adding it under the iPhone project's application target Link Binary With Libraries box. - Build
Behavior:
Following build errors are emitted:
Build target ReactiveCocoa-iOS Check dependencies The file "Debug.xcconfig" couldn’t be opened because its path couldn't be resolved. It may be missing. The file "iOS-StaticLibrary.xcconfig" couldn’t be opened because its path couldn't be resolved. It may be missing. [ . . . snip RACCommand.m compiler invocation . . . ] /Users/bvanderveen/code/TestRAC/Dependencies/ReactiveCocoa/ReactiveCocoaFramework/ReactiveCocoa/RACCommand.m:47:12: error: __weak attribute cannot be specified on an automatic variable [-Werror] __weak id weakSelf = self; ^ 1 error generated.
Wanted: +zip:reduce:
I just ran into a situation where I needed this.
Like
+combineLatest:reduce:
except it should only reduce to a new value when it's received a new value from each subscribable since it was last reduced. Would also be useful for sequences.Add custom resource disposal to RACDisposable
Maybe through a public
-addDisposeBlock:
method onRACDisposable
.For instance, I would like to retain the GCD semaphore in firstOrDefault:success:error:, and have it be released only when the subscribable is completely torn down.
Replay subject with asMaybes and take
I'm having trouble with a scenario like this:
RACReplaySubject *subject = [RACReplaySubject subject]; [subject sendError:[[NSError alloc] init]]; [[[subject asMaybes] take:1] subscribeNext:^(id x) { // I loop 4evar } completed:^{ // I never complete }];
And this is because
asMaybes
actually is "asMaybesAndRepeatOnError
" andtake:1
valuesTaken goes past count.
This makes me think to the Materialize as discussed in #90To be more specific, I'm trying to make something like this (pseudocode):
RACAble(property) select:^id(id x) { return [[<a replay subject> asMaybe] take:1]; } switch subscribeNext:...
The goal is to keep the outer rac alive even if the inner one fails.
If I moveasMaybe
afterswitch
the replay subject builded by theRACAble
macro, immediately fires the subscribable again, which is not desired.Wouldn't be this a use case for a subscribable that convert to maybes but completes upon error?
ReactiveCocoa.xcodeproj doesn't specify iOS target version
When trying to compile RACiOSDemo/RACiOSDemo.xcodeproj on a version of Xcode that doesn't target iOS 5.1 as the default (REDACTED, for example), the target iOS target for the demo is set to iOS 5.1, and it builds correctly, but the Framework is only built for the default version, so when the Demo runs, the Framework won't load because it has the wrong target.
This leads to immediate crash with runtime error:
dyld: lazy symbol binding failed: Symbol not found: _objc_setProperty_nonatomic_copy
And I figured I'd save someone else the trouble of figuring out what the Hell Xcode meant by that.
Remove RACAsyncSubject in favor of RACReplaySubject
It's not clear what advantage
RACAsyncSubject
offers overRACReplaySubject
. It seems like the latter has a strict superset of the former's behavior. It also seems like a safer default to replay the whole subscribable stream, rather than just the last thing sent.Replace RACTupleNil with EXTNil
I know that
RACTupleNil
was deliberately chosen overEXTNil
at one point, but I don't remember/understand the motivation for it.EXTNil
interoperates with code that expectsnil
orNSNull
, so is more "backwards compatible" in a certain sense. This same property also makes it nicer for things likeRACBlockTrampoline
, becauseEXTNil == nil
for most intents and purposes.add podspec file in git repo
This would easily allow us to consume ReactiveCocoa by adding the following code in our Podfile.
platform :ios pod "ReactiveCocoa", :git => 'https://github.com/github/ReactiveCocoa.git', :tag => 'v0.8.0'
Readme should include basic installation instructions
Installation on the Mac is rather straightforward, but on iOS it's a little bit more prone to error due to the additional linker flag needed. A section in the readme would be fantastic so people just getting started won't be frustrated with runtime errors. 🤘
Is NSObject(RACSubscribable) necessary?
I'm looking at the
NSObject(RACSubscribable)
category, and it would seem that all of its methods assert conformance to<RACSubscribable>
at runtime. Wouldn't this be better placed in the actual<RACSubscribable>
protocol? It seems like that would be the safer and more hygienic approach.Are there some use-cases that make the current approach necessary, or at least more optimal?
Unify next, error, and completed
I propose that we unify next, error, and completed into a single stream of values, so that error and completed are no longer "out of band" communications. In effect:
- An
NSError
value is equivalent tosendError:
. RACUnit.defaultUnit
is equivalent tosendCompleted
. Most of the framework's current uses ofRACUnit
could easily be replaced with something else, likenil
or a dummy value.- Anything else is equivalent to
sendNext:
.
This would provide a couple huge advantages:
- Subscribables could have useful
head
andtail
implementations that don't require any translation of the "error" or "completed" concepts. - Monadic bind could be applied to subscribables.
Among other things, this would facilitate interoperation with a concept of sequences like that described in #89.
Obviously, this would be a huge breaking change. However, subscriber-side APIs don't have to change that much –
subscribeNext:
,subscribeError:
,subscribeCompleted
, and most of the concrete methods in<RACSubscribable>
could, for convenience, distinguish values as above. Errors and completion could still terminate subscriptions without violating the above semantics.@xpaulbettsx @joshaber @jonsterling
switch fails assert if the receiver sends nil
If a subscribable sends nil, then switch fails it's assert:
NSAssert2([x conformsToProtocol:@protocol(RACSubscribable)], @"-switch requires that the source subscribable (%@) send subscribables. Instead we got: %@", self, x);
From a cursory glance at the code there doesn't seem to be any practical reason why nil wouldn't be a valid value.
Is requiring a non-nil subscribable a design choice or just something that never came up?CoreData objects dealloc.
Hi. I have a question about using RAC with CoreData, core data handle NSManagedObjects and dealloc swizzling not work as expected, so we have RACObjects leaked. Or I understand something wrong?
Lazy sequences
Sequences were originally suggested for Mantle in Mantle/Mantle#1, but after doing some work on a sequences branch there, I'm wondering if it makes more sense to provide this facility in ReactiveCocoa.
Conceptually, sequences and subscribables support many of the same kinds of operations (map, filter, concat, cons, etc.), and both represent streams of things.
There are a couple of major differences, though:
- Sequences can be lazy, and are inherently repeatable (i.e., not time-based). Subscribables are neither of those things.
- Subscribables model errors and completion, neither of which apply to a general-purpose sequence.
I think subscribables can be represented as sequences, but the opposite is not true – sending a sequence through a subscribable would require evaluating the entire thing.
@joshaber @xpaulbettsx @jonsterling Any thoughts on this?
Sending messages to a subscriber from different threads can result in delivery race conditions
As pointed out by @Coneko in #136, sending next, error, or completed to a
RACSubscriber
orRACSubject
from multiple threads might result in them being processed simultaneously, and most<RACSignal>
and<RACStream>
methods aren't built to handle it.Subjects and subscribers should serialize their messages onto a private queue so that stream methods don't have to worry about synchronization.
dispose defect.
I use RAC in my ios project, but I find that there is something problem about subscribe disposition.
that is,
in a view controller A, I write__unsafe_unretained id weakSelf = self; [[RACSubscribable combineLatest:[NSArray arrayWithObjects:RACAbleSelf(self.name), RACAbleSelf(self.desc), RACAbleSelf(self.avatar), RACAbleSelf(self.state), RACAbleSelf(self.city), nil] reduce:^id(RACTuple *xs) { return [NSNumber numberWithBool: ![[xs objectAtIndex:0] isEqualToString:user.nickName] || ![[xs objectAtIndex:1] isEqualToString:user.desc] || ![[xs objectAtIndex:2] isEqualToString:user.avatar] || ![[xs objectAtIndex:3] isEqualToString:user.birthState] || ![[xs objectAtIndex:4] isEqualToString:user.birthCity]]; }] subscribeNext:^(NSNumber *needUpdate) { PersonalSettingController *this = (PersonalSettingController *)weakSelf; if ([needUpdate boolValue]) { this.navigationItem.rightBarButtonItem = [UIBarButtonItem barButtonWithText:NSLocalizedString(@"保存", nil) target:this action:@selector(__saveUserInfo)]; }else { this.navigationItem.rightBarButtonItem = nil; } }];
and in controller A, it push controller B, and in Controller B, I write
__unsafe_unretained id weakSelf = self; [[[[RACSubscribable merge:[NSArray arrayWithObjects: RACAbleSelf(self.allowSearch), RACAbleSelf(self.name), RACAbleSelf(self.call), RACAbleSelf(self.isDefault), nil]] distinctUntilChanged] take:1] subscribeNext:^(id _) { FamilyMemberEditController *this = (FamilyMemberEditController *)weakSelf; this.navigationItem.rightBarButtonItem = [UIBarButtonItem barButtonWithText:NSLocalizedString(@"保存", nil) target:this action:@selector(__saveFamilyMember)]; }];
and the app always crash when Popup the controller B, I found that sizzling method call
dealloc
method for Controller A not for B, so it crash...I am a newbie for cocoa dev, I don't know how to debug further about this issue. any help about this?
Retain cycle from RACAbleSelf
Investigating some memory leaks in my application, I've found that whenever I use RACAbleSelf to subscribe for changes to a property on an object, that object is never freed. If I use a weak pointer inside the block, my object is freed, but about 60 KB of RAC infrastructure is retained somehow even though nothing is actively referencing it.
I've reproduced this with the following simple code:
// // main.m // #import <Foundation/Foundation.h> #import <ReactiveCocoa/ReactiveCocoa.h> @interface MyClass : NSObject @property (nonatomic) NSString *value1; @property (nonatomic) NSString *value2; @end @implementation MyClass @synthesize value1, value2; - (MyClass *)initWithWeak:(BOOL)isWeak { self = [super init]; if (self) { if (isWeak) { __weak __block id weakSelf = self; [[RACAbleSelf(value1) distinctUntilChanged] subscribeNext:^(id x) { NSLog(@"Using weak: subscribeNext called with x=%@", x); MyClass *strongSelf = weakSelf; strongSelf.value2 = strongSelf.value1; }]; } else { [[RACAbleSelf(value1) distinctUntilChanged] subscribeNext:^(id x) { NSLog(@"Not using weak: subscribeNext called with x=%@", x); self.value2 = self.value1; }]; } } return self; } @end int main(int argc, const char * argv[]) { @autoreleasepool { // Pause for a while to give time to connect with Instruments.app [NSThread sleepForTimeInterval:30]; MyClass* mc = [[MyClass alloc] initWithWeak:YES]; mc.value2 = @"foo"; mc.value1 = @"bar"; mc.value1 = @"bar"; // Repeat a value to ensure distinctUntilChanged works mc.value1 = @"baz"; NSLog(@"value1 = %@", mc.value1); NSLog(@"value2 = %@", mc.value2); mc = nil; // Should cause all allocated objects to be freed // Give time to mark another heap snapshot before exiting [NSThread sleepForTimeInterval:30]; } return 0; }
If I pass YES into the initializer for MyClass, its instance is freed, but it's not if I pass in NO instead. Either way, after running this, in Instruments.app I see about 60 KB of memory still allocated, including several RAC objects: 1 RACReplaySubject, 1 RACSubscribable, 1 RACSubscriber, and 2 RACDisposables.
My expectation is that when nothing references the object being subscribed to anymore, it and all of the objects created by RAC for the subscription would be cleaned up.
Re-evaluate cancelable signals
Cancelable signals were created out of need but I don't think they're the best way to address the problem.
They're conceptually weird. What does it mean to cancel a signal? Does it complete? Does it error?
We should re-think this.
More natural derived properties
I've found when doing reactive UI stuff, I end up using
-rac_deriveProperty:from:
a lot. It's awesome for the most part, but it doesn't read very naturally. What I really want to write and read is something like:self.titleLabel.textColor = someSubscribable;
I've come up with two different ways to write something more like that, both with tradeoffs, so I'd like to get some feedback.
Keyed subscripting:
rac(self.titleLabel.textColor) = someSubscribable;
That abuses keyed subscripting. It works for both object and non-object properties. The downside is that the class has to implement
-setObject:forKeyedSubscript:
. We can create a macro that does it for them, but it's an extra step users have to remember per-class.Proxy bounce
self.titleLabel.rac.textColor = (id) someSubscribable; // ooooh also: [self.createButton.rac setTitleColor:(id) someSubscribable forState:UIControlStateNormal];
This uses a proxy to bounce message sends through. It's kinda awesome because you can use it with methods that aren't just plain setters, which happens to be the case a fair amount in UIKit land. But this approach has two downsides: (1) you have to cast the subscribable, (2) it won't work with non-object properties.
So I'd be curious to see if anyone has any other ideas or feels strongly about either of those two options.
GHAPIDemo spinner showed with no end
I checked out the latest commit and tried to login with invalid account/password many times. The spinner hid the first time but remained unhidden since the second time. Looks like the subscription wasn't triggered.
Add instructions for submodules to the README
The README doesn't mention anywhere that submodules need to be cloned too. We should include information about recursive cloning or submodule initialization.
+combineLatest:reduce: and -flatten: have serialization issues.
Regardless of scheduler and subjects' serialization issues, methods that subscribe to multiple signals have serialization issues if the signals they subscribe to send from different threads.
+combineLatest:reduce:
and-flatten:
are affected for sure,+zip:reduce:
doesn't seem to have issues since it synchronizes all subscriptions.GHAPIDemo stack overflow upon two sucessive failed logins
Possibly an interaction between repeat and asMaybes operations when the subject has error set?
Please add semantic version tags
I’ve recently added ReactiveCocoa to the CocoaPods package manager repo.
CocoaPods is a tool for managing dependencies for OSX and iOS Xcode projects and provides a central repository for iOS/OSX libraries. This makes adding libraries to a project and updating them extremely easy and it will help users to resolve dependencies of the libraries they use.
However, ReactiveCocoa doesn't have any version tags. I’ve added the current HEAD as version 0.0.1, but a version tag will make dependency resolution much easier.
Semantic version tags (instead of plain commit hashes/revisions) allow for resolution of cross-dependencies.
Should KVO subscribables send their current value on subscribe?
I'm starting to think
+rac_subscribableFor:keyPath:onObject:
should send the current value of the key path when it is first called. It already replays the last value, but it seems even better to ensure a subscribable for a property will always have the current value, even if it'snil
.RACSubscribable constructors should return instancetype
Then they're not typed
id
, but still work with subclasses.RACAbleSelf syntax changed?
I'm having issues with
RACAbleSelf
andRACAbleSelfWithStart
, whereby my class has a publicNSURL
propertyurlToLoad
:@property(nonatomic, strong) NSURL *urlToLoad;
However when I call the following (as shown in all the samples):
[[RACAbleSelfWithStart(self.urlToLoad) distinctUntilChanged] subscribeNext:^(NSURL * newURL) {…}];
I get the following error:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<MyViewController 0x8bb33a0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key self.urlToLoad.'
I've tried changing it to just:
[[RACAbleSelfWithStart(urlToLoad) distinctUntilChanged] subscribeNext:^(NSURL * newURL) {…}];
This works, but my app complains about observation info being leaked whenever the view controller is deallocated. Breaking on
NSKVODeallocateBreak
doesn't yield anything useful, but I assume that the NSURL instance is somehow outliving the view controller. Here's the errorAn instance 0xf47de20 of class MyViewController was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info: <NSKeyValueObservationInfo 0x13e6a190> ( <NSKeyValueObservance 0x13e6a150: Observer: 0x13e6a0c0, Key path: urlToLoad, Options: <New: NO, Old: NO, Prior: NO> Context: 0x19e6a0, Property: 0x13e6a1d0> )
Am I missing something really obvious here? The project uses ARC.
Handle exceptions from RACSignal+Operations blocks
For blocks given to
RACSignal+Operations
methods that don't themselves return a signal, it's difficult – if not outright impossible – to indicate error cases. RAC could catch exceptions thrown by those blocks (since it invokes them directly) and translate those into errors.Issue when subscribing to NSUserDefaults on iOS
NB: This has been discussed to some extent on Twitter, but I think it's worth tracking as an issue.
While it's possible to subscribe to
NSUserDefaults
values using the following syntax:[[[NSUserDefaults standardUserDefaults] rac_subscribableForKeyPath:kDWKUserDefaultRequirePasscodeToUnlockKey onObject:self] subscribeNext:^(NSNumber *newValue) { ... }]];
I'm seeing the following crash report from users once the app is compiled for release and distributed:
https://gist.github.com/f7131bf0fa8a18ea884b
Officially,
NSUserDefaults
has no KVO support on either platform (on OS X and Cocoa proper, you can use theNSUserDefaultsController
'svalues
object for KVO support).I'm hoping this is some kind of simple deallocation issue, but I haven't found a way around this yet (nor a reproducible test case).
-[RACSubscribable(Operations) select:] conflicts w/ existing UIKit method
One of the consequences of Apple's unfortunate (and usually unnecessary) use of informal protocols is that under UIKit, the
NSObject(UIResponderStandardEditActions)
category pollutes nearly the entire object namespace with methods like-select:
.The result is that the compiler can't resolve the static type of a
-select:
message: is it(id → id) → RACSubscribable*
or is itid → void
? So we get a compiler warning.This can be solved by renaming RAC's
-select:
method; with my background, I'd of course suggest-map:
, but that would be somewhat non-conformant with the LINQ-inspired scheme you guys have going (as well as the Smalltalk heritage of Objective-C)...Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.