I want to get comments for a photo from a web server. Server returns an array that includes comments. Is it possible to attach a block instead of comment array to NSMutableDictionary?
I want the block to return the comment and insert it's value to dictionary.
I mean some think like this (but it gives compile errors):
NSArray* (^commentsBlock)(id responseObject) = ^(id responseObject){
return responseObject;
};
[self fetchCommentsForNode:[fileInfo objectForKey:#"nid"]
success: commentsBlock];
VDPhoto *photo = [VDPhoto photoWithProperties:
#{#"imageView": imageview,
#"title": [fileInfo objectForKey:#"title"],
#"comments" : commentsBlock,
}];
[photos addObject:photo];
Further to the discussion in the comments you probably want to do something like this...
Do something inline in the block for fetchCommentsForNode:success: - update the dictionary:
NSMutableDictionary *properties = [#{#"imageView": imageview,
#"title": [fileInfo objectForKey:#"title"]} mutableCopy];
[self fetchCommentsForNode:[fileInfo objectForKey:#"nid"] success:^(id responseObject){
properties[#"comments"] = responseObject;
return responseObject;
}];
VDPhoto *photo = [VDPhoto photoWithProperties:properties];
[photos addObject:photo];
All you have to do is make sure the #property in the VDPhoto you save the properties to in the init method is strong, and not copy and then you can look at the dictionary and you will have your comments set once the success block has been called.
EDIT:
An even better option would be to add a #property (nonatomic, copy) NSArray *comments property to VDPhoto, and then set the result on the fetchCommentsForNode: on that:
VDPhoto *photo = [VDPhoto photoWithProperties:#{#"imageView": imageview,
#"title": [fileInfo objectForKey:#"title"]}];
[photos addObject:photo];
[self fetchCommentsForNode:[fileInfo objectForKey:#"nid"] success:^(id responseObject){
photo.comments = responseObject;
return responseObject;
}];
No, an object can't "become" another object. What you want to do is have the block insert the results array in the dictionary, rather than "become" the results array.
Related
I'm trying to check if NSString 'testing' (47) exists inside of my NSMutableArray 'self.checkfriendData'. I'm using the code below, though after logging my if statement it appears as though it's never executed (even though the statement is true - see console data below, uid = 47, and thus hiding my object should fire?) Any idea as to why this isn't working? Help is much appreciated!
ViewController.m
NSMutableDictionary *viewParams3 = [NSMutableDictionary new];
[viewParams3 setValue:#"accepted_friends" forKey:#"view_name"];
[DIOSView viewGet:viewParams3 success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.checkfriendData = (NSMutableArray *)responseObject;
NSString *testing = #"47";
NSArray *friendorNo = self.checkfriendData;
if ([friendorNo containsObject:testing]) // YES
{
self.addFriend.hidden = YES;
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
Here's what's inside self.checkfriendData:
2017-05-18 19:36:07.266529-0700 This is the friend data check (
{
body = "My name is Britt";
friendphoto = "/sites/default/files/stored/x.jpg";
"node_title" = "Britt";
uid = 47;
}
)
It appears that your NSArray contains NSDictionarys and you are asking if the array contains an NSString. The answer will always be no as the array doesn't directly contain any NSStrings.
If you want to search for the uid of 47 you will have to iterate over the array and check the uid key of each NSDictionary for the value 47.
The code for this would look something like:
for (NSDictionary *dict in friendorNo) {
if ([dict[#"uid"] isEqualToString:testing]) {
self.addFriend.hidden = YES;
}
}
I've retrieved data to my iOS app from my Drupal database using the below code:
.h
#property (strong, nonatomic) NSMutableArray *userData;
.m
self.userData = [NSMutableArray new];
NSMutableDictionary *viewParams = [NSMutableDictionary new];
[viewParams setValue:#"u000" forKey:#"view_name"];
[DIOSView viewGet:viewParams success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.userData = [responseObject mutableCopy];
NSLog(#"%#",self.userData);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
self.userData = [[NSMutableArray alloc] init];
self.userBio.text = self.userData[0][#"userbio"];
self.userData is populated, so I know my data has successfully been returned. Does anyone know how I would display the JSON returned field in a UIlabel? I'm just not sure how I would write this line of code (newb, sorry). My field name is userbio.
Here's how the data structure is returned (incase it's of any use):
UPDATE: NSLog(#"userData = %#", self.userData); returns this in the console:
2015-10-25 11:22:06.601 [7605:2738034]
userData = (
> {
> userbio = "No user bio available at this time.";
> "users_name" = "<a href=\"/user/20\" title=\"View user profile.\" class=\"username\" xml:lang=\"\" about=\"/user/20\"
> typeof=\"sioc:UserAccount\" property=\"foaf:name\"
> datatype=\"\">Brittany</a>";
> },
If it's an NSDictionary the code would look like this:
self.myLabelName.text = self.userData[#"userbio"];
If it's an NSArray of NSDictionaries it would look like:
self.myLabelName.text = [self.userData firstObject][#"userbio"];
That's assuming that the array contains only one dictionary, otherwise you would have to access each element: self.userData[0], self.userData[1], etc.
I have this code, but when I log the mediaDictionaryArray, I get null. Does the receiver array have to be initialized with a value first or can I add objects to an empty array? Does [NSArray array] vs. [[NSArray alloc]init] have anything to do with it?
Adding dictionary from API call that happens i times. Asynch call will return the dictionary - can't be sure if NSMutableArray will work in catchJSONArray since asynch nature of call will make the array of indeterminate size which will make it hard to use later on.
Updated with relevant bit.
for (int i = 0; i<[array count]; i++) {
NSString *getString = array[i];
NSLog(#"getstring %#", getString);
[client GET:getString parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;
if (httpResponse.statusCode == 200) {
dispatch_async(dispatch_get_main_queue(), ^{
_locationMediaArray = (NSArray*)responseObject[#"data"];
[self catchJSONArray:_locationMediaArray];
then here is method with the array issue
-(void)catchJSONArray:(NSArray*)array{
NSArray *catchJSONArray = [NSArray array];
_mediaDictionaryArray = [catchJSONArray arrayByAddingObjectsFromArray:array];
NSLog(#"mediaDictionaryArray %#", _mediaDictionaryArray);
}
arrayByAddingObjectsFromArray returns a new array containing your objects, as an NSArray can not be changed once created.
If you want to change an existing array, you should be using an NSMutableArray.
The best way you could do this is:
_mediaDictionaryArray=[NSArray arrayWithArray:otherArray];
That will create a new array with the contents of otherArray and assign it to _mediaDictionary.
No need to alloc init your array just pass the refrence of your other array. If
_mediaDictionaryArray is mutable array then use below:-
_mediaDictionaryArray=[array mutableCopy];
If it is non mutable array then use below
_mediaDictionaryArray=[array copy];
I'm trying to get the data from a JSON response object in my iOS app after I log in. I keep getting this error though.
Error:
'NSInvalidArgumentException', reason: '-[__NSCFArray objectForKeyedSubscript:]: unrecognized selector sent to instance 0x8fc29b0'
Here is my code for the request, I'm using AFNetworking:
self.operation = [manager GET:urlString parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary *JSON = (NSDictionary *)responseObject;
NSDictionary *user = JSON[#"user"];
NSString *token = user[#"auth_token"];
NSString *userID = user[#"id"];
// NSString *avatarURL = user[#"avatar_url"];
// weakSelf.credentialStore.avatarURL = avatarURL;
weakSelf.credentialStore.authToken = token;
weakSelf.credentialStore.userId = userID;
weakSelf.credentialStore.username = self.usernameField.text;
weakSelf.credentialStore.password = self.passwordField.text;
[SVProgressHUD dismiss];
[self dismissViewControllerAnimated:YES completion:nil];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (operation.isCancelled) {
return;
}
[SVProgressHUD showErrorWithStatus:#"Login Failed"];
NSLog(#"%#", error);
}];
What the JSON response object looks like logged:
<__NSCFArray 0x8cac0b0>(
{
user = {
"auth_token" = b3a18e0fb278739649a23f0ae325fee1e29fe5d6;
email = "jack#jack.com";
id = 1;
username = jack;
};
}
)
I'm converting the array to a Dictionary using pointers like this:
EDIT: As pointed out in the comments incase anyone else stumbles across this with limited knowledge in iOS. I'm casting here not converting. See the answers for a full explanation.
NSDictionary *JSON = (NSDictionary *)responseObject;
I'm new to iOS, apologies if problem is obvious.
Thanks for any help.
The "conversion" you do is not doing any conversion, it's a cast. This simply tells the compiler to ignore the type it knows for this object and act as if it's the type you pass it.
Looking at the output you have, you don't get a dictionary back, but an array of dictionaries with a single dictionary. To get to the first dictionary you can use this instead of the cast:
NSDictionary *JSON = [responseObject objectAtIndex:0];
Note that since you get your data from a web service, you should probably also check if the contents you get are what you expect.
You say:
I'm converting the array to a Dictionary using pointers like this:
But that is not what you are doing. You are casting it, but the underlying object is still an array.
From the JSON response you can see that those JSON is constructed as an array with a single element which is a dictionary. You can get to the dictionary by calling [responseObject firstObject];. Of course, so that you don't get error going in the other direction, you should check how the input is constructed before calling any array or dictionary specific methods on the response object.
You have to convert your self but do not use casting.
Or, this is the code to detect if a json object is an array or dictionary
NSError *jsonError = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&jsonError];
if ([jsonObject isKindOfClass:[NSArray class]]) {
NSLog(#"its an array!");
NSArray *jsonArray = (NSArray *)jsonObject;
NSLog(#"jsonArray - %#",jsonArray);
}
else {
NSLog(#"its probably a dictionary");
NSDictionary *jsonDictionary = (NSDictionary *)jsonObject;
NSLog(#"jsonDictionary - %#",jsonDictionary);
}
I come from Android dev, so sorry if I'm missing obvious iOS concepts here.
I have a JSON feed that looks like:
{"directory":[{"id":0,"fName":"...","lName":"...","title":"...","dept":"...","bld":"...","room":"...","email":"...","phone":"..."},{"id":1,"fName":"...","lName":"...","title":"...","dept":"...","bld":"...","room":"...","email":"...","phone":"..."}]}
Then, I have a Staff.h and .m with a class with properties to match it (id, fName, lName) ect.
I've been working at this for hours, but I can't seem to parse the JSON string to an array of Staff objects. The end goal is to get them into Core Data, so any advice would be nice.
Tutorials I've read haven't shown how to work with a JSON string in the form of {"directory":[{...}]} I had no problem doing this in my Android app, but I'm out of ideas here for iOS (6) in objective-c.
Thanks for reading.
You can do it like
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseObject options:0 error:&error];//response object is your response from server as NSData
if ([json isKindOfClass:[NSDictionary class]]){ //Added instrospection as suggested in comment.
NSArray *yourStaffDictionaryArray = json[#"directory"];
if ([yourStaffDictionaryArray isKindOfClass:[NSArray class]]){//Added instrospection as suggested in comment.
for (NSDictionary *dictionary in yourStaffDictionaryArray) {
Staff *staff = [[Staff alloc] init];
staff.id = [[dictionary objectForKey:#"id"] integerValue];
staff.fname = [dictionary objectForKey:#"fName"];
staff.lname = [dictionary objectForKey:#"lName"];
//Do this for all property
[yourArray addObject:staff];
}
}
}
Use: NSJSONSerialization
You use the NSJSONSerialization class to convert JSON to Foundation
objects and convert Foundation objects to JSON.
An object that may be converted to JSON must have the following properties:
The top level object is an NSArray or NSDictionary.
All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
All dictionary keys are instances of NSString.
Numbers are not NaN or infinity.
You will get NSDictionary then you can parse (create) it to your object and then use it in CoreData.
Use following code:
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
This will covert json data onto NSDictionary, which is similar to hashmap on android. I think this will help you. :)
you can use NSJSonSerialisation or AFNetworking library. Here is the example of AFNetworking to parse json response
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:#"http://example.com/resources.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
NSDictionary *json = (NSDictionary *)responseObject;
NSArray *staffArray = json[#"directory"];
[staffArray enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop){
Staff *staff = [[Staff alloc] init];
staff.id = [[obj objectForKey:#"id"] integerValue];
staff.fname = [obj objectForKey:#"fName"];
staff.lname = [obj objectForKey:#"lName"];
//add data to new array to store details
[detailsArray addObect:staff);
} ];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
then use Core Data framework to store data.
I would take a look at RestKit. It provides object-mapping and CoreData backed storage.
For this, you can SBJSON framework.
You have to convert the response string into an NSDictionary like
NSString *responseString = [[NSString alloc]initWithData:responseData encoding:NSUTF8StringEncoding];
NSDictionary *dic = [responseString JSONValue];
Now you can create an object for Staff class.
Staff *staff = [[Staff alloc]init];
Then you can store values in this object like
staff.firstname = [[[dic objectForKey:#"directory"] objectAtIndex:0] objectForKey:#"fName"];
Now you can pass this single object to other classes
You can use the handmade solution proposed by #janak-nirmal, or use a library like jastor, https://github.com/elado/jastor, it doesn't make much difference.
I warn you against Restkit, because the ratio benefits-vs-pain is very low, in my opinion.
Moreover, it could be as use a tank to kill a fly in your scenario.