Parse-sdk-ios-osx: Closures passed to Parse functions stop mysteriously

Created on 5 Mar 2018  路  14Comments  路  Source: parse-community/Parse-SDK-iOS-OSX

Issue Description

In my Swift code, functions that are passed closures as "block" parameters sometimes stop mysteriously at the moment one of the closure parameters is used.

Steps to reproduce

Observe the following function.

PFCloud.callFunction(inBackground: "someFunction", withParameters: ["blah": someVar], block: { (object: Any?, error: Error?) in
    print("foo")
    print(error!.localizedDescription)
    print("bar")
})

It may be worth mentioning that this function call _itself_ is inside a closure (namely, its in the closure passed to saveInBackground())

Results

The program prints "foo" but then it prints "-[__NSDictionaryI length]: unrecognized selector sent to instance 0x1c02ec000". It never prints "bar", nor does it throw an error - there is only debugger output.

I know for a fact that error is not nil, but even if it was nil, it should be throwing a nil unwrapping exception - it shouldn't just stop dead in its tracks.

When I use print(error) with no nil unwrapping, I get the following:

Optional(Error Domain=Parse Code=141 "{
code = 21608;
message = "Some message";
moreInfo = "Some info";
status = 400;
}" UserInfo={code=141, temporary=0, error={
code = 21608;
message = "Some message";
moreInfo = "Some info";
status = 400;
}, NSLocalizedDescription={
code = 21608;
message = "Some messgage";
moreInfo = "Some info";
status = 400;
}})

I've encountered a problem almost exactly like this in the past, but with the object variable. Check out the post here. Something unusual is going on with the object variable and the error variable.

Stale Troubleshooting

Most helpful comment

Now that you know what to look for, it's about digging the code path and adding a failing unit test first :)

All 14 comments

thanks for reporting the issue.

Did you try with:

print(error?.localizedDescription)

Is it generating the same issue?

Yes, same issue

Can you provide a demo project so we can reproduce the issue and investigate please? An possibly the full stacktace of the issue.

The project associated with this issue has been discontinued within the last 4 months. I am unable to give a demo because our server that was running parse is offline - I can't reproduce this issue. I can point you to the line of code where the issue was happening. I basically wanted to display error!.localizedDescription but since accessing the "error" variable was causing problems, I printed a string literal instead. There is no stack trace - the code stops immediately which is part of my confusion.

https://github.com/spoke-repair/Spoke/blob/master/ParseStarterProject/ConfirmBikeVC.swift#L50

Seeing the same thing:

Using:

pod 'Parse', '~> 1.17.1'
pod 'Parse/Core', '~> 1.17.1'
pod 'Parse/FacebookUtils', '~> 1.17.1'
pod 'Parse/TwitterUtils', '~> 1.17.1'

Code to cause the crash:

newUser.signUpInBackground { (success: Bool, error: Error?) in
   if let error = error {
      print(error.localizedDescription)
   } else {
      print("User Registered successfully")
   }
}

Stack Trace:

2018-08-27 22:48:40.154144-0400 MyApp[9685:16895891] [Error]: (
    "This username/email has already been taken"
) (Code: 141, Version: 1.17.1)
2018-08-27 22:48:40.154958-0400 MyApp[9685:16895776] -[__NSSingleObjectArrayI length]: unrecognized selector sent to instance 0x60c00001c620
2018-08-27 22:48:40.169144-0400 MyApp[9685:16895776] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSingleObjectArrayI length]: unrecognized selector sent to instance 0x60c00001c620'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010c8391e6 __exceptionPreprocess + 294
    1   libobjc.A.dylib                     0x000000010bece031 objc_exception_throw + 48
    2   CoreFoundation                      0x000000010c8ba784 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
    3   CoreFoundation                      0x000000010c7bb898 ___forwarding___ + 1432
    4   CoreFoundation                      0x000000010c7bb278 _CF_forwarding_prep_0 + 120
    5   libswiftCore.dylib                  0x000000010d5b1008 _T0S2SyXl12_cocoaString_tcfCTf4gd_n + 104
    6   libswiftCore.dylib                  0x000000010d549773 _T0S2SyXl12_cocoaString_tcfC + 19
    7   libswiftFoundation.dylib            0x000000010dafb99d _T0s5ErrorP10FoundationE20localizedDescriptionSSvg + 221
    8   MyApp                            0x00000001072121b5 _T08MyApp29CompleteProfileViewControllerC21completeSignupPressedyypFySb_s5Error_pSgtcfU_ + 293
    9   MyApp                            0x00000001072123f7 _T0Sbs5Error_pSgIegyx_SbSo7NSErrorCSgIeyByy_TR + 119
    10  Parse                               0x0000000108bd621c __62-[BFTask(Private) thenCallBackOnMainThreadWithBoolValueAsync:]_block_invoke + 156
    11  Parse                               0x0000000108bd5bb7 __72-[BFTask(Private) continueWithMainThreadResultBlock:executeIfCancelled:]_block_invoke + 311
    12  Bolts                               0x00000001081f05b8 __55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke + 104
    13  libdispatch.dylib                   0x000000010dee47ab _dispatch_call_block_and_release + 12
    14  libdispatch.dylib                   0x000000010dee57ec _dispatch_client_callout + 8
    15  libdispatch.dylib                   0x000000010def08cf _dispatch_main_queue_callback_4CF + 628
    16  CoreFoundation                      0x000000010c7fbc99 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    17  CoreFoundation                      0x000000010c7bfea6 __CFRunLoopRun + 2342
    18  CoreFoundation                      0x000000010c7bf30b CFRunLoopRunSpecific + 635
    19  GraphicsServices                    0x0000000111539a73 GSEventRunModal + 62
    20  UIKit                               0x00000001096b6057 UIApplicationMain + 159
    21  MyApp                            0x000000010721bdb7 main + 55
    22  libdyld.dylib                       0x000000010df62955 start + 1
    23  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

Potential workaround for error.localizedDescription:

newUser.signUpInBackground { (success: Bool, error: Error?) in
   let err = error! as? NSError

   if let err = err {

   let userInfo = err.userInfo
   let userError = userInfo["error"]
   let messageArray = userError as! [String]
   let message = messageArray[0]
    print(message)
}

@duffek are you willing to open a PR and provide a fix?

I'm very willing to do so, however I'm not sure I completely understand the issue. I believe the issue is with the conversion between Objective-C NSError and Swift 4 Error objects. It looks like the properties are not all translating over. For example, when you view the properties in the swift error you only see localizedDescription and not code, etc.

I could do a PR and simply add the cast from error to NSError but we'd be going back against the latest version of Swift. The second line my example gives a warning that this always succeeds.

Anyone else know what's happening here? I'm happy to make the change if I understand what change would be best to make it?

-David

Isn鈥檛 it just because there鈥檚 an array instead of a string inside the localizedDescription key that it breaks? I mean the crash is clear saying something tries to send the length message to an array like object. length is a valid selector on String and your workaround implies reading the first object of an array.

The fix is to find where in the code, an array is passed into an NSError and makes it crash after

Very good point. I'll see if I can find this and do the PR. I'd love to see this fixed and to contribute to Parse.

Now that you know what to look for, it's about digging the code path and adding a failing unit test first :)

Now that you know what to look for, it's about digging the code path and adding a failing unit test first :)

@flovilmart I'm looking into this and really running into two issues. Should this test be added to the UserUnitTests.m testUserCannotSignUpWithoutUsername test?
And the case: XCTAssertNotNil(task.error.userInfo[NSLocalizedDescriptionKey]); is there but only checking if it's nil. What would the test case be to check if it's an invalid type (i.e. array vs string)?

I am obviously new to writing test code (need to do more) and I'd love to see a guide on how to setup, contribute, and do some basic testing of the iOS-SDK. I'm also willing to write this guide and be more active if I can get some direction. I'll keep plugging away on my own either way.

And @flovilmart, thanks for all you are doing to keep this moving forward.

I have not much time on my hands now, so I guess besides running the tests from Xcode or running bundle exec rake:test those are the two main ways to run the tests. As for test code examples, you鈥檒l need to jump right in. Your fresh experience is very nice, if you can report your findings in the CONTRUBUTIING.md that would be awesome :)

This issue has been automatically marked as stale because it has not had recent activity. If you believe it should stay open, please let us know! As always, we encourage contributions, check out the Contributing Guide

Was this page helpful?
0 / 5 - 0 ratings