Send NSMutableArray of NSMutableDictionary data using NSURLRequest - objective-c

This is my request body
[
{
"DealId":677304,
"CustomerId":328702,
"CouponQtn":1,
"PaymentType":"MPD",
"CustomerMobile":"01670234032",
"CustomerAlternateMobile":"01670234032",
"CustomerBillingAddress":"IT test order.......",
"Sizes":"not selected",
"Color":"",
"DeliveryDist":62,
"CardType":"Manual",
"OrderFrom":"iOS",
"MerchantId":14025,
"OrderSource":"app",
"AdvPaymentType":0,
"AdvPayPhoneId":0,
"deliveryCharge":45,
"OrderCouponPrice":500
}
]
I am trying to send NSMutableArray of NSMutableDictionary data using NSURLRequest in a Restful api but my app is getting exceptions like
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM bytes]: unrecognized selector sent to instance 0x600000855e40'.
My Parsing code :
-(NSDictionary*)getDataByPOST:(NSString*)url parameter:(id)parameter{
NSDictionary *dictionaryData;
NSDictionary *dic;
Reachability *reachTest = [Reachability reachabilityWithHostName:#"www.apple.com"];
NetworkStatus internetStatus = [reachTest currentReachabilityStatus];
if ((internetStatus != ReachableViaWiFi) && (internetStatus != ReachableViaWWAN)){
dictionaryData = [[NSDictionary alloc] initWithObjectsAndKeys:#"error",#"status",#"No Network",#"message",nil];
dic = [NSDictionary dictionaryWithObjectsAndKeys:dictionaryData, #"response",nil];
return dic;
}
else{
NSURL *s =[self getAbsoluteURL:url];
NSMutableURLRequest *requestURL = [NSMutableURLRequest requestWithURL:s cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:900.00];
//NSLog(#"%#",requestURL);
[requestURL setHTTPMethod:#"POST"];
NSError *error=nil ;
if ([parameter isKindOfClass : [NSString class]]) {
[requestURL setHTTPBody:[parameter dataUsingEncoding:NSUTF8StringEncoding]];
}
else if([parameter isKindOfClass:[NSDictionary class]]) {
[requestURL setHTTPBody:parameter];
}
else {
[requestURL setHTTPBody:parameter];
}
NSHTTPURLResponse *response;
NSError *error1=nil;
// NSLog(#"%#\n\n%#",s,parameter);
NSData *apiData = [NSURLConnection sendSynchronousRequest:requestURL returningResponse:&response error:&error1];
if (!apiData) {
NSLog(#"Error: %#", [error localizedDescription]);
return NO;
}
if (response.statusCode == 0) {
dictionaryData = [[NSDictionary alloc] initWithObjectsAndKeys:#"error",#"status",#"Server Error",#"message",nil];
return dic;
}
else if(response.statusCode == 404) {
dictionaryData= [[NSDictionary alloc] initWithObjectsAndKeys:#"error",#"status",#"Server is Currently Down.",#"message", nil];
return dic;
}
else {
dictionaryData = [NSJSONSerialization JSONObjectWithData:apiData options:0 error:&error];
}
}
return dictionaryData;
}
And here is my api calling code
tempDic = [apiCom getNodeDataByPOST:CART_ORDER_URL parameter:orderArray];
Here orderArray is NSMutableArrray contains NSMutableDictionary objects.
Thanks

You got the error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM bytes]: unrecognized selector sent to instance 0x600000855e40'.
This means that at some point in your code you thought you could use the bytes method (getter) on a object that has it, but in fact the object is a NSMutableArray one, and since it doesn't implement bytes, your code crash with that error. Now, bytes is for instance a NSData method. I'll get back to it.
As a developer, you need to locate the lines causing that crashes. Even if you don't understand it, if you pinpoint the issue, others might be happier to help because they can focus on the issue and not lose time looking on big portion of code hoping to find the issue. And even if it's not for others, do it for you.
That's not a negative critic, that's a tip.
Culprit lines:
if ([parameter isKindOfClass : [NSString class]]) {
[requestURL setHTTPBody:[parameter dataUsingEncoding:NSUTF8StringEncoding]];
}
else if([parameter isKindOfClass:[NSDictionary class]]) {
[requestURL setHTTPBody:parameter];
}
else {
[requestURL setHTTPBody:parameter];
}
Doc of NSMutableURLRequest:
#property(copy) NSData *HTTPBody;
So clearly, if parameter is a NSDictionary, or a NSArray you'll get that same crash, with either: -[__NSDictionary bytes]: unrecognized selector sent to instance (or similar, with a I or a M somewhere in the class name for Mutable/Immutable or Single for optimized Dictionary/Array, etc.)
Now, it depends on the doc of your Web API:
A common usage is to use JSON:
else if([parameter isKindOfClass:[NSDictionary class]] || [parameter isKindOfClass:[NSArray class]]) {
[request setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameter options:0 error:nil]];
}
I used nil for the error, but it might be interesting to check its value in case of failure.

Related

Native Facebook/iOS6 integration: Cocoa error 3840 when trying to get profile picture

I am currently using only Social.framework (no FacebookSDK) and getting starting with requesting and getting access to basic user data. Here's all the code I have (with a few properties declared outside, as you'll notice). Everything works fine in terms of getting the right permissions, but I'm getting the following output error when asking for user's profile picture:
2013-01-27 21:28:44.324 TestApp[9230:1a703] Account saved to accountStore
2013-01-27 21:28:45.002 TestApp[9230:1d603] (null)
2013-01-27 21:28:45.003 TestApp[9230:1d603] Request error: The operation couldn’t be completed. (Cocoa error 3840.)
And here is the code:
- (IBAction)btnFbLoginPressed:(id)sender
{
ACAccountType *fbAccountType = [self.accountStore accountTypeWithAccountTypeIdentifier: ACAccountTypeIdentifierFacebook];
NSArray *permissions = #[#"email"];
self.requestAccessOptions = #{ACFacebookAppIdKey:FB_API_KEY, ACFacebookPermissionsKey:permissions, ACFacebookAudienceKey:ACFacebookAudienceOnlyMe};
[self.accountStore requestAccessToAccountsWithType:fbAccountType options:self.requestAccessOptions completion:^(BOOL granted, NSError *e) {
if (granted && e == nil) {
NSArray *readPermissions = #[#"user_photos"];
NSDictionary *readAcccessOptions = #{ACFacebookAppIdKey:FB_API_KEY, ACFacebookPermissionsKey:readPermissions, ACFacebookAudienceKey:ACFacebookAudienceOnlyMe};
[self.accountStore requestAccessToAccountsWithType:fbAccountType options:readAcccessOptions completion:^(BOOL granted, NSError *e) {
if (granted && e == nil) {
NSArray *accounts = [self.accountStore accountsWithAccountType:fbAccountType];
self.facebookAccount = [accounts lastObject];
[self.accountStore saveAccount:self.facebookAccount withCompletionHandler:^(BOOL success, NSError *error) {
if (error != nil || !success) {
NSLog(#"Error saving account to accountStore: %#", error.localizedDescription);
} else {
NSLog(#"Account saved to accountStore");
}
}];
NSString *uid = [NSString stringWithFormat:#"%#", [[self.facebookAccount valueForKey:#"properties"] valueForKey:#"uid"]];
NSString *url = [NSString stringWithFormat:#"https://graph.facebook.com/%#/picture", uid];
NSURL *profilePictureURL = [NSURL URLWithString:url];
SLRequest *profilePictureRequest = [SLRequest requestForServiceType:SLServiceTypeFacebook requestMethod:SLRequestMethodGET URL:profilePictureURL parameters:nil];
profilePictureRequest.account = self.facebookAccount;
[profilePictureRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *e)
{
NSDictionary *responseDataDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:&e];
NSLog(#"%#", responseDataDictionary);
if (e != nil) {
NSLog(#"Request error: %#", e.localizedDescription);
} else {
}
}];
} else {
NSLog(#"Read permissions request error: %#", e.localizedDescription);
}
}];
} else {
NSLog(#"Basic permissions request error: %#", e.localizedDescription);
}
}];
}
You can see that the reponseDataDictionary is null and something happens when parsing the data. I noticed a couple of other threads on SO about the same error code, but no luck so far. My guess is that either 1) there's something wrong with my Facebook code, or 2) I'm parsing the data incorrectly. Any help's appreciated!
Note: I would like to stick to using the Social/Account frameworks only.
UPDATE: Slight modification thanks to a suggestion in the comments.
Changed code:
[profilePictureRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *e)
{
NSLog(#"Request error value: %#", e.localizedDescription);
NSError *jsonError = nil;
NSDictionary *responseDataDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:&jsonError];
NSLog(#"Response data dictionary value: %#", responseDataDictionary);
if (jsonError != nil) {
NSLog(#"Serialization error: %#", jsonError.localizedDescription);
} else {
NSLog(#"Serialization successful");
}
}];
Output:
2013-01-28 18:55:16.265 TestApp[9565:1ae03] Account saved to accountStore
2013-01-28 18:55:17.640 TestApp[9565:1b503] Request error value: (null)
2013-01-28 18:55:17.640 TestApp[9565:1b503] Response data dictionary value: (null)
2013-01-28 18:55:17.642 TestApp[9565:1b503] Serialization error: The operation couldn’t be completed. (Cocoa error 3840.)
The profilePictureRequest is returning an image and not JSON. Use + (CIImage *)imageWithData:(NSData *)data to convert the response to an image.

Error in NSMutableArray

I am very new to ios development, I am trying to add some values from NSMutableDictionary to NSMutableArray, when I run the code I get this error
2012-05-29 14:09:34.913 iShop[7464:f803] -[__NSCFArray objectForKey:]:
unrecognized selector sent to instance 0x6e423d0 2012-05-29
14:09:34.915 iShop[7464:f803] * Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: '-[__NSCFArray
objectForKey:]: unrecognized selector sent to instance 0x6e423d0'
* First throw call stack: (0x13cb022 0x155ccd6 0x13cccbd 0x1331ed0 0x1331cb2 0x2bb7 0x13cce42 0x93b9df 0x139f94f 0x1302b43 0x1302424
0x1301d84 0x1301c9b 0x12b47d8 0x12b488a 0x15626 0x28bd 0x2825)
terminate called throwing an exception(lldb)
below is my code:
-(void) getData:(NSData *) response {
NSError *error;
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:response options:kNilOptions error:&error];
//NSLog(#"%#", json);
jsonArray = [[NSMutableArray alloc] init];
jsonArray = [json objectForKey:#"Name"];
NSLog(#"%#", jsonArray);
}
- (void)viewDidLoad {
[super viewDidLoad];
jsonURL = [NSURL URLWithString:#"http://localhost:8888/read_product_list.php"];
dispatch_async(BgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:jsonURL];
[self performSelectorOnMainThread:#selector(getData:)
withObject:data waitUntilDone:YES];
});
}
JSONObjectWithData return an object of type id. depending on the structure of your received json data.
The data recieved is eiher NSDictionary or NSArray. In your case I am guessing the top level object is of type NSArray which does not respond to objectForKey

Accessing JSON data inside an NSDictionary generated from NSJSONSerialization

Having some trouble accessing the JSON data in the following URL ( http://jamesstenson.com/portraits/?json=1 ), basically I want to access the "full" "url"'s underneath "attachments". My code at the moment is as follows:
NSError *e = nil;
NSData *jsonFeed = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://jamesstenson.com/portraits/?json=1"]];
NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:jsonFeed options:NSJSONReadingMutableContainers error: &e];
if (!jsonData) {
NSLog(#"Error parsing JSON: %#", e);
} else {
for(NSDictionary *item in [jsonData objectForKey:#"page"]) {
for(NSDictionary *attachment in [item objectForKey:#"images"]) {
NSLog(#"%#", attachment);
}
}
}
This keeps throwing up an error:
2011-12-21 10:13:39.362 JSON[3463:f803] -[__NSCFString objectForKey:]: unrecognized selector sent to instance 0x6a7b500
2011-12-21 10:13:39.363 JSON[3463:f803] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString objectForKey:]: unrecognized selector sent to instance 0x6a7b500'
I am aware I am accessing the items wrongly, but cannot figure out how to achieve this. I've tried several solutions such as http://blogs.captechconsulting.com/blog/nathan-jones/getting-started-json-ios5 - but no luck. I am complete newbie to iOS development and have a little knowledge of JSON. Thanks for everyones help in advance.
The problem is in you for loop
for(NSDictionary *item in [jsonData objectForKey:#"page"])
You won't get NSDictionary in item, it will return you key of Dictionary, which would be NSString
Check this link for each loop in objective c for accessing NSMutable dictionary to know how to traverse through NSDictionay
Below is the modified code for your requirement, might help you
if (!jsonData) {
NSLog(#"Error parsing JSON: %#", e); } else {
NSArray *attachments = [[jsonData objectForKey:#"page"] objectForKey:#"attachments"];
for(NSDictionary *object in attachments) {
NSLog(#"%#", [object objectForKey:#"images"]);
NSLog(#"%#", [[[object objectForKey:#"images"] objectForKey:#"full"] objectForKey:#"url"]);
}
}

HTTP server works in Cocoa application but not test case -- run loop issue?

I'm trying to add a GHUnit test case to this SimpleHTTPServer example. The example include a Cocoa application that works fine for me. But I can't duplicate the behavior in a test case.
Here is the test class:
#import <GHUnit/GHUnit.h>
#import "SimpleHTTPServer.h"
#interface ServerTest : GHTestCase
{
SimpleHTTPServer *server;
}
#end
#implementation ServerTest
-(void)setUpClass
{
[[NSRunLoop currentRunLoop] run];
}
- (NSString*)requestToURL:(NSString*)urlString error:(NSError**)error
{
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:1];
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:error];
NSString *page = nil;
if (error == nil)
{
NSStringEncoding responseEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)[response textEncodingName]));
page = [[NSString alloc] initWithData:data encoding:responseEncoding];
[page autorelease];
}
return page;
}
- (void)testPortReuse
{
unsigned int port = 50001;
NSError *error = nil;
NSString *path, *url;
server = [[SimpleHTTPServer alloc] initWithTCPPort:port delegate:self];
sleep(10);
path = #"/x/y/z";
url = [NSString stringWithFormat:#"http://localhost:%u%#", port, path];
[self requestToURL:url error:&error];
GHAssertNil(error, #"%# : %#", url, error);
[server release];
}
- (void)processURL:(NSURL *)path connection:(SimpleHTTPConnection *)connection
{
NSLog(#"processURL");
}
- (void)stopProcessing
{
NSLog(#"stopProcessing");
}
#end
I've tried sending requests via NSURLRequest and also (during the sleep) via a web browser. The delegate methods -processURL and -stopProcessing are never called. The problem seems to be that [fileHandle acceptConnectionInBackgroundAndNotify] in SimpleHTTPServer -initWithTCPPort:delegate: is not causing any NSFileHandleConnectionAcceptedNotifications to reach the NSNotificationCenter -- so I suspect a problem involving run loops.
The problem seems to be with the NSFileHandle, not the NSNotificationCenter, because when [nc postNotificationName:NSFileHandleConnectionAcceptedNotification object:nil] is added to the end of initWithTCPPort:delegate:, the NSNotificationCenter does get the notification.
if (error == nil)
That should be:
if (data != nil)
error here is the passed-in pointer to an NSError* - it will only be nil if the caller passed nil instead of a reference to an NSError* object, which isn't what your -testPortReuse method does.
It would also be incorrect to dereference it (as in if (*error == nil)), because error arguments are not guaranteed to be set to nil upon error. The return value indicates an error condition, and the value returned in the error argument is only meaningful or reliable if there is an error. Always check the return value to determine if an error happened, then check the error parameter for details only if something did in fact go wrong.
In other words, as it's written above, your -requestToURL:error: method is incapable of handling success. Much like Charlie Sheen. :-)

Cannot get Length of a NSString - unrecognized selector sent to instance

What I'm trying to get is to search for the Anime Titile's ID, compare the length and perform some action afterwards. Here is what I get in the debugger:
2010-08-09 14:30:48.818 MAL Updater OS X[37415:a0f] Detected : Amagami SS - 06
2010-08-09 14:30:48.821 MAL Updater OS X[37415:a0f] http://mal-api.com/anime/search?q=Amagami%20SS
2010-08-09 14:30:49.635 MAL Updater OS X[37415:a0f] 8676
2010-08-09 14:30:49.636 MAL Updater OS X[37415:a0f] -[NSCFNumber length]: unrecognized selector sent to instance 0x384aa40
2010-08-09 14:30:49.637 MAL Updater OS X[37415:a0f] -[NSCFNumber length]: unrecognized selector sent to instance 0x384aa40
The code in question:
if ([self detectmedia] == 1) { // Detects Media from MPlayer via LSOF
NSLog(#"Detected : %# - %#", DetectedTitle, DetectedEpisode);
NSString * AniID = [self searchanime]; // Perform a Search Operation and Returns the ID of the time from JSON
NSLog(#"%#",AniID);
if (AniID.length > 0) { // Compare the length of AniID to make sure it contains a ID
// Other Action here
}
//Release Detected Title and Episode
[DetectedTitle release];
[DetectedEpisode release];
}
SearchAnime method:
-(NSString *)searchanime{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
//Escape Search Term
NSString * searchterm = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)DetectedTitle,
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8 );
//Set Search API
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://mal-api.com/anime/search?q=%#",searchterm]];
NSLog(#"%#",[NSString stringWithFormat:#"http://mal-api.com/anime/search?q=%#",searchterm]);
//Release searchterm
[searchterm release];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
//Ignore Cookies
[request setUseCookiePersistence:NO];
//Set Token
[request addRequestHeader:#"Authorization" value:[NSString stringWithFormat:#"Basic %#",[defaults objectForKey:#"Base64Token"]]];
//Perform Search
[request startSynchronous];
// Get Status Code
int statusCode = [request responseStatusCode];
NSString *response = [request responseString];
if (statusCode == 200 ) {
return [self RegExSearchTitle:response]; // Returns ID as NSString
}
else {
return #"";
}
}
RegExSearchTitle
-(NSString *)RegExSearchTitle:(NSString *)ResponseData {
OGRegularExpressionMatch *match;
OGRegularExpression *regex;
//Set Detected Anime Title
regex = [OGRegularExpression regularExpressionWithString:DetectedTitle];
NSEnumerator *enumerator;
// Initalize JSON parser
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSArray *searchdata = [parser objectWithString:ResponseData error:nil];
for (id obj in searchdata) {
// Look in every RegEx Entry until the extact title is found.
enumerator = [regex matchEnumeratorInString:[obj objectForKey:#"title"]];
while ((match = [enumerator nextObject]) != nil) {
// Return the AniID for the matched title
return [obj objectForKey:#"id"];
}
}
// Nothing Found, return nothing
return #"";
}
This behavior is unusual because I have compared the NSString's length in the past and it never failed on me. I am wondering, what is causing the problem?
The declared return type of RegExSearchTitle is NSString *, but that doesn’t force the returned object to actually be an NSString. The "id" element of obj (from the JSON) is a number, so an NSNumber is being returned. The compiler can’t warn you about this because it doesn’t know what classes will be found in a collection.
There are other bugs in the code. Having an unconditional return in a while statement in a for statement does not make sense.
On a side note, by convention Objective-C method names start with a lowercase letter.
Well, it's because you assigned an NSNumber to AniID, not an NSString. NSNumber doesn't have a length method.