Parse-SDK-iOS-OSX
Parse-SDK-iOS-OSX copied to clipboard
macOS Command Line App Crash
I am getting a 'NSInvalidArgumentException', reason: 'Invalid class name. Class names cannot start with an underscore.' shortly after running my macOS app.
When setting a symbolic breakpoint in +[PFObject(Private) _assertValidInstanceClassName:] which checks if a class name is nil or begins with an underscore,
+ (void)_assertValidInstanceClassName:(NSString *)className {
PFParameterAssert(className, @"Class name can't be 'nil'.");
PFParameterAssert(![className hasPrefix:@"_"], @"Invalid class name. Class names cannot start with an underscore.");
}
I see that the class name being passed in is:
@"_Installation"
In looking at PFInstallation it does appear to be returning a class name with an underscore.
https://github.com/parse-community/Parse-SDK-iOS-OSX/blob/41e9ed0c41d2a5b53aaacd413d9a29c911ca478d/Parse/Parse/PFInstallation.m#L134
Has anyone seen this behavior before or know why an underscore is being returned from parseClassName for PFInstallation and other classes such as PFPin, PFProduct, PFUser if class names cannot start with an underscore?
I am using the latest from master with the macOS SDK compiled with bundle exec rake package:frameworks
Please let me know if any additional detail would be needed. Thanks in advance.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid class name. Class names cannot start with an underscore.'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff3ae58ecd __exceptionPreprocess + 256
1 libobjc.A.dylib 0x00007fff66f24720 objc_exception_throw + 48
2 CoreFoundation 0x00007fff3ae58cff +[NSException raise:format:] + 201
3 Parse 0x00000001003b6735 +[PFObject(Private) _assertValidInstanceClassName:] + 128
4 Parse 0x00000001003bcf0d -[PFObject init] + 381
5 Parse 0x00000001003bd1bc -[PFObject initWithObjectState:] + 62
6 Parse 0x00000001003bd2ca +[PFObject objectWithClassName:objectId:completeData:] + 244
7 Parse 0x00000001003bd719 +[PFObject object] + 211
8 Parse 0x0000000100406485 __56-[PFCurrentInstallationController getCurrentObjectAsync]_block_invoke.40 + 251
9 Bolts 0x000000010050235b __62-[BFTask continueWithExecutor:successBlock:cancellationToken:]_block_invoke + 126
10 Bolts 0x0000000100501c8b __55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke + 93
11 Bolts 0x0000000100502ff2 __29+[BFExecutor defaultExecutor]_block_invoke_2 + 138
12 Bolts 0x00000001005035a6 -[BFExecutor execute:] + 72
13 Bolts 0x0000000100501868 -[BFTask runContinuations] + 392
14 Bolts 0x000000010050137e -[BFTask trySetResult:] + 165
15 Bolts 0x00000001004ff8a3 -[BFTaskCompletionSource trySetResult:] + 86
16 Parse 0x00000001003ae9f4 __28-[PFAsyncTaskQueue enqueue:]_block_invoke_2 + 211
17 Bolts 0x0000000100501c8b __55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke + 93
18 libdispatch.dylib 0x00000001005266eb _dispatch_call_block_and_release + 12
19 libdispatch.dylib 0x00000001005277c3 _dispatch_client_callout + 8
20 libdispatch.dylib 0x000000010052a3d2 _dispatch_queue_override_invoke + 1046
21 libdispatch.dylib 0x000000010053a270 _dispatch_root_queue_drain + 334
22 libdispatch.dylib 0x000000010053ad33 _dispatch_worker_thread2 + 125
23 libsystem_pthread.dylib 0x00000001005a2119 _pthread_wqthread + 619
24 libsystem_pthread.dylib 0x00000001005a1e41 start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException
After doing some more investigation, it appears that in the PFCurrentInstallationController when the PFInstallation is created on Line 121 it will end up calling the subclassForParseClassName: method on Line 113 of the PFObjectSubclassingController.
At this point, the _registeredSubclasses dictionary does not contain anything other than my one Parse subclass that I have registered.
(lldb) po _registeredSubclasses
{
ESStock = "<PFObjectSubclassInfo: 0x100977d30>";
}
As a result of PFInstallation not being registered yet, nil is being returned as the result from this method, which then results in the class being set to PFObject on this line,
Class class = [[self subclassingController] subclassForParseClassName:className] ?: [PFObject class];
which results in an instance of PFObject getting initialized with a classname of @"_Installation" being set in the internal state, and resulting in the Assert getting hit on Line 769 of PFObject.
Whats interesting is if I remove the macOS Parse Framework from my project that was generated with the the build script, and instead update my project to include the Parse.xcodeproj as a dependency project, setting Parse-macOS as a Target Dependency, etc when I then build and run my app, without changing any code, upon PFInstallation being registered, I do see valid data in the _registeredSubclasses dictionary, where as before, I was only seeing my custom Parse class that I registered, and everything works fine.
(lldb) po _registeredSubclasses
{
ESStock = "<PFObjectSubclassInfo: 0x100977d30>";
"_EventuallyPin" = "<PFObjectSubclassInfo: 0x100a60ac0>";
"_Installation" = "<PFObjectSubclassInfo: 0x10084d970>";
"_Pin" = "<PFObjectSubclassInfo: 0x100853e70>";
"_Role" = "<PFObjectSubclassInfo: 0x100856cb0>";
"_Session" = "<PFObjectSubclassInfo: 0x100854ff0>";
"_User" = "<PFObjectSubclassInfo: 0x100855160>";
}
Any idea why this may be. I have tried building both Release and Debug versions of the macOS Framework, and both have the same issue, but when I build and run my app with Parse as a dependency project, and not using a pre-built framework, it runs fine.
I am using Xcode 10.1 on Mojave.
After further investigation I have identified the issue. The reason why the crash does not occur when building the project with the Parse Framework set as a dependency project, is the built framework will reside in my built products directory in my Derived Data. The path to the bundle will be as such,
NSBundle </Users/John/Library/Developer/Xcode/DerivedData/MyApp-evymfyxvlxhybqevmdagabhijijj/Build/Products/Debug-dynamic-/Parse.framework> (loaded),
However, when I do not build and run my app with Parse as a dependency project, due to the fact that its a command line app, and thus cannot bundle the framework in the app bundle, the framework is installed in /Library/Frameworks.
"NSBundle </Library/Frameworks/Parse.framework> (loaded)",
As a result of PFObjectSubclassingController filtering out any bundles installed at /Library/
https://github.com/parse-community/Parse-SDK-iOS-OSX/blob/41e9ed0c41d2a5b53aaacd413d9a29c911ca478d/Parse/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.m#L333-L343
This prevents the classes in the Parse Framework from being registered resulting in the empty _registeredSubclasses dictionary as described above, thus resulting in the crash.
As documented in Apple's Framework Programming Guide, the /Library/Frameworks/ directory is a preferred directory for installing Frameworks.
I have submitted PR #1395 to address this issue.
Thanks for making such a report of this, this is the sort of contribution we need more of in this SDK 🤩
Closing via https://github.com/parse-community/Parse-SDK-iOS-OSX/pull/1395