Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding more than one object to PFRelation in PFObject subclass "Operation is invalid after previous operation." #911

Closed
meoz opened this issue Apr 27, 2016 · 22 comments

Comments

@meoz
Copy link

meoz commented Apr 27, 2016

  • Using LocalDataStore
  • Subclass of PFObject is defined like this:
//PList.h
@interface PList : PFObject<PFSubclassing>
+ (NSString *)parseClassName;

@property (retain) NSString *name;
@property (retain) PFRelation *notes;
@end

//PList.m
@implementation PList
@dynamic name;
@synthesize notes = _notes;
+ (void)load {
    [self registerSubclass];
}
+ (NSString *)parseClassName {
    return @"PList";
}

- (PFRelation *)notes{
    if(_notes == nil) {
        _notes = [self relationForKey:@"notes"];
    }
    return _notes;
}
- (void)setNotes:(PFRelation *)notes{
    _notes = notes;
}
@end

//----------

Used in code like this:
PNote *note = [PNote Object];
note.name = @"mynote";

PList list = ....
 PFRelation *relation = [list notes];
[relation addObject:note];
 [list saveInBackground];

Adding one 'note'-object goes without problems, I can see the object appearing on the dashboard. But when adding a second 'note' object an exception is thrown: [NSException raise:NSInternalInconsistencyException format:@"Operation is invalid after previous operation."];

-> object in relation is not added

@nlutsenko
Copy link
Contributor

Hey @meoz, thanks for the report!

Let's look into this together:

  • Are you calling into .notes = ... at any give point in time?
  • Is there any chance notes can be anything else other than PFRelation at any given point in time?
  • Can you post a full stack trace when the exception is being thrown? (it is most likely inside PFRelationOperation, where if you could print out and paste here the value of oldValue argument that would be just amazing.

Most likely what happens here is that you are trying to set the relation field to a PFRelation, which is unsupported use case at this point (we could support it eventually).

Another solution that might help here is to not to use synthesized property for your relation, but rather organize it into something that looks like this:

@interface PList : PFObject<PFSubclassing>
+ (NSString *)parseClassName;

@property (retain) NSString *name;
@property (nonatomic, strong, readonly) PFRelation *notes;
@end

//PList.m
@implementation PList
@dynamic name;
@dynamic notes;
+ (void)load {
    [self registerSubclass];
}
+ (NSString *)parseClassName {
    return @"PList";
}

- (PFRelation *)notes {
    return [self relationForKey:@"notes"];
}
@end

It would better describe your intention here, compared to mutable relation.

Let me know if any of this helps.

@parse-github-bot
Copy link

Thank you for your feedback. We prioritize issues that have clear and concise repro steps. Please see our Bug Reporting Guidelines about what information should be added to this issue.

Please try the latest SDK. Our release notes have details about what issues were fixed in each release.

In addition, you might find the following resources helpful:

@meoz
Copy link
Author

meoz commented May 2, 2016

Hi @nlutsenko thanks for replying (sorry for the late reaction)

For some reason it appears that after calling 'saveEventually' on the subclassed PFObject the PFRelation property 'notes' becomes a PFRelationOperation which will cause the subsequent NSInternalInconsistencyException. I cant't find any place in my code where I use the notes property for anything else than adding 'child' objects which the PFRelation is pointing to (ASQTask in my code).

This is the method I wrote to add objects to the relation:

- (void)addNotesObject:(PTask *)note toList:(PList*)list
{
    [list unpinInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {
        if (succeeded)
        {
            PFRelation *relation = [list notes];

            //add to list.notes PFRelation
            //notes = "<PFRelation: 0x7fd653830c90, 0x7fd651747580.notes -> ASQTask>";

            [relation addObject:note];

            [list saveEventually:^(BOOL succeeded, NSError * _Nullable error) {

                //here list.notes became PFRelationOperation
                //notes = "PFRelationOperation<ASQTask> add:{(\n    <ASQTask: 0x7fd65162a860, objectId: sggBDRwAoE, localId: (null)>\n)} remove:{(\n)}";

                [list pinInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {
                    if (succeeded)
                    {
                        NSLog(@"saved & pinned");
                    }
                }];

            }];
        }
    }];
}

When I would add a second object, it'll crash on the following method in PFFieldOperation.m
Value of oldValue: FRelationOperation<ASQTask> add:{( <ASQTask: 0x7fd65162a860, objectId: sggBDRwAoE, localId: (null)> {....
Value of key: notes

- (id)applyToValue:(id)oldValue forKey:(NSString *)key {
    PFRelation *relation = nil;
    if (!oldValue) {
        relation = [PFRelation relationWithTargetClass:self.targetClass];
    } else if ([oldValue isKindOfClass:[PFRelation class]]) {
        relation = oldValue;
        if (self.targetClass) {
            if (relation.targetClass) {
                PFParameterAssert([relation.targetClass isEqualToString:targetClass],
                                  @"Related object object must be of class %@, but %@ was passed in",
                                  relation.targetClass, self.targetClass);
            } else {
                relation.targetClass = self.targetClass;
            }
        }
    } else {
        [NSException raise:NSInternalInconsistencyException format:@"Operation is invalid after previous operation."];
        return nil;
    }

    for (PFObject *object in self.relationsToAdd) {
        [relation _addKnownObject:object];
    }
    for (PFObject *object in self.relationsToRemove) {
        [relation _removeKnownObject:object];
    }

    return relation;
}

Also doing this:
PFQuery *query = [[self.list notes] query]; NSArray *items = [query findObjects];

will crash on the following method:

- (BFTask *)_findObjectsAsyncInRelation:(PFRelation *)relation
                               ofObject:(PFObject *)parentObject
                          forQueryState:(PFQueryState *)queryState
                  withCancellationToken:(BFCancellationToken *)cancellationToken
                                   user:(PFUser *)user {
    return [[super findObjectsAsyncForQueryState:queryState
                           withCancellationToken:cancellationToken
                                            user:user] continueWithSuccessBlock:^id(BFTask *fetchTask) {

        NSArray *objects = fetchTask.result;
        for (PFObject *object in objects) {
            [relation _addKnownObject:object];
        }

        return [[_offlineStore updateDataForObjectAsync:parentObject] continueWithBlock:^id(BFTask *task) {
            // Roll-forward the result of find task instead of a result of update task.
            return fetchTask;
        } cancellationToken:cancellationToken];
    } cancellationToken:cancellationToken];
}

Stacktrace:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[PFRelationOperation _addKnownObject:]: unrecognized selector sent to instance 0x7ff6e0ccbbf0' *** First throw call stack: ( 0 CoreFoundation 0x000000010c22bd85 __exceptionPreprocess + 165 1 libobjc.A.dylib 0x000000010bc76deb objc_exception_throw + 48 2 CoreFoundation 0x000000010c234d3d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205 3 CoreFoundation 0x000000010c17acfa ___forwarding___ + 970 4 CoreFoundation 0x000000010c17a8a8 _CF_forwarding_prep_0 + 120 5 Notes_parseServer 0x00000001066e1ee0 __106-[PFOfflineQueryController _findObjectsAsyncInRelation:ofObject:forQueryState:withCancellationToken:user:]_block_invoke + 432 6 Notes_parseServer 0x0000000106563170 __62-[BFTask continueWithExecutor:successBlock:cancellationToken:]_block_invoke + 160 7 Notes_parseServer 0x00000001065624f0 __55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke + 112 8 Notes_parseServer 0x000000010655d8be __29+[BFExecutor defaultExecutor]_block_invoke_2 + 190 9 Notes_parseServer 0x000000010655e26e -[BFExecutor execute:] + 94 ....


I want to add that not synthesizing the property and doing this:

- (PFRelation *)notes {
    return [self relationForKey:@"notes"];
}

dit not help. Still crashing on the same locations.

Thanks for any help on this.

@meoz
Copy link
Author

meoz commented May 6, 2016

It seems the problem is not related to using subclasses or localDataStore. Apparently the problem occurs when a beforeSave cloud function returns response.success()instead of response.success(request.object). When using the former on an object that contains a PFRelation, that PFRelation get's screwed up on the client side (becomes PFRelationOperation).

Unfortunately just using response.success(request.object) is not the solution. Using this will keep the PFRelation field intact but it will not save any data defined in the cloud function beforeSave method.

Here MyObject will not save (or create) the 'colorstring' column.

Parse.Cloud.beforeSave('MyObject', function(request, response) {
    request.object.set('colorstring', 'green');
        return response.success(request.object);
});

Here MyObject will save (or create) the 'colorstring' column. But will render any PFRelation column on MyObject useless (see first posts).

Parse.Cloud.beforeSave('MyObject', function(request, response) {
    request.object.set('colorstring', 'green');
        return response.success();
});

@kokernutz
Copy link

I started getting this error message after migrating to heroku. I am adding a single PFUser to the relation "blocked" off the User class. I even tried a save before the add just in case.

oldValue is

PFRelationOperation<_User> add:{(
    <PFUser: 0x7fd5051256f0, objectId: GkDlCuA92g, localId: (null)> {
}
)} remove:{(
)}

@tony-pizza
Copy link

Is this issue specific to parse-server?

@kokernutz
Copy link

Well I am using the parse-server (2.2.9) in my heroku app, but I sense that it has more to do with the iOS SDK than the server component.

@tony-pizza
Copy link

@kokernutz Cool, thanks.

I'm encountering this bug after switching to parse-server (2.2.7), also on Heroku. The relation code in our app that's causing the PFRelationOperation thing hasn't changed in a while. I'm pretty sure the same code was working on Parse.com.

Has anyone encountered this using the iOS SDK with Parse.com?

@shrimant-nikate-mobisoft
Copy link

shrimant-nikate-mobisoft commented May 17, 2016

@nlutsenko, I have also encountered the same issue after migrating parse server(2.2.9) on Heroku. I was trying to add some objects to the PFRelation Object but it automatically converted into the PFRelationOperation.

let ratedRelation = currentUser?.relationForKey("ratedImages")
        ratedRelation?.addObject(imagePFObject!)
        currentUser?.saveInBackground()

In the above code, I have a one to many relation between User and RatedImages and trying to add new ratedImage into relation of the current user.

I have also tried to save the imagePFObject before adding into the PFRelation.

Also, The above code is working fine with parse.com.

@hshinde
Copy link

hshinde commented May 18, 2016

Any update on this issue. We are observing the same and the migration to Parse Server is blocked due to this issue.

@rubenatorio
Copy link

I'm also having this issue trying to recreate it now

@hshinde
Copy link

hshinde commented May 24, 2016

Any updates on this issue? Anybody else observing the same?

@parse-github-bot
Copy link

This issue has not been updated for 7 days. If you have additional information to help pinpoint this issue as an SDK bug, please comment on this issue. We will close this issue in 7 days if no additional information is provided. Thank you for your feedback.

@shrimant-nikate-mobisoft
Copy link

shrimant-nikate-mobisoft commented Jun 1, 2016

@nlutsenko, I was trying to catch the actual issue and following are the details which I have found so far,

  1. I am working on the parse server(2.2.9) on Heroku.
  2. There is a relation between User and Images and the Name of relation is "RatedImages"
  3. The same code is working with the Parse.com
  4. Please find the attached screenshot
    pfrelation copy
    changedvalue copy
    exception copy
  5. Also, I have attached the stack that may help you through.
    stack.txt

Please let me know in case you required further details from me.

@kokernutz
Copy link

Tried upgrading parse-server to 2.2.11 and still have the problem.

@kokernutz
Copy link

Upgraded to parse-server 2.2.12 and still have the problem.

@parse-github-bot
Copy link

This issue has not been updated for 7 days. If you have additional information to help pinpoint this issue as an SDK bug, please comment on this issue. We will close this issue in 7 days if no additional information is provided. Thank you for your feedback.

@hshinde
Copy link

hshinde commented Jun 17, 2016

Any update on this issue?

@parse-github-bot
Copy link

This issue has not been updated for 7 days. If you have additional information to help pinpoint this issue as an SDK bug, please comment on this issue. We will close this issue in 7 days if no additional information is provided. Thank you for your feedback.

@hshinde
Copy link

hshinde commented Jun 28, 2016

We upgraded to 2.2.14 and did not face this issue.
We are still testing it, and update here if we face any issues.

@parse-github-bot
Copy link

This issue has not been updated for 7 days. If you have additional information to help pinpoint this issue as an SDK bug, please comment on this issue. We will close this issue in 7 days if no additional information is provided. Thank you for your feedback.

@parse-github-bot
Copy link

We are closing this issue due to another 7 days of inactivity. If you have additional information to help pinpoint this issue as an SDK bug, please reopen it with the additional information.Thank you for your feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants