How can I use saved tokens in NXOAuth2? - ios

I am trying to implement a solution using the NXOauth2 pod to handle OAuth2 on my iOS app.
I am able to go through the installed application flow to get OAuth2 properties including accessToken and refreshToken - and the account is being saved into my NXOAuth2AccountStore properly (verified by inspecting [[NXOAuth2AccountStore sharedStore] accounts]).
Now that I have saved the tokens, I want to use them on subsequent app opens rather than go through requesting access again from the user. I do this here:
- (NSArray *)allAccounts
{
NXOAuth2AccountStore *store = [NXOAuth2AccountStore sharedStore];
NSArray *accounts = [store accountsWithAccountType:kIDMOAuth2AccountType];
return accounts;
}
The following call (to get some user details) works right after the user goes through the approval flow but it does not work when the app is closed and reopened.
- (void)requestOAuth2ProtectedDetails
{
[NXOAuth2Request performMethod:#"GET"
onResource:[NSURL URLWithString:#"https://www.googleapis.com/oauth2/v1/userinfo"]
usingParameters:nil
withAccount:[self allAccounts][0]
sendProgressHandler:^(unsigned long long bytesSend, unsigned long long bytesTotal) {
// e.g., update a progress indicator
}
responseHandler:^(NSURLResponse *response, NSData *responseData, NSError *error){
// Process the response
if (responseData) {
NSError *error;
NSDictionary *userInfo = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&error];
NSLog(#"%#", userInfo);
}
if (error) {
NSLog(#"%#", error.localizedDescription);
}
}];
}
How should I use a saved accessToken / refreshToken to:
Query data using requestOAuth2ProtectedDetails?
Get an updated accessToken if required, using the refreshToken I have saved?
Here is the error I am getting:
2014-06-23 09:41:17.040 Connector[8495:60b] Got access token
2014-06-23 09:41:19.296 Connector[8495:60b] *** Assertion failure in -[NXOAuth2Client initWithClientID:clientSecret:authorizeURL:tokenURL:accessToken:tokenType:persistent:delegate:], /Users/ericgross/Documents/Connector/Pods/NXOAuth2Client/Sources/OAuth2Client/NXOAuth2Client.m:82
2014-06-23 09:41:19.300 Connector[8495:60b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'No token or no authorize URL'
*** First throw call stack:
(
0 CoreFoundation 0x01c281e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x019a78e5 objc_exception_throw + 44
2 CoreFoundation 0x01c28048 +[NSException raise:format:arguments:] + 136
3 Foundation 0x015874de -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 116
4 Connector 0x00011456 -[NXOAuth2Client initWithClientID:clientSecret:authorizeURL:tokenURL:accessToken:tokenType:persistent:delegate:] + 502
5 Connector 0x00009a59 -[NXOAuth2Account oauthClient] + 841
6 Connector 0x0001f30b -[NXOAuth2Request performRequestWithSendingProgressHandler:responseHandler:] + 667
7 Connector 0x0001e8d4 +[NXOAuth2Request performMethod:onResource:usingParameters:withAccount:sendProgressHandler:responseHandler:] + 404
8 Connector 0x00003eca -[ESGOAuth2Manager requestOAuth2ProtectedDetails] + 266
9 Connector 0x00002cba -[ESGOAuth2Manager setup] + 282
10 Connector 0x0000214f -[ESGViewController viewDidLoad] + 415
11 UIKit 0x0078633d -[UIViewController loadViewIfRequired] + 696
12 UIKit 0x007865d9 -[UIViewController view] + 35
13 UIKit 0x006a6267 -[UIWindow addRootViewControllerViewIfPossible] + 66
14 UIKit 0x006a65ef -[UIWindow _setHidden:forced:] + 312
15 UIKit 0x006a686b -[UIWindow _orderFrontWithoutMakingKey] + 49
16 UIKit 0x006b13c8 -[UIWindow makeKeyAndVisible] + 65
17 UIKit 0x00661bc0 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 2097
18 UIKit 0x00666667 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 824
19 UIKit 0x0067af92 -[UIApplication handleEvent:withNewEvent:] + 3517
20 UIKit 0x0067b555 -[UIApplication sendEvent:] + 85
21 UIKit 0x00668250 _UIApplicationHandleEvent + 683
22 GraphicsServices 0x02fa7f02 _PurpleEventCallback + 776
23 GraphicsServices 0x02fa7a0d PurpleEventCallback + 46
24 CoreFoundation 0x01ba3ca5 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
25 CoreFoundation 0x01ba39db __CFRunLoopDoSource1 + 523
26 CoreFoundation 0x01bce68c __CFRunLoopRun + 2156
27 CoreFoundation 0x01bcd9d3 CFRunLoopRunSpecific + 467
28 CoreFoundation 0x01bcd7eb CFRunLoopRunInMode + 123
29 UIKit 0x00665d9c -[UIApplication _run] + 840
30 UIKit 0x00667f9b UIApplicationMain + 1225
31 Connector 0x0000443d main + 141
32 libdyld.dylib 0x02265701 start + 1
33 ??? 0x00000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
The first time through, this works:
- (void)performRequestWithSendingProgressHandler:(NXOAuth2ConnectionSendingProgressHandler)progressHandler
responseHandler:(NXOAuth2ConnectionResponseHandler)responseHandler;
{
NSAssert(self.me == nil, #"This object an only perform one request at the same time.");
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.resource];
[request setHTTPMethod:self.requestMethod];
self.connection = [[NXOAuth2Connection alloc] initWithRequest:request
requestParameters:self.parameters
oauthClient:self.account.oauthClient
sendingProgressHandler:progressHandler
responseHandler:responseHandler];
self.connection.delegate = self;
// Keep request object alive during the request is performing.
self.me = self;
}
And I notice the following:
(lldb) po self.account.oauthClient
<NXOAuth2Client: 0x8f1e760>
But in the failure case, this happens:
(lldb) po self.account.oauthClient
2014-06-23 10:13:25.457 Connector[8678:60b] *** Assertion failure in -[NXOAuth2Client initWithClientID:clientSecret:authorizeURL:tokenURL:accessToken:tokenType:persistent:delegate:], /Users/ericgross/Documents/Connector/Pods/NXOAuth2Client/Sources/OAuth2Client/NXOAuth2Client.m:82
error: Execution was interrupted, reason: internal ObjC exception breakpoint(-3)..
The process has been returned to the state before expression evaluation.

The library works pretty well,it automatically saves your accounts after a successful login was made. The accounts are not deleted from the account store unless you specifically say so.
For example i use this to delete all account on logout:
NXOAuth2AccountStore* store=[NXOAuth2AccountStore sharedStore];
for (NXOAuth2Account *account in [store accounts]) {
[store removeAccount:account];
}
see that you don't remove your accounts when you enter on close the app.
As for the second matter, i am searching for a solution as well

Related

Spotify SPTAuth canHandleURL is crashing with NSInvalidArgumentException

I have upgraded Spotify from Beta6 to Beta9. One of the necessary changes to support the upgrade is to the canHandleURL method signature. The Beta6 signature was:
canHandleURL: withDeclaredRedirectURL:
The new signature removes withDeclaredRedirectURL. However, when I try to execute the method with the new signature from my appDelegate in the following manner:
-(BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
if ([[SPTAuth defaultInstance] canHandleURL:url]) {
[[SPTAuth defaultInstance]
handleAuthCallbackWithTriggeredAuthURL:url callback:^(NSError *error, SPTSession *session) {
if (error != nil) {
...
return;
}
// Save the session info
...
}];
return YES;
}
...
return NO;
}
The error is as follows:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '- [__NSCFString hasPrefix:]: nil argument'
*** First throw call stack:
(
0 CoreFoundation 0x0000000112eeec65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000112b87bb7 objc_exception_throw + 45
2 CoreFoundation 0x0000000112eeeb9d +[NSException raise:format:] + 205
3 CoreFoundation 0x0000000112e0ee00 -[__NSCFString hasPrefix:] + 96
4 MyAPP 0x000000010fa64c0a -[SPTAuth _canHandleURL:withDeclaredRedirectURL:] + 143
5 MyAPP 0x000000010fa64c7e -[SPTAuth canHandleURL:] + 82
6 MyAPP 0x000000010f9e8c09 -[myAppDelegate application:openURL:sourceApplication:annotation:] + 73
7 UIKit 0x0000000111159cd0 __45-[UIApplication _applicationOpenURL:payload:]_block_invoke + 144
8 UIKit 0x0000000111159c31 -[UIApplication _applicationOpenURL:payload:] + 333
9 UIKit 0x0000000111162328 -[UIApplication _handleNonLaunchSpecificActions:forScene:withTransitionContext:] + 2350
10 UIKit 0x0000000111165e71 __88-[UIApplication _handleApplicationLifecycleEventWithScene:transitionContext:completion:]_block_invoke + 196
11 UIKit 0x0000000111165d9e -[UIApplication _handleApplicationLifecycleEventWithScene:transitionContext:completion:] + 349
12 UIKit 0x00000001111507fa -[UIApplication scene:didUpdateWithDiff:transitionContext:completion:] + 486
13 FrontBoardServices 0x00000001175605e5 __31-[FBSSerialQueue performAsync:]_block_invoke_2 + 21
14 CoreFoundation 0x0000000112e2241c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
15 CoreFoundation 0x0000000112e18165 __CFRunLoopDoBlocks + 341
16 CoreFoundation 0x0000000112e17f25 __CFRunLoopRun + 2389
17 CoreFoundation 0x0000000112e17366 CFRunLoopRunSpecific + 470
18 GraphicsServices 0x00000001138f6a3e GSEventRunModal + 161
19 UIKit 0x0000000111152900 UIApplicationMain + 1282
20 MyAPP 0x000000010f9925b1 main + 97
21 libdyld.dylib 0x0000000113420145 start + 1
22 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
This code appears to follow the iOS SDK tutorial, so I am not sure why this is crashing. When I updated the Spotify.framework, I deleted the old one (moved to trash) and I deleted the Derived Data to clear out the cache in the compiler. Then I dragged the new Spotify.framework into Xcode. Can you see if I have made some mistake? Please help.

Using Chat Application XMPPFramework Iam getting This Error

Using Chat Application with XMPPFramework Iam getting This Error
Message SendButton Action as given below, plz help me if any one have idea then tell me plz..............
- (IBAction)sendAction:(id)sender
{
if([_chatTextField.text length] > 0)
{
NSString* po = getUser.ofUser;
bubbleTable.typingBubble = NSBubbleTypingTypeNobody;
NSBubbleData *messageBubble = [NSBubbleData dataWithText:_chatTextField.text date:[NSDate dateWithTimeIntervalSinceNow:0] type:BubbleTypeMine];
[bubbleData addObject:messageBubble];
[bubbleTable reloadData];
[bubbleTable scrollBubbleViewToBottomAnimated:YES];
[[QuoteMessageController SharedInstance] SendChatMessageTo:getUser.account withContent:_chatTextField.text toUserId:[NSString stringWithFormat:#"%ld", (long)getUser.Id] andOFId:po andVerifyKey:chatMessageKey];
}
Getting error in output as given bellow>>>>>>
*** First throw call stack:
(
0 CoreFoundation 0x000000010e18ff35 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010da7bbb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010e18fe6d +[NSException raise:format:] + 205
3 Foundation 0x000000010ba211f8 -[NSString stringByAppendingString:] + 96
4 SourceSage 0x000000010ae0c939 +[SSWriteReadInDb writeQuotesTable:UserImageUrl:UserId:OfUser:] + 409
5 SourceSage 0x000000010adb8d56 -[QuoteMessageController SendChatMessageTo:withContent:toUserId:andOFId:andVerifyKey:] + 2454
6 SourceSage 0x000000010ad6ac30 -[SSChatViewController sendAction:] + 752
7 UIKit 0x000000010beb48be -[UIApplication sendAction:to:from:forEvent:] + 75
8 UIKit 0x000000010bfbb410 -[UIControl _sendActionsForEvents:withEvent:] + 467
9 UIKit 0x000000010bfba7df -[UIControl touchesEnded:withEvent:] + 522
10 UIKit 0x000000010befa308 -[UIWindow _sendTouchesForEvent:] + 735
11 UIKit 0x000000010befac33 -[UIWindow sendEvent:] + 683
12 UIKit 0x000000010bec79b1 -[UIApplication sendEvent:] + 246
13 UIKit 0x000000010bed4a7d _UIApplicationHandleEventFromQueueEvent + 17370
14 UIKit 0x000000010beb0103 _UIApplicationHandleEventQueue + 1961
15 CoreFoundation 0x000000010e0c5551 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
16 CoreFoundation 0x000000010e0bb41d __CFRunLoopDoSources0 + 269
17 CoreFoundation 0x000000010e0baa54 __CFRunLoopRun + 868
18 CoreFoundation 0x000000010e0ba486 CFRunLoopRunSpecific + 470
19 GraphicsServices 0x000000010fe7c9f0 GSEventRunModal + 161
20 UIKit 0x000000010beb3420 UIApplicationMain + 1282
21 SourceSage 0x000000010ae02893 main + 115
22 libdyld.dylib 0x000000010ee2e145 start + 1
23 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
After looking at this part of your stack trace:
2 CoreFoundation 0x000000010e18fe6d +[NSException raise:format:] + 205
3 Foundation 0x000000010ba211f8 -[NSString stringByAppendingString:] + 96
4 SourceSage 0x000000010ae0c939 +[SSWriteReadInDb writeQuotesTable:UserImageUrl:UserId:OfUser:] + 409
5 SourceSage 0x000000010adb8d56 -[QuoteMessageController SendChatMessageTo:withContent:toUserId:andOFId:andVerifyKey:] + 2454
6 SourceSage 0x000000010ad6ac30 -[SSChatViewController sendAction:] + 752
You'll see the exception is raised after a string is appended to a string. That is usually caused from appending nil to the string. By guess is that one of your NSString arguments that you're sending to the method below is nil.
[[QuoteMessageController SharedInstance] SendChatMessageTo:getUser.account
withContent:_chatTextField.text
toUserId:[NSString stringWithFormat:#"%ld", (long)getUser.Id]
andOFId:po
andVerifyKey:chatMessageKey];
To find out if this is in fact the case, either set a breakpoint here and check all the values, or add in the following before you call this method:
NSLog(#"%#", getUser.account);
NSLog(#"%#", _chatTextField.text);
NSLog(#"%#", po);
NSLog(#"%#", [NSString stringWithFormat:#"%ld", (long)getUser.Id]);
NSLog(#"%#", chatMessageKey);
I don't know what your parameters actually are, so remove the NSLogs for the variables that are not NSString. If one of these logs come back as nil or null (I forget what the console will output), then you found your issue. If it's an argument that you don't necessarily need, you should pass an empty NSString instead. I usually do this with a ternary. So assuming the culprit is _chatTextField.text, I would pass that argument as:
[[QuoteMessageController SharedInstance] SendChatMessageTo:getUser.account
withContent:_chatTextField.text ?: #""
toUserId:[NSString stringWithFormat:#"%ld", (long)getUser.Id]
andOFId:po
andVerifyKey:chatMessageKey];
Doing this basically says, if _chatTextField.text is true (which it will equate to if it is not nill), use that value, otherwise use #""
EDIT:
- (IBAction)sendAction:(id)sender
{
if([_chatTextField.text length] > 0)
{
NSString* po = getUser.ofUser ?: #"";
NSString *acct = getUser.account ?: #"";
bubbleTable.typingBubble = NSBubbleTypingTypeNobody;
NSBubbleData *messageBubble = [NSBubbleData dataWithText:_chatTextField.text date:[NSDate dateWithTimeIntervalSinceNow:0] type:BubbleTypeMine];
[bubbleData addObject:messageBubble];
[bubbleTable reloadData];
[bubbleTable scrollBubbleViewToBottomAnimated:YES];
[[QuoteMessageController SharedInstance] SendChatMessageTo:acct withContent:_chatTextField.text toUserId:[NSString stringWithFormat:#"%ld", (long)getUser.Id] andOFId:po andVerifyKey:chatMessageKey];
}

how to integrate zksforce with native ios and create custom login to get fields of sales force user

i try this to custom login with user name and password + security token. but it return error or exception like
Terminating app due to uncaught exception 'INVALID_LOGIN', reason: 'INVALID_LOGIN: Invalid username, password, security token; or user locked out.'
*** First throw call stack:
(
0 CoreFoundation 0x018fb5e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x0167e8b6 objc_exception_throw + 44
2 lead miner sales force 0x0001932a -[ZKBaseClient sendRequest:name:returnRoot:] + 2266
3 lead miner sales force 0x0001882a -[ZKBaseClient sendRequest:name:] + 90
4 lead miner sales force 0x00004516 -[ZKSoapLogin login] + 358
5 lead miner sales force 0x000107c1 -[ZKSforceClient soapLogin:] + 65
6 lead miner sales force 0x00010965 -[ZKSforceClient login:password:] + 277
7 lead miner sales force 0x0000b0fb -[loginViewController loginbutton:] + 315
8 libobjc.A.dylib 0x01690874 -[NSObject performSelector:withObject:withObject:] + 77
9 UIKit 0x003ee0c2 -[UIApplication sendAction:to:from:forEvent:] + 108
10 UIKit 0x003ee04e -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61
11 UIKit 0x004e60c1 -[UIControl sendAction:to:forEvent:] + 66
12 UIKit 0x004e6484 -[UIControl _sendActionsForEvents:withEvent:] + 577
13 UIKit 0x004e5733 -[UIControl touchesEnded:withEvent:] + 641
14 UIKit 0x0042b51d -[UIWindow _sendTouchesForEvent:] + 852
15 UIKit 0x0042c184 -[UIWindow sendEvent:] + 1232
16 UIKit 0x003ffe86 -[UIApplication sendEvent:] + 242
17 UIKit 0x003ea18f _UIApplicationHandleEventQueue + 11421
18 CoreFoundation 0x0188483f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
19 CoreFoundation 0x018841cb __CFRunLoopDoSources0 + 235
20 CoreFoundation 0x018a129e __CFRunLoopRun + 910
21 CoreFoundation 0x018a0ac3 CFRunLoopRunSpecific + 467
22 CoreFoundation 0x018a08db CFRunLoopRunInMode + 123
23 GraphicsServices 0x038a09e2 GSEventRunModal + 192
24 GraphicsServices 0x038a0809 GSEventRun + 104
25 UIKit 0x003ecd3b UIApplicationMain + 1225
26 lead miner sales force 0x0001bd42 main + 130
27 libdyld.dylib 0x020a370d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type ZKSoapException
Thank you for kind replay....
-(IBAction)loginbutton:(id)sender
{
NSString *username=[NSString stringWithFormat:#"%#",usernamefield.text];
NSString *password=[NSString stringWithFormat:#"%#",passwordfield.text];
ZKSforceClient *sforce = [[ZKSforceClient alloc] init];
[sforce login:username password:password];
ZKDescribeSObject *taskDescribe = [sforce describeSObject:#"Task"];
NSLog(#"url for the new Task page is %#", [taskDescribe urlNew]);
[sforce release];
}
in ZKSforce, the login: call (and all other calls that goto the server) will throw a ZKSoapException if the server returns a soap fault, which it'll do if your credentials are invalid (which is what is reported in the stack trace you've shown). You need to use Objective-C's exception handling to catch this exception and process it, e.g.
#try {
[sforce login:username password:password];
ZKDescribeSObject *task = [sforce describeSObject:#"Task"];
} #catch (ZKSoapException *ex) {
NSLog(#"login failed %#", [ex reason]);
// show to user etc, whatever you want to do when login fails.
}
You need to compile with objective-c exceptions enabled for your project, which i believe has been the default for a while now.
In swift you can use this.
let username = "abc#gmail.com"
let password = "1234" + "yourtoken"
let client = ZKSforceClient()
client.performLogin(username, password: password, fail:{ (fail) in
print(fail)
}) { (success) in
print(success)
}
It will give you proper exception handling with fail and success.Hope it will work!!

Parsing JSON and sometimes getting number instead of a string

I have an iPhone app which fetches user information (first name, last name, city) in JSON format from different social networks.
This works mostly well, but one of the social networks returns the city as a number instead of a string (actually I should made one more REST call to map this number to a city name... but for now I just want to display the number).
And when I try to display that number in a UILabel I get the exception (here fullscreen):
2014-02-15 11:24:16.194 MyAuth[8872:a0b] -[__NSCFNumber length]: unrecognized selector sent to instance 0xb074f90
2014-02-15 11:24:16.203 MyAuth[8872:a0b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber length]: unrecognized selector sent to instance 0xb074f90'
*** First throw call stack:
(
0 CoreFoundation 0x01bb15e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x019348b6 objc_exception_throw + 44
2 CoreFoundation 0x01c4e903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3 CoreFoundation 0x01ba190b ___forwarding___ + 1019
4 CoreFoundation 0x01ba14ee _CF_forwarding_prep_0 + 14
5 Foundation 0x015798ed -[NSConcreteMutableAttributedString replaceCharactersInRange:withString:] + 39
6 Foundation 0x0157a55a -[NSConcreteMutableAttributedString initWithString:attributes:] + 293
7 UIKit 0x0084fbc6 -[UILabel _setText:] + 97
8 UIKit 0x0084fd84 -[UILabel setText:] + 40
9 MyAuth 0x0000a296 -[UserViewController viewDidLoad] + 678
10 UIKit 0x007b6318 -[UIViewController loadViewIfRequired] + 696
11 UIKit 0x007b65b4 -[UIViewController view] + 35
12 UIKit 0x007d03e2 -[UINavigationController _startCustomTransition:] + 778
13 UIKit 0x007dd0c7 -[UINavigationController _startDeferredTransitionIfNeeded:] + 688
14 UIKit 0x007ddcb9 -[UINavigationController __viewWillLayoutSubviews] + 57
15 UIKit 0x00917181 -[UILayoutContainerView layoutSubviews] + 213
16 UIKit 0x0070d267 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 355
17 libobjc.A.dylib 0x0194681f -[NSObject performSelector:withObject:] + 70
18 QuartzCore 0x054e12ea -[CALayer layoutSublayers] + 148
19 QuartzCore 0x054d50d4 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
20 QuartzCore 0x054d4f40 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 26
21 QuartzCore 0x0543cae6 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 294
22 QuartzCore 0x0543de71 _ZN2CA11Transaction6commitEv + 393
23 QuartzCore 0x0543e544 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 92
24 CoreFoundation 0x01b794ce __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
25 CoreFoundation 0x01b7941f __CFRunLoopDoObservers + 399
26 CoreFoundation 0x01b57344 __CFRunLoopRun + 1076
27 CoreFoundation 0x01b56ac3 CFRunLoopRunSpecific + 467
28 CoreFoundation 0x01b568db CFRunLoopRunInMode + 123
29 GraphicsServices 0x031a09e2 GSEventRunModal + 192
30 GraphicsServices 0x031a0809 GSEventRun + 104
31 UIKit 0x006a2d3b UIApplicationMain + 1225
32 MyAuth 0x0000ab7d main + 141
33 libdyld.dylib 0x02518725 start + 0
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
So I go to my JSON parsing code:
- (User*)createUserFromJson:(id)json
{
if (![json isKindOfClass:[NSDictionary class]]) {
NSLog(#"Parsing response failed");
return nil;
}
NSDictionary *dict = json[#"response"][0];
User *user = [[User alloc] init];
user.key = kVK;
user.userId = dict[#"uid"];
user.firstName = dict[#"first_name"];
user.lastName = dict[#"last_name"];
user.city = dict[#"city"]; // THE PROBLEMATIC LINE
user.avatar = dict[#"photo_big"];
user.female = (2 == [dict[#"female"] intValue]);
return user;
}
and try to change it to:
user.city = [NSString stringWithFormat:#"%d", dict[#"city"]];
but then I get the compile-time warning (here fullscreen):
Format specifies type 'int' but the argument has type 'id'
So my question is how to solve this issue cleanly (w/o Xcode warnings) and robust (when fetched JSON data happens to be a string)?
The fastest solution is:
[NSString stringWithFormat:#"%#", dict[#"city"]];
which will take the description of the string or the number and convert that into a string.
In the future you may want to use:
if ([1dict[#"city"] isKindOfClass:[NSNumber class]]) { ...
to check what you have received and work with it specifically. i.e. to do your lookup and to not use stringWithFormat: when you actually already have a string (because it's inefficient).

Add empty object to an array

I need to add an empty object to index 0 and index 1 of an array being populated with data from a third party XML feed.
This is my parseXML method, it works.
-(void) parseXML{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"APIKEYHERECANTSHOW YOU"]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *xmlString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSLog(#"The string : %#", xmlString);
NSDictionary *xml = [NSDictionary dictionaryWithXMLString:xmlString];
NSLog(#"The dict:%#", xml);
NSMutableDictionary *PageItem = [xml objectForKey:#"TeamLeagueStanding"];
NSLog(#"PageItem: %#", PageItem);
NSMutableArray *items = [xml objectForKey:#"TeamLeagueStanding"];
NSNull *nullValue = [NSNull null];
[items insertObject:nullValue atIndex:0]; <- THIS MAKES MY APP CRASH
NSLog(#"The array: %#", items);
[self setTableData:items];
}
But when i run this i get a crash with the console output:
2014-02-03 21:24:09.063 Liga Zon Sagres Companion[9645:70b] -[NSNull objectForKey:]: unrecognized selector sent to instance 0x101a85b40
2014-02-03 21:24:09.066 Liga Zon Sagres Companion[9645:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull objectForKey:]: unrecognized selector sent to instance 0x101a85b40'
*** First throw call stack:
(
0 CoreFoundation 0x000000010192a795 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010168d991 objc_exception_throw + 43
2 CoreFoundation 0x00000001019bbbad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x000000010191c09d ___forwarding___ + 973
4 CoreFoundation 0x000000010191bc48 _CF_forwarding_prep_0 + 120
5 Liga Zon Sagres Companion 0x000000010000ee20 -[StandingsTableViewController tableView:cellForRowAtIndexPath:] + 256
6 UIKit 0x00000001003bbb8a -[UITableView _createPreparedCellForGlobalRow:withIndexPath:] + 348
7 UIKit 0x00000001003a3836 -[UITableView _updateVisibleCellsNow:] + 2297
8 UIKit 0x00000001003b4381 -[UITableView layoutSubviews] + 207
9 UIKit 0x000000010034bb27 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 354
10 QuartzCore 0x0000000102081a22 -[CALayer layoutSublayers] + 151
11 QuartzCore 0x0000000102076589 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 363
12 QuartzCore 0x0000000102081956 -[CALayer layoutIfNeeded] + 162
13 UIKit 0x00000001003ebfc2 -[UIViewController window:setupWithInterfaceOrientation:] + 264
14 UIKit 0x000000010032ab4d -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:isRotating:] + 4360
15 UIKit 0x0000000100329a3f -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:] + 36
16 UIKit 0x000000010032998f -[UIWindow _setRotatableViewOrientation:updateStatusBar:duration:force:] + 101
17 UIKit 0x0000000100328c9e -[UIWindow _updateToInterfaceOrientation:duration:force:] + 377
18 UIKit 0x00000001003dfd4a -[UIViewController _tryBecomeRootViewControllerInWindow:] + 147
19 UIKit 0x0000000100323a87 -[UIWindow addRootViewControllerViewIfPossible] + 506
20 UIKit 0x0000000100323bd5 -[UIWindow _setHidden:forced:] + 275
21 UIKit 0x000000010032cca2 -[UIWindow makeKeyAndVisible] + 51
22 UIKit 0x00000001002eb0c8 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1449
23 UIKit 0x00000001002eebe8 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 660
24 UIKit 0x00000001002ffaab -[UIApplication handleEvent:withNewEvent:] + 3092
25 UIKit 0x00000001002fff1e -[UIApplication sendEvent:] + 79
26 UIKit 0x00000001002f02be _UIApplicationHandleEvent + 618
27 GraphicsServices 0x0000000102578bb6 _PurpleEventCallback + 762
28 GraphicsServices 0x000000010257867d PurpleEventCallback + 35
29 CoreFoundation 0x00000001018ac819 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41
30 CoreFoundation 0x00000001018ac5ee __CFRunLoopDoSource1 + 478
31 CoreFoundation 0x00000001018d5ab3 __CFRunLoopRun + 1939
32 CoreFoundation 0x00000001018d4f33 CFRunLoopRunSpecific + 467
33 UIKit 0x00000001002ee4bd -[UIApplication _run] + 609
34 UIKit 0x00000001002f0043 UIApplicationMain + 1010
35 Liga Zon Sagres Companion 0x0000000100011f93 main + 115
36 libdyld.dylib 0x0000000102f815fd start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Any ideas how to solve this? Thank you.
The error is coming from your StandingsTableViewController tableView:cellForRowAtIndexPath: method. Your data is giving you an NSNull instance where you expect an NSDictionary.
Since you explicitly add the NSNull object you need to update your cellForRow... method to check to see if the object is an NSNull instance before assuming it is an NSDictionary.
Something like this:
NSDictionary *data = self.tableData[someIndex];
if ([data isKindOfClass:[NSDictionary class]]) {
// process the data as usual
} else {
// This is probably the NSNull object, ignore it or handle appropriately
}

Resources