NSArray arrayByAddingObjectsFromArray - ios

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];

Related

Obj-C: Check if object exists in NSMutableArray?

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;
}
}

iOS fetching data from server inside for loop

I want to fetch data from server with multiple calls inside for loop. I'm passing different parameter each time. I know it is possible to fetch data like, I'm fetching in code below :
for (NSDictionary *feedItem in [feed objectForKey:#"content"]) {
// url with feedItem data.
NSURL *url = ....
[UrlMethod GetURL:url success:^(NSDictionary *placeData) {
if (placeData) {
dispatch_async(dispatch_get_main_queue(), ^{
// adding object to table data source array
[dataSourceArray addObject:[placeData objectForKey:#"data"]];
// reloading table view.
[self.tableView reloadData];
});
}
} failure:^(NSError *error) {
}];
}
The problem is, Whenever I add data to dataSourceArry, It is not adding sequentially. It is adding according to response of API calls. Please let me know, If it is not clear.
In your case, I would allocate a mutable array first and set [NSNull null] at each position:
NSInteger count = [[feed objectForKey:#"content"] count];
NSMutableArray *dataSourceArray = [NSMutableArray arrayWithCapacity:count];
for (NSInteger i = 0; i < count; ++i) {
[dataSourceArray addObject:[NSNull null]];
}
Then, I would use something called dispatch groups (see more here http://commandshift.co.uk/blog/2014/03/19/using-dispatch-groups-to-wait-for-multiple-web-services/):
__block NSError *apiCallError = nil; // Just to keep track if there was at least one API call error
NSInteger index = 0;
// Create the dispatch group
dispatch_group_t serviceGroup = dispatch_group_create();
for (NSDictionary *feedItem in [feed objectForKey:#"content"]) {
// Start a new service call
dispatch_group_enter(serviceGroup);
// url with feedItem data.
NSURL *url = ...
[UrlMethod GetURL:url success:^(NSDictionary *placeData) {
if (placeData) {
dispatch_async(dispatch_get_main_queue(), ^{
// Add data to Data Source
// index should be the correct one, as the completion block will contain a snapshot of the corresponding value of index
dataSourceArray[index] = [placeData objectForKey:#"data"];
}
dispatch_group_leave(serviceGroup);
} failure:^(NSError *error) {
apiCallError = error;
dispatch_group_leave(serviceGroup);
}];
index++;
}
dispatch_group_notify(serviceGroup, dispatch_get_main_queue(),^{
if (apiCallError) {
// Make sure the Data Source contains no [NSNull null] anymore
[dataSourceArray removeObjectIdenticalTo:[NSNull null]];
}
// Reload Table View
[self.tableView reloadData];
});
Hope it works for you.
This might be of help for you,
//keep dictionary property which will store responses
NSMutableDictionary *storeResponses = [[NSMutableDictionary alloc]init];
//Somewhere outside function keep count or for loop
NSInteger count = 0;
for (NSDictionary *feedItem in [feed objectForKey:#"content"]) {
//Find out index of feddItem
NSInteger indexOfFeedItem = [[feed objectForKey:#"content"] indexOfObject:feedItem];
NSString *keyToStoreResponse = [NSString stringWithFormat:#"%d",indexOfFeedItem];
// url with feedItem data.
NSURL *url = ....
[UrlMethod GetURL:url success:^(NSDictionary *placeData) {
if (placeData) {
//instead of storing directly to array like below
// adding object to table data source array
[dataSourceArray addObject:[placeData objectForKey:#"data"]];
//follow this
//increase count
count++;
[storeResponses setObject:[placeData objectForKey:#"data"] forKey:keyToStoreResponse];
// reloading table view.
if(count == [feed objectForKey:#"content"].count)
{
NSMutableArray *keys = [[storeResponses allKeys] mutableCopy]; //or AllKeys
//sort this array using sort descriptor
//after sorting "keys"
for (NSString *key in keys)
{
//add them serially
[dataSourceArray addObject:[storeResponses objectForKey:key]];
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
}
} failure:^(NSError *error) {
}];
}
Edit : The answer I have given is directly written here,you might face compilation errors while actually running this code
Don't reload your table each time in the loop. After the loop finishes fetching data , do a sorting on your datasourcearray to get the desired result and then reload table.
This is because you're calling web-services asynchronously so it's not give guarantee that it's give response in sequence as you have made request!
Now solutions for that :
You should write your api like it's give all data at a time. So,
You not need to make many network call and it will improve
performance also!
Second thing you can make recursive kind of function, I mean make another request from completion handler of previous one. In this case once you got response then only another request will be initialize but in this case you will have to compromise with performance!! So first solution is better according to me!
Another thing you can sort your array after you get all the responses and then you can reload your tableView
Try the following :-
for (NSDictionary *feedItem in [feed objectForKey:#"content"]) {
// url with feedItem data.
NSURL *url = ....
[UrlMethod GetURL:url success:^(NSDictionary *placeData) {
if (placeData) {
// adding object to table data source array
[dataSourceArray addObject:[placeData objectForKey:#"data"]];
// reloading table view.
dispatch_sync(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
} failure:^(NSError *error) {
}];
}

Inserting block callback to a NSMutableDictionary

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.

How to get array of values from NSDictionary array

When I try to print array of json values in log, I get addresses instead of values. Here's how I coded.
NSData *jsonData = [json dataUsingEncoding:NSASCIIStringEncoding];
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:jsonArray.count];
NSMutableArray *anotherTempArray = [NSMutableArray arrayWithCapacity:jsonArray.count];
NSDictionary *dict;
for(dict in jsonArray)
{
NSString *projectName = dict[#"Name"];
NSString *urlText = dict[#"Url"];
NSLog(#"Url text in array = %#", urlText);
NSString *attch = dict[#"attachmentes"];
NSLog(#"Attached url in array = %#", attch);
NSString *projID = dict[#"ProjectID"];
NSLog(#"Project ID in array = %#", projID);
SaveAttachment *saveAt = [[SaveAttachment alloc] initWithName:projectName withList:#"View" withAttachment:#"View"];
[tempArray addObject:saveAt];
SaveProjectId *saveProj = [[SaveProjectId alloc] initWithProjectId:projID];
saveProj.projectId = projID;
[anotherTempArray addObject:saveProj];
}
array = tempArray;
[self.tableViewProject reloadData];
NSLog(#"Array of project IDs === %#", anotherTempArray); //Get values (array of project ids here.
}
Replace
SaveProjectId *saveProj = [[SaveProjectId alloc] initWithProjectId:projID];
saveProj.projectId = projID;
[anotherTempArray addObject:saveProj];
with
[anotherTempArray addObject:projID];
This is because your anotherTempArray contains objects of SaveProjectId ie, everytime in for loop you are adding saveProj object not projID. Thats why your array showing SaveProjectId objects.
If you want to directly save them, then use the below modification
[anotherTempArray addObject:projID];
or you can use like(this is i would prefer)
NSLog(#"First project ID === %#", [anotherTempArray objectAtindex:0] projectId]);
You are storing SaveProjectId objects in the array, therefore when you print the content you see the address of those objects.
your "anotherTemoArray" is having objects of SaveProbectId so you have to pass object at index to SaveProjectId and then you can see the array information
When calling NSLog(#"Array of project IDs === %#", anotherTempArray); the -(NSString*)description method on each of the objects inside 'anotherTempArray' is being called.
In your case that means -(NSString*)description is being called on SaveProjectId objects. Override it to print out what you want... e.g.
-(NSString*)description {
return [NSString stringWithFormat:#"SaveProjectId: %#",self.projectId];
}

NSMutableArray insert object at last index

I am trying to copy the objects content of a NSDictionary to a NSMutableArray, and I am using the following code :
// Use when fetching binary data
NSData *responseData = [request responseData];
// View the data returned - should be ready for parsing.
resultsDictionary = [responseData objectFromJSONData];
NSLog(#"ResultsDictionary:%#", resultsDictionary);
self.OnlineObjects = [[[NSMutableArray alloc] init] autorelease];
for (NSDictionary * dataDict in resultsDictionary) {
[OnlineObjects insertObject:dataDict atIndex:0];
}
NSLog(#"OnlineObjects:%#", OnlineObjects);
This is working as i am getting all objects from the Dictionary, but the objects order have been revers, first object is now last ...
How can tell the insertObject to add the object at the last index ?
Thanks
You can use the addObject: method instead.
To get rid of the hash order problem get allKeys, sort the array and then use the elements as keys to get the objects in proper order.
Verbose example (for integer keys):
NSArray *indices = [[resultsDictionary allKeys] sortedArrayUsingComparator:^(id obj1, id obj2) {
if ( [obj1 intValue] > [obj2 intValue] ) {
return (NSComparisonResult)NSOrderedDescending;
}
if ( [obj1 intValue] < [obj2 intValue] ) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}];
for (int i = 0; i < [indices count]; i++) {
NSDictionary *obj = [resultsDictionary objectForKey:[indices objectAtIndex:i]];
[OnlineObjects addObject:obj];
}
The order of the elements in a NSDictionary is undefined, you don't know in which order they will be retrieved from the dictionary. The only way to do have the array sorted is to sort it once all the values from the dictionary are transferred to the array.
Two things you should know:
NSDictionary is a key-value container, which does not guarantee the order of the objects. You have no way to ensure that the order of inserting will be mantained when reading by using this data structure. Check other strategies if order is important for you, but do not rely on NSDictionary for this.
You have a couple of methods to extract the info of the keys and data: allKeys and allValues. Use them instead of creating your own.

Resources