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.
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())
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.
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
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 :)