GithubHelp home page GithubHelp logo

parse-racextensions's Introduction

ReactiveCocoa for Parse

Parse is a service that allows developers to build server backed mobile apps, without needing to build a custom backend. Parse makes it easy to throw in a data backend, freeing you to focus on building the front end.

ReactiveCocoa, you've heard about it, now try it out. This library might be the perfect starting place to get started on that app you've been wanting to build, using Parse, while using ReactiveCocoa, that library you've been itching to try.

Currently supports iOS, but I just got started. OS X next.

Available Extensions

Pull requests welcome!

parse-racextensions's People

Contributors

jondwillis avatar kastiglione avatar mhupman 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

parse-racextensions's Issues

Thought about synchronous request!

Hi Dave,

Since the extension currently only support for asynchronous request, do you think it is a need to implement synchronous request?
Because I think some people might find it useful (not me just because I haven't face the situation that need synchronous request ๐Ÿ˜† )
Moreover, there is other part might be useful including PFImage & PFFile.

rac_findObjects doesn't react well to multiple subscribers

I would like to use Parse RACExtensions to have so that I'll know

PFQuery *query = ...;
self.initializationSignal = [query rac_findObjects];

When I subscribe two subscribers: one subscribeNext: and one subscribeCompleted:, then everything works fine.

If instead of subscribeCompleted: I use waitUntilCompleted:, or if I add one more subscriber (doesn't matter whether it's 'next' or 'completed'), then I get this error from Parse:

This query has an outstanding network connection. You have to wait until it's done.

Write tests

In most cases, I think stubbing/mocking unit tests will be sufficient, but in some cases I think integration tests are called for, for example -rac_getDataStream.

rac_deleteAll hangs indefinitely

I wanted to write unit tests against Parse and I came up with the following to purge a bunch of objects:

            [[PFObject rac_deleteAll:objects] waitUntilCompleted:nil];

This call hung forever with a total of two objects passed in. Why?

Ideal API for #7

Have you thought about what kind of interface would be appropriate for #7? Methods like getDataStreamInBackgroundWithBlock:progressBlock: seem to complicate things in that they have multiple types of values that could be sent across the signal - (int) percentDone and (NSInputStream *) result in this case.

Here are some potential implementations I can see:

  1. Send single values, require client to inspect object class - ๐Ÿ‘Ž
[[myPFFile rac_getDataStreamInBackgroundWithProgress] subscribeNext:^(NSObject *obj) {
    // Progress
    if ([obj isKindOfClass:[NSNumber class]]){}
    // Result
    else if ([obj isKindOfClass:[NSInputStream class]]){}
}];
  1. Send tuple values for progress-enabled signals, single values for data-only ones.
// With Progress
[[myPFFile rac_getDataStreamInBackgroundWithProgress] subscribeNext:^(RACTuple *tuple) {

    RACTupleUnpack(NSInputStream *stream, NSNumber *percentDone) = tuple;

    if (percentDone.intValue == 100) {}

    if (stream) {}
}];

// No Progress
[[myPFFile rac_getDataStreamInBackground] subscribeNext:^(NSInputStream *stream) {
}];
  1. Support an optional out parameter for the progress signal. Bizarre since only one of the signals (probably the returned one) would kick off the work when subscribed to. ๐Ÿ‘Ž
RACSignal *progressSignal;
[[myPFFile rac_getDataStreamInBackgroundWithProgress:&progressSignal] subscribeNext:^(NSInputStream *stream) {

}];

RAC(self, percentDone) = progressSignal;

  1. seems to be the best of these choices IMO. I took a look at how this was implemented before 78edef7, but I don't think that interface differed much from option 1) as far as consumers are concerned.

Thoughts or other suggested implementations?

Update PodSpec

Is there any reason that Parse-RACExtensions is dependent on Parse 1.3.0 now that Parse 1.4.0 is out?

Would it be possible to update this in the pod spec so that developers can also make use of the latest Parse APIs?

Thanks!

Write documentation

Using appledoc, write headers docs for the rac extensions. Additionally, give some love to the README and show some code examples.

  • Write header docs
  • Write README

-[PFObject saveEventually] does not necessarily complete at a sensible time; misleading API

Since I thought -saveEventually is supposed to return more or less synchronously, I thought that the RAC extension rac_saveEventually would also complete within reasonable time.

This is not the case. -rac_saveEventually is implemented with -saveEventually:, whose parameter is a callback function.

The callback function is, in fact, never called if the save has not succeeded yet. Thus, this signal never actually completes. This is very odd behaviour and I think we should remove -rac_saveEventually from the API for now, since it represents a signal that could take a long time to complete.

Need help to make the code look more coherent using Parse-RACExtensions

Hi guys,
I'm now able to use a bit of Parse-RACExtensions but cannot explain why I always feel so wrong with my current code even though it worked. Could you have a look at the following and give me advice how to make it look more simpler or is it just me who is trying to make things more complicated ๐Ÿค

- (RACSignal *)saveTagListSignal:(NSArray *)listOfTagArray {
    return
    [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSLog(@"Start saveTagListSignal");
        // Perform scanning tag database, if new tag is matched with query data, skip that tag
        PFQuery *tagQuery = [PFQuery queryWithClassName:@"Tag"];
        [tagQuery selectKeys:@[@"tagName"]];
        [[[tagQuery rac_findObjects] doNext:^ (NSArray *objects) {
            __block NSArray *pfTagObjects = objects;
            __block NSArray *filteredTagList;

            // Filter the existing tag list, only pick the tag that doesn't exist in the database.
            if ([pfTagObjects count] > 0) { // If there is tags existing in the database
                filteredTagList = _.array(listOfTagArray)
                .reject(^ BOOL (id tagArrayElement){
                    return _.array(pfTagObjects).any(^ BOOL (id pfTagObject){
                        return [[pfTagObject objectForKey:@"tagName"] isEqualToString:tagArrayElement];
                    });
                }).unwrap;

                // Save filtered tag list to the server first
                _.array(filteredTagList).each(^(NSString *tag){
                    [self saveTagList:tag];
                });
            } else { //  If there is no tag in database

                // Fix the case that duplicated tags are allowed to created if there is no tag in database
                filteredTagList = _.uniq(listOfTagArray);
                // Save new tag list to server
                _.array(filteredTagList).each(^(NSString *tag){
                    [self saveTagList:tag];
                });
                            };
        }] subscribeError:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^ {
            [subscriber sendCompleted];
            NSLog(@"Finish saveTagListSignal");
        }];
        return nil;
    }] deliverOn:[RACScheduler scheduler]];
}
- (void)saveTagList:(NSString *)tag {
    PFObject *newTag = [PFObject objectWithClassName:@"Tag"];
    [newTag setObject:tag forKey:@"tagName"];
    [newTag setObject:[PFUser currentUser] forKey:@"creator"];
    [[newTag rac_save] subscribeCompleted:^ {
        NSLog(@"New tag has been created");
    }];
}

Remove Parse SDK NSError* Normalization?

PFRACCallbacks.m#L16 looks like it was written to handle a situation where the NSError* returned from the ParseSDK didn't set the NSLocalizedDescriptionKey and instead stuffed the string representation of the underlying error into userInfo[@"error"]

However, NSErrors returned by ParseSDK 1.2.15+ do have a localizedDescription set. So, the question is, should we remove PFRACNormalizeError completely? Alternatively, we could leave it in place but modify it to only handle the error == nil case.

FWIW, I checked the Parse iOS SDK release notes but didn't see anything about a change in how NSError were generated, so I'm assuming this code was originally written as a workaround for a time when Parse SDK errors did not include a localized description.

Best way to use `rac_countObjects`?

Hi guys,
I'm having a problem with how to use rac_countObjects. In my sample code method, what I did is get an aFilteredPFLocationObjectsArray from previous signal by flattenMap. I want to return a signal which value is a pair of location and number of photos. With ordinary Parse Query, I used -countObjects to synchronously get number of photo based on particular location. The problem is -rac_countObjects get data asynchronously, there is possibility my method return signal before rac_countObjects completed, hence no corresponding photo is counted.
How can I overcome this issue?

- (RACSignal *)filteredPFLocationObjectsSignal:(NSArray *)aFilteredPFLocationObjectsArray {
    return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSMutableArray *filteredArray = [NSMutableArray array];
        _.array(aFilteredPFLocationObjectsArray).each(^ (PFObject *pfLocationObject){
            PFRelation *photoRelation  = [pfLocationObject relationforKey:@"photos"];
            NSNumber *newNumber = [NSNumber numberWithInt:[[photoRelation query]countObjects]];
            NSDictionary *data = [NSDictionary dictionaryWithObjects:@[pfLocationObject, newNumber] forKeys:@[@"pfLocationObject", @"number"]];
            [filteredArray addObject:data];
        });
        [subscriber sendNext:filteredArray];
        [subscriber sendCompleted];
        return nil;
    }] deliverOn:[RACScheduler scheduler]];
}

Edited 1: Is using zip:reduce possible in this case?

OS X support

At this time, it seems not much needs to be done, mainly conditionally disabling support for PFPush.

rac_findObjects just hangs with firstOrDefault

Why?

I don't want to use the synchronous SDK API because I want to compose my signal with other parts of code asynchronously as well.

Basically what my code does:

PFQuery *query = [PFQuery queryWithClassName:...];

NSArray *objects = [query findObjects];
DDLogInfo(@"1. got objects %@", objects);                  // works

objects = [[query rac_findObjects] first];
DDLogInfo(@"2. got objects with RAC: %@", objects); // HANGS

[pfobject rac_save] is not fired

Hi @kastiglione,
I'm trying to save an PFObject after modify its data. But some how rac_save is not fired when I subscribe to that signal:

[[obj rac_save] subscribeNext:^ (id x) {
    //Do stuff here
}];

Updated: subscribeCompleted is working in my case

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.