Objective-C errors after getting the IAP product response - objective-c

This code is from the Phonegap Code: IAP Plugin. The error happens on the line of the code right after the "sent js". All the elements sent to the function are non-nil except for the last one 'nil'. I even logged them out to make sure they were sent. This code is right out of the plugin (https://github.com/usmart/InAppPurchaseManager-EXAMPLE) and has not been modified except for the logging. In the debugger i saw that none of the objects were nil, so i don't understand why the error is happening.
Here is the error:
[__NSArrayI JSONRepresentation]: unrecognized selector sent to
instance 0xdc542d0
2013-02-13 23:26:17.209 GoblinSlots[4519:707] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:
'-[__NSArrayI JSONRepresentation]: unrecognized selector sent to
instance 0xdc542d0'
here is the code:
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse: (SKProductsResponse *)response
{
NSLog(#"got iap product response");
for (SKProduct *product in response.products) {
NSLog(#"sending js for %#", product.productIdentifier);
NSLog(#" title %#", product.localizedTitle );
NSLog(#" desc%# - %#", product.localizedDescription, product.localizedPrice );
NSArray *callbackArgs = [NSArray arrayWithObjects:
NILABLE(product.productIdentifier),
NILABLE(product.localizedTitle),
NILABLE(product.localizedDescription),
NILABLE(product.localizedPrice),
nil ];
NSLog(#"sent js");
NSString *js = [NSString stringWithFormat:#"%#.apply(plugins.inAppPurchaseManager, %#)", successCallback, [callbackArgs JSONSerialize]];
NSLog(#"js: %#", js);
[command writeJavascript: js];
}

All the stuff to do JSON serialization seems to be already included with the Cordova plugins.
There's no need to download and install yet another JSON library.(a)
It appears that PhoneGap is in the process of switching from SBJson to JSONKit.(b)
PhoneGap is also in the process of changing all the JSON methods to use a "cdvjk_" prefix. (c)
As far as I can tell, something didn't quite go right during those changes.
What I did was edit the file Plugins/InAppPurchaseManager.m , where I made these changes:
Add the line
#import <Cordova/CDVJSON.h>
Replace the line
return [self respondsToSelector:#selector(cdvjk_JSONString)] ? [self cdvjk_JSONString] : [self cdvjk_JSONRepresentation];
with
return [self JSONString];
. (What's the right way to push this or a better bugfix back to the nice PhoneGap people?)

JSONRepresentation is a category that SBJson adds so you have to include SBJson.h in the class that uses it.

Related

+[NSData bookmarkDataWithContentsOfURL:]: unrecognized selector sent to class

I am trying to resolve an alias file's original path using Objective-C(or maybe C++; it's an .mm file). Not being very much familiar, I am somehow missing + and - methods' usage. I am aware of them being class and instance methods respectively, but in practice, the following the code, with the indicated lines give me following warning and error(at build):
Class method '+bookmarkDataWithContentsOfURL:' not found (return type defaults to 'id')
-
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NSData bookmarkDataWithContentsOfURL:]: unrecognized selector sent to class 0x7fff88942cb8'
with 0x7fff88942cb8 being the NSData address as per lldb.
Which files should I make the changes in, to get bookmarkDataWithContentsOfURL:error: and URLByResolvingBookmarkData to work?
void *pathclass::resolveAliasFromURL(const char *filepath) const
{
NSError *error = nil;
NSString *filepathh = [[NSString alloc] initWithUTF8String:filepath];
NSData *bookmarkk = [NSData bookmarkDataWithContentsOfURL:filepathh]; /*problematic line*/
BOOL isstale = NO;
NSURL *actual = [NSURL URLByResolvingBookmarkData:bookmarkk bookmarkDataIsStale:isstale error:error];/*another problematic line, but build fails already*/
NSString *urlString = [actual absoluteString];
NSLog(#"%#",urlString);
}
If there are any other faults, please point out.
Your call to bookmarkDataWithContentsOfURL: is wrong in a few ways:
The signature looks like this:
+ (NSData *)bookmarkDataWithContentsOfURL:(NSURL *)bookmarkFileURL error:(NSError * _Nullable *)error;
First, the first parameter is of type NSURL*, not NSString*. Next, you miss off the error parameter completely (despite defining a variable for it). Lastly, the method is a class method on NSURL not NSData (NSData* is the return type).
So, first, make your file path into an NSURL*:
NSURL* bookmarkUrl = [NSURL URLWithString:filepathh];
Then, call the function using the proper arguments:
NSData *bookmarkk = [NSURL bookmarkDataWithContentsOfURL:bookmarkUrl error:&error];
You should check the returned value against nil - if it's nil, then an error occurred, and the error information will be contained inside error.
The documentation is quite helpful.
Your call to URLByResolvingBookmarkData:options:relativeToURL:bookmarkDataIsStale:error: has similar problems: you are missing several parameters, the first parameter should be NSURL, etc. Again, the documentation should help.

Passing NSArray of custom objects as NSData via WatchConnectivity's sendMessageData

Once a WKInterfaceController's didAppear function is fired, I send an empty NSData to WCSession's default session with the sendMessageData callback function:
// WKInterfaceController
NSData *emptyData = [[NSData alloc] init];
[[WCSession defaultSession] sendMessageData:emptyData replyHandler:^(NSData *replyMessageData) {
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:replyMessageData];
} errorHandler:^(NSError *error) {
NSLog(#"WATCH: Error from replyData %#", error);
}];
The emptyData NSData object is sent because sendMessageData: is a non-null argument. I only use it to be able to fire WCSession's Delegate method, didReceiveMessageData on the iOS app. Then the replyHandler in that very function sends the appropriate data back to the replyHandler to the WKInterfaceController.
// UITableViewController
- (void)session:(WCSession *)session didReceiveMessageData:(NSData *)messageData replyHandler:(void (^)(NSData * _Nonnull))replyHandler
{
[self loadData:nil onSuccess:^(NSArray *tips) {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:tips];
replyHandler(data);
}];
}
The problem I'm having is that I get a crash on the following line in the WKInterfaceController
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:replyMessageData];
Here's the error I get:
* Terminating app due to uncaught exception
'NSInvalidUnarchiveOperationException', reason: '*
-[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (Tip) for key (NS.objects); the class may be defined in source
code or a library that is not linked'
What I've found so far:
The NSArray I'm trying to pass is made of custom objects (Tip.m). I know that all of the objects within the NSArray must conform to the NSCoding protocol (How to convert NSArray to NSData?), which I have done properly in my opinion. I've encoded and decoded every variable and object within the object with initWithCoder and encodeWithCoder.
My Tip.m object should be added to my WatchKit Extension (NSInvalidUnarchiveOperationException cannot decode object error in Apple Watch extension). Adding the Tip.m file only gives me: "Undefined symbols for architecture i386" from other objects.
Sorry for the long post but I've tried everything to find a solution to this problem, without success. Hope this helps more people that are having issues with WatchConnectivity Framework.
I solved this temporarily by using didReceiveMessage (the NSDictionary version instead of the NSData).
I sent a manually created NSDictionary of a single NSArray that held regular NSStrings of my previous custom objects.
I have the same scenario and reached the same problem. After some searching (without any luck) and experimenting, I've solved it by adding the -all_load flag to the linker flags in the extension target.

How to deal with an empty object {} in RestKit

The response I sometimes get from the server is a JSON representing an empty object like this {}
I've read this question/answer over here already, which states I should implement the willMapData delegate function and point the *mappableData somewhere else. The thing is I can't figure out what should I assign to *mappableData so that my app won't crash.
I've tried this
- (void)objectLoader:(RKObjectLoader *)loader willMapData:(inout id *)mappableData
{
id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType:RKMIMETypeJSON];
*mappableData = [parser objectFromString:#"{\"unknownObject\":\"\"}" error:nil];
}
But nevertheless my app crashes with a rather pissing
'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[0]
Can you help me out?
UPDATE
Turning on RKDebug messages gives me this in the console:
Performing object mapping sourceObject: {
}
and targetObject: (null)
then the code reaches RKObjectMapper.m:
if (mappableData) {
id mappingResult = [self performMappingForObject:mappableData atKeyPath:#"" usingMapping:mappingsForContext];
foundMappable = YES;
results = [NSDictionary dictionaryWithObject:mappingResult forKey:#""];
}
but mappingResult over there comes back nil... so the app crashes when it tries to create an NSDictionary with a nil object.
Break up the assignment into two lines.
SomeDataType *object = [parser objectFromString:#"{\"unknownObject\":\"\"}" error:nil];
if(object){
*mappableData = object;
}else{
// You've got nil, do something with it
}
Now you can check for nil values and take the appropriate action. What that action is depends on the context of the crash.

how to solve run time error of [NSURL fileURLWithPath:error:]: unrecognized selector sent to class?

I am beginner in IPhone Developing. I want play sound. so, that's why I have apply this code
(void)viewDidLoad
{
NSError* err;
path=[[NSBundle mainBundle] pathForResource:#"Animalfile" ofType:#"plist"];
dict=[NSDictionary dictionaryWithContentsOfFile:path];
NSArray *animalaudio=[dict valueForKey:#"audio"];
NSString *audiolist=[animalaudio objectAtIndex:currentsound];
AVAudioPlayer *audio=[[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:audiolist error:&err]];
audio.delegate=self;
[audio play];
}
and I have got the run time error of
[NSURL fileURLWithPath:error:]: unrecognized selector sent to class 0x182121c
2012-07-14 14:51:21.711 plistdemo[1236:10703] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: '+[NSURL fileURLWithPath:error:]:
unrecognized selector sent to class 0x182121c'
terminate called throwing an exceptionsharedlibrary apply-load-rules all
so, give any suggestion and source code which apply in my code
current documentation for NSURL doesn't list any such method like 'fileURLWithPath:error:'... seems like its either deprecated or incorrect.
instead try using something like:
[NSURL fileURLWithPath:audioList]
hope it helps...

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.