Crash with SBJSON library - objective-c

following code is copied from Stig Brautaset JSON library - I removed the comments to be more clear.
#interface NSString (NSString_SBJSON)
- (id)JSONFragmentValue;
- (id)JSONValue;
#end
I have a crash when I call:
NSString *jsonString = [request responseString];
...
NSDictionary *results = [jsonString JSONValue];//here is the crash with invalid selector.
I added this:
if (![jsonString respondsToSelector:#selector(JSONValue)])
{
NSLog(#"fix this!!!\n");
}
and the message is shown. Do you have any idea why this function in not called?
Thanks!
EDIT: I compile JSON framework as a static lib. The call is made in the same lib.
When I compile it as exe it runs without any problem.

You need to both link your static library and your final executable with the -ObjC linker option.
The -JSONValue method is implemented as a category on the NSString class in the file NSString+SBJSON.m file. Because of how the dynamic runtime works in Objective-C, categories defined in static libraries don't get loaded up unless you link with the -Objc flag. If the category doesn't get loaded, then dynamic binding fails, and you get the dreaded "doesn't respond to selector" exception.

Related

Objective-C library category methods not working in Swift app environment

I have an Objective-C iOS app that is composed of a workspace (AuthPort.xcworkspace) with a project (AuthPort.xcodeproj) and an Objective-C SDK project ("ANet SDK.xcodeproj") which builds a library called “libAnet SDK.a”).
“libAnet SDK.a” is linked in with the AuthPort target Build Phases.
In the SDK, there are some categories on NSString which get built into “libAnet SDK.a”. They are named:
NSString+stringWithXMLTag.h and NSString+stringWithXMLTag.m
.
.
.
etc.
Some code in the AuthPort.xcodeproj calls code in the library which in turn calls these category methods.
It all works smoothly in the above Objective-C environment!
Now…I am re-writing the AuthPort code in Swift in a new workspace with a new project and also using the Objective-C SDK which builds “libAnet SDK.a”
So, I created a new Swift Xcode project called AuthPort.xcodeproj and added it to a new workspace called AuthPort.xcworkspace. I also added the authorize.net SDK ("ANet SDK.xcodeproj", written in Objective-C) to the project.
So far, so good. I created an AuthPort-Bridging-Header.h file and imported all the headers from the SDK (without the category headers - more on this later). I also linked in “libAnet SDK.a” in the Build Phases of the AuthPort target.
AuthPort builds and runs with no errors or warnings.
Now, in viewDidLoad of the primary view controller I added code to access library methods to register a new device with the company, authorize.net:
var r: MobileDeviceRegistrationRequest = MobileDeviceRegistrationRequest()
an.mobileDeviceRegistrationRequest(r)
These two calls are the same library methods in both Objective-C and Swift versions. The last method calls other library methods which call methods from the NSString category above.
When I put breakpoints in a category method in the Objective-C environment (all Objective-C code in app and library), the program breaks as expected and I can step through the code.
When I put breakpoints in a category method in the Swift environment (Swift app project with Objective-C library), the debugger never enters a category method. At one point in the execution, the app SIGABRT’s with the following:
2015-04-21 12:25:47.388 AuthPort[4743:2404231] +[NSString stringWithXMLTag:andValue:]: unrecognized selector sent to class 0x38450e18
2015-04-21 12:25:47.390 AuthPort[4743:2404231] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NSString stringWithXMLTag:andValue:]: unrecognized selector sent to class 0x38450e18'
* First throw call stack:
(0x29a0a5a7 0x3792fc77 0x29a0f989 0x29a0d949 0x2993eb68 0xd9e4b 0xc301f 0xdd507 0xc4725 0xc44b1 0xb8f28 0xb9e60 0x2cf0eb65 0x2cf0e8d5 0x2d031c43 0x2d031ac7 0x2d03196b 0x2cf1b5f1 0x2d0357b3 0x2d03491f 0x2cf2433b 0x2cf159e1 0x2cf15003 0x2cf14e6b 0x2cf148ef 0x2cf121ef 0x2cf7c031 0x2d16e34f 0x2d170781 0x2d17b1a9 0x2d16f063 0x302880a1 0x299d125d 0x299d0521 0x299cecbf 0x2991bb51 0x2991b963 0x2cf72b8f 0x2cf6dc91 0xb5290 0x37ed8aaf)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
The [NSString stringWithXMLTag:andValue:] is from the category added by the library onto NSString.
The library method stringOfXMLRequest calls the category method stringWithXMLTag:andValue:
- (NSString *) stringOfXMLRequest {
NSString *s = [NSString stringWithFormat:#""
#"<merchantAuthentication>"
#"%#" //name (optional)
#"%#" //fingerPrint type Object #"%#" //transactionKey or
#"%#" //sessionToken or
#"%#" //password
#"%#" //mobileDeviceId (optional)
#"</merchantAuthentication>",
(self.name ? [NSString stringWithXMLTag:#"name" andValue:self.name] : #""),
(self.fingerPrint ? [self.fingerPrint stringOfXMLRequest] : #""),
(self.transactionKey ? [NSString stringWithXMLTag:#"transactionKey" andValue:self.transactionKey] : #""),
(self.sessionToken ? [NSString stringWithXMLTag:#"sessionToken" andValue:self.sessionToken] : #""),
(self.password ? [NSString stringWithXMLTag:#"password" andValue:self.password] : #""),
(self.mobileDeviceId ? [NSString stringWithXMLTag:#"mobileDeviceId" andValue:self.mobileDeviceId] : #"")];
return s;
}
The SIGABRT doesn't happen until the second call is made to stringWithXMLTag:andValue: for the transitionKey.
The exact same library code is run in both environments.
Here’s the code from stringWithXMLTag:andValue: which is never seen in the debugger:
+ (NSString *)stringWithXMLTag:(NSString *)t andValue:(NSString *)v {
if (v == nil) {
return #"";
}
else {
v = [NSString stringWithEscapedXMLValue:v];
return [NSString stringWithFormat:#"<%#>%#</%#>", t, v, t];
}
}
The problem is solely within the library code where a library method calls another library method which calls a library category method which is never entered in the debugger in the Swift version.
I also tried adding the category header files in the bridging header and adding -ObjC and -all_load to the Other Linker Flags for AuthPort. No luck.
I’ve searched the net for 2 days with no luck. Hopefully one of you will have seen this behavior.
I'm building using Xcode 6.3 and iOS 8.3 (deploying on iOS 8.2).
Thanks.
Check that:
you've added you category to the Umbrella Framework of your Framework project. Use #import "your.h"
I've marked the .h file from the category as public. Select the .h > Identity and Type > Target Membership > Public
In your project, set correct Framework Search Paths

Xcode 4.3.2 ans SBJSON

I am developing an iOS application. i am using Xcode 4.3.2 and SBJSON, i have imported all the JSON classes to my project and it compiles fine, but when i navigate in the project , i have a crash like this : -[__NSCFDictionary JSONRepresentation]: unrecognized selector sent to instance
and in my code i am doing like this : NSString *jsonString = [dic JSONRepresentation];
dic is a NSDictionnary.
Thanks for your answer
Try following code, where responseString is your response string that you have received from parser.
SBJSON *json = [SBJSON new];
NSMutableDictionary *jsonDictionary = (NSMutableDictionary*) [json objectWithString:responseString error:nil];
JSONRepresentation is not part of Apple's NSDictionary class.
It's a very useful category included in the JSON Api.
=> Are you using this JSON Api ?
=> Do you import correctly the JSON Api header file ?
=> If you have a look to the code, is the JSONRepresentation category declared as :
#interface NSDictionary (NSDictionary_SBJsonWriting)
/// Returns a string containing the receiver encoded in JSON.
- (NSString *)JSONRepresentation;
#end
with the corresponding code in the .m file ?
EDIT :
If you are making a static library and using JSON Api in it (or other API), you should make some changes in your library's build settings and in the calling project's ones.
in your library build settings, check the line "other linker flags". The value should be : "-ObjC"
in the calling project's build setting, the value of "other linker flags" should be "-all_load"

ObjC / iOS: NSCFString not NSString?

I'm making a small iOS application which requests a JSON file with ASIHTTPRequest and I want it to be parsed by JSONKit. I'm using the following code:
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar{
// yada yada
NSURL *url = [NSURL URLWithString:#"http://localhost/file.json"]; // the file is a valid Json
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request setTimeOutSeconds:20]; // Response takes too long on local machine
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request {
responseString = [request responseString]; // request type: ASIREQUEST, responseString is declared as NSString
NSLog(#"%# \n", [responseString class]); // NSCFString
NSDictionary *deserializedData = [responseString objectFromJSONString];
}
However, I'm seeing the following exception when the application runs:
[7646:207] -[NSCFString objectFromJSONString]: unrecognized selector sent to instance 0xdba0000
[7646:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-`[NSCFString objectFromJSONString]: unrecognized selector sent to instance 0xdba0000'`
What could be causing this exception? Why is it showing that I'm using an NSCFString here, even though I'm specifying an NSString?
NSString is something known as a class cluster. What this basically means is that when you construct an NSString you will get back something that is guaranteed to behave like an NSString as defined in its documentation, but could be implemented by some other class. In this case NSCFString is the type the system decided to return.
Anything that takes an NSString will take anything that is part of that cluster.
From looking at your code, ASI must define objectFromJSONString as part of a category on NSString. This will work perfectly fine with the clustering system, are you loading a static library that includes ASI? If so you need to add -all_load and -ObjC to your linker flags in order to get categories working from external libraries.
Edit:
Based on your comments then your solution is making sure the JSON library is included in your project. I'm assuming the objectFromJSONString was copy/pasted from some sample somewhere. It is part of the JSONKit library. Make sure both JSONKit.m and JSONKit.h are present in your project.
Update:
JSONKit is included (both .h and .m) but still the same error...
you are right, i just copied it because it seemed to do its job :)
You've included JSONKit.h, but you forgot to include JSONKit.m in the project. It compiles fine, but the implementation isn't there at runtime.
I had same problem because I enabled ARC and JSonKit doesn't support it after rectifying it worked.
Also when you include JSonKit.h and .m files please make sure you check target box too.
JSONKit declares a category called JSONKitDeserializing on NSString in order to allow you to call objectFromJSONString. Make sure you've included JSONKit.h in your source file where you are trying to use objectFromJSONString.

twitpic API GSTwitPicEngine error while setAccessToken

I tried to use GSTwitPicEngine class https://github.com/Gurpartap/GSTwitPicEngine for sharing image on twitter
but its giving error
As we have to set [twitpicEngine setAccessToken:token];
if I am right, I am using _accessToken of class SA_OAuthTwitterEngine as token
_accessToken was private in class SA_OAuthTwitterEngine, I set it to public and also
#property (nonatomic, readonly) OAToken *accessToken;
#synthesize accessToken = _accessToken;
and then in action
twitPicEngine = [GSTwitPicEngine twitpicEngineWithDelegate:self];
[twitPicEngine setAccessToken:twitterObj.accessToken];
[twitPicEngine uploadPicture:[shareDict objectForKey:#"image"] withMessage:[shareDict objectForKey:#"image_msg"]];
But Application getting crash while setAccessToken with log
-[OAToken parameters]: unrecognized selector sent to instance 0x6327e30
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[OAToken parameters]: unrecognized selector sent to instance 0x6327e30'
Please help if you able to find any thing wrong
Amit Battan
Unfortunately, GSTwitPicEngine is not using the same version of oauth-consumer than the fabulous Twitter+Oauth library (SAOAuthTwitterEngine). I assume you are using that library for posting messages to twitter.
The crash is because OAToken from Twitter+Oauth doesn´t implement the "parameters" method.
Today I spent the entire morning tweaking the several libraries to avoid crashes.
Here you can download a sample project I created for posting a twitpic photo to twitter with a message.
TestTwitpic
The project has all the latest versions of all libraries from github.
Instructions for making my TestTwitpic project work:
In TestTwitpic-Prefix.pch set the variables for:
#define kTwitterOAuthConsumerKey #""
#define kTwitterOAuthConsumerSecret #""
#define kTwitPicAPIKey #""
In RootViewController you can change these lines to your needs. To change the photo:
//change [UIImage imageNamed:#"image.jpg"] for whatever UIImage you want to upload
//change #"my photo" for whatever title you want for your photo in twitpic website
[twitpicEngine uploadPicture:[UIImage imageNamed:#"image.jpg"] withMessage:#"my photo"];
and this one to change message sent to twitter:
//I post to twitter the title of the photo and the twitpic url but you can post whatever you want
[engine sendUpdate:[NSString stringWithFormat:#"%# %#", [[[response objectForKey:#"request"] userInfo] objectForKey:#"message"], [[response objectForKey:#"parsedResponse"] objectForKey:#"url"]]];
If you want to create your own project based on this sample. Do the following:
Import into your project (drag and drop) the Twitpic folder with all the libraries that are inside.
Add these frameworks to your project:
CoreGraphics
libz.1.2.3
libxml2
MobileCoreServices
SystemConfiguration
CFNetwork
Security
In Build Settings add "$SDKROOT/usr/include/libxml2" to the "Header Search Paths" (mark it as recursive)
In Build Settings add -lxml2 to "Other linker flags"
If you want to know what I did for fixing the libraries, I will tell you more or less what I remember I did:
Import Twitter+Oauth, GSTwitPicEngine, OARequestHeader, TouchJSON, and ASIHTTPRequest libraries.
Set GSTwitPicEngine to use TouchJSON instead of YAJL.
Added the category NSString+URLEncoding from oauth-consumer github project as OARequestHeader was missing it.
Modified all occurrences of NSDictionary* foo = [toke parameters] inside OARequestHeader with the line:
NSDictionary *foo = [NSDictionary dictionaryWithObject:[token key] forKey:#"oauth_token"];
Created a method getAccessToken in SAOAuthTwitterEngine to return the private _accessToken variable.
In requestFinished: inside GSTwitPicEngine
change the line:
response = [[CJSONDeserializer deserializer] deserialize:responseString error:&error];
with the line:
response = [[CJSONDeserializer deserializer] deserialize:[responseString dataUsingEncoding:NSUTF8StringEncoding] error:&error];
as GSTwitPicEngine wrongly assumed deserialize:error: method accepts an NSString instead of an NSData.
You can set Access token & Access Secret for twitpic after getting from twitter engine i.e
SA_OAuthTwitterEngine.m
(void) setAccessToken: (OAServiceTicket *) ticket withData: (NSData *) data
Create object of "GSTwitPicEngine.m" class in "SA_OAuthTwitterEngine.m" & pass Access token & Access Secret to "GSTwitPicEngine.m" and set delegate methods of "GSTwitPicEngine.m" in "SA_OAuthTwitterEngine.m"
And one more change...
must cross check URLEncoding while genrating OAuth Header i.e
[requestHeader generateRequestHeaders]
this will be according to "OAuthConsumer" classes in Twitter Library

Categories in Objective-C aren't working

I'm developing an iOS application that needs to deploy to iOS 3.1.3. I need to extend some of the functionality of the NSData class and am using the following code inside NSData+Base64 (truncated to show the interesting part):
NSData+Base64.h
[...]
#interface NSData (Base64)
+ (NSData *)dataFromBase64String:(NSString *)aString;
- (NSString *)base64EncodedString;
#end
NSData+Base64.m
#implementation NSData (Base64)
[...]
//
// base64EncodedString
//
// Creates an NSString object that contains the base 64 encoding of the
// receiver's data. Lines are broken at 64 characters long.
//
// returns an autoreleased NSString being the base 64 representation of the
// receiver.
//
- (NSString *)base64EncodedString
{
size_t outputLength;
char *outputBuffer =
NewBase64Encode([self bytes], [self length], true, &outputLength);
NSString *result =
[[[NSString alloc]
initWithBytes:outputBuffer
length:outputLength
encoding:NSASCIIStringEncoding]
autorelease];
free(outputBuffer);
return result;
}
#end
However, when I try to message this selector:
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
NSString *hash = [HMAC base64EncodedString];
I get the following error:
-[NSConcreteData base64EncodedString]: unrecognized selector sent to instance 0x6146e70
2010-11-09 13:44:41.443 SpringboardApplication[21318:40b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConcreteData base64EncodedString]: unrecognized selector sent to instance 0x6146e70'
I read a lot about iOS 3.1.x having problems with categories. I tried adding the flags -all_load and -ObjC (both separately and together) to no avail. I would really appreciate some direction of how to get this selector to work.
Thanks!
It really seems like your category isn't being compiled or linked into the same target that you're using it from. You should make sure that NSData+Base64.m is marked to be compiled by the same target that it's being used from by getting info on the two files and comparing the targets they're assigned to.
A test you can perform is to add a line with an #error error message to NSData+Base64.m, which will cause the build to fail when it gets to that file. Like this:
#error We're now compiling NSData+Base64.m
Then look and see which target fails to compile.
I had the same issue with ARC project which was linking with non-ARC module having category extension.
Fixed the issue by adding "Other Linker Flags: -all_load" in parent ARC project.
Have you #imported the header file for your category? I know it sounds simple, but I forget nearly every time.
There is a great post on The Carbon Emitter about about handling categories in iOS. It details an easy way to handle importing categories to your project.
Make a file containing all of your category imports, in this example it is Extensions.h:
#import "NSDate+Formatting.h"
#import "UIFonts+MyFonts.h"
#import "UIViewController+Tourbot.h"
Add import your file in AppName-Prefix.pch:
#import <Availability.h>
#ifndef __IPHONE_3_0
#warning "This project uses features only available in iPhone SDK 3.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>
#import <CoreText/CoreText.h>
#import "Extensions.h" // Add import here
#endif
In My case when I got this error I simply added the .m file in the Compiled resources, and it get worked. This can be achieved by selecting target project->Build Phases->Compile Sources. Then you click on the + button from its bottom left. In this case you may add 'NSData+Base64.m' file to the compile sources. Then you clean your project and run. I guess this may help.