Coder Social home page Coder Social logo

reactivecocoa / reactivecocoa Goto Github PK

View Code? Open in Web Editor NEW
19.9K 19.9K 3.5K 16.69 MB

Cocoa framework and Obj-C dynamism bindings for ReactiveSwift.

License: MIT License

Objective-C 0.55% Swift 97.96% Shell 0.81% Ruby 0.68%
reactivecocoa reactiveswift swift

reactivecocoa's Introduction

ReactiveCocoa

Reactive extensions to Cocoa frameworks, built on top of ReactiveSwift.

Join the ReactiveSwift Slack community.


Carthage compatible CocoaPods compatible SwiftPM compatible GitHub release Swift 5.1 platforms

⚠️ Looking for the Objective-C API?

🎉 Migrating from RAC 4.x?

🚄 Release Roadmap

What is 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.

What is ReactiveCocoa?

ReactiveCocoa wraps various aspects of Cocoa frameworks with the declarative ReactiveSwift primitives.

  1. UI Bindings

    UI components expose BindingTargets, 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.

  2. Controls and User Interactions

    Interactive UI components expose Signals for control events and updates in the control value upon user interactions.

    A selected set of controls provide a convenience, expressive binding API for Actions.

    // 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)
  3. 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)
  4. Expressive, Safe Key Path Observation

    Establish key-value observations in the form of SignalProducers and DynamicPropertys, 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.

Getting started

ReactiveCocoa supports macOS 10.9+, iOS 8.0+, watchOS 2.0+, and tvOS 9.0+.

Carthage

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 and ReactiveSwift.framework to the "Linked Frameworks and Libraries" section of your target, and have included them in your Carthage framework copying build phase.

CocoaPods

If you use CocoaPods to manage your dependencies, simply add ReactiveCocoa to your Podfile:

pod 'ReactiveCocoa', '~> 10.1'

Swift Package Manager

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")

Git submodule

  1. Add the ReactiveCocoa repository as a submodule of your application’s repository.
  2. Run git submodule update --init --recursive from within the ReactiveCocoa folder.
  3. Drag and drop ReactiveCocoa.xcodeproj and Carthage/Checkouts/ReactiveSwift/ReactiveSwift.xcodeproj into your application’s Xcode project or workspace.
  4. On the “General” tab of your application target’s settings, add ReactiveCocoa.framework and ReactiveSwift.framework to the “Embedded Binaries” section.
  5. If your application target does not contain Swift code at all, you should also set the EMBEDDED_CONTENT_CONTAINS_SWIFT build setting to “Yes”.

Have a question?

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.

Release Roadmap

Current Stable Release:
GitHub release

In Development

Plan of Record

ABI stability release

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

Contributors

335g avatar adlai-holler avatar alanjrogers avatar almassapargali avatar andersio avatar bigboybad avatar brow avatar ikesyo avatar iv-mexx avatar javisoto avatar jlawton avatar jonsterling avatar joshaber avatar joshvera avatar jspahrsummers avatar kastiglione avatar kkazuo avatar larryonoff avatar lawrencelomax avatar lbrndnr avatar liscio avatar mattjgalloway avatar mdiep avatar nachosoto avatar neilpa avatar robrix avatar ruiaaperes avatar sharplet avatar thenikso avatar tomj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reactivecocoa'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 by loadCachedMessages 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:, and rac_any: duplicate functionality provided in Mantle, and can also be expressed using <RACStream> (through NSArray.rac_sequence).

Combine RACTuple with RACSequence

If RACSequence supported indexing and had first, second, etc. convenience methods like RACTuple, 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 with

2012-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: within combineLatest: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's do 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 return nextSequence() 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.

RACSubject => RACMutableSignal?

When we talked about renaming RACSubscribable, @jspahrsummers also brought up that RACSubject, 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 like NSMutableArray vs. NSArray.

The downside is that RACReplayMutableSignal / RACMutableReplaySignal is a pretty ridiculous name.

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 the rac_sequence functionality provided on the built-in collection classes. Arguably, the laziness of rac_sequence also leads to a better API.

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:

  1. Create a new git repo git init
  2. Add ReactiveCocoa as a submodule git submodule add git://github.com/github/ReactiveCocoa.git Dependencies/ReactiveCocoa
  3. Pull in ReactiveCocoa's dependencies with git submodule update --init --recursive
  4. Create a new Xcode iPhone project in the repo.
  5. Drag the ReactiveCocoaFramework/ReactiveCocoa.xcodeproj project file into the new project's project navigator.
  6. Add the ReactiveCocoa-iOS static library target as a dependency of the iPhone project's application target under Target Dependencies.
  7. Link against the libReactiveCocoa-iOS.a library by adding it under the iPhone project's application target Link Binary With Libraries box.
  8. 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.

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" and take:1 valuesTaken goes past count.
This makes me think to the Materialize as discussed in #90

To 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 move asMaybe after switch the replay subject builded by the RACAble 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 over RACReplaySubject. 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 over EXTNil at one point, but I don't remember/understand the motivation for it.

EXTNil interoperates with code that expects nil or NSNull, so is more "backwards compatible" in a certain sense. This same property also makes it nicer for things like RACBlockTrampoline, because EXTNil == 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 to sendError:.
  • RACUnit.defaultUnit is equivalent to sendCompleted. Most of the framework's current uses of RACUnit could easily be replaced with something else, like nil or a dummy value.
  • Anything else is equivalent to sendNext:.

This would provide a couple huge advantages:

  • Subscribables could have useful head and tail 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?

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.

+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.

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's nil.

RACAbleSelf syntax changed?

I'm having issues with RACAbleSelf and RACAbleSelfWithStart, whereby my class has a public NSURL property urlToLoad:

@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 error

An 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 the NSUserDefaultsController's values 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 it id → 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 photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.