I'm very new to developing in Objective C and am trying to figure out why I'm getting an error with my NSDictionary when trying to apply it to a table view. I'm getting the error "Expected method to read array element not found on object of type 'NSDictionary*". Does anyone know what that means, or how I would go about fixing it? I've included the model where I'm having the issue.
UPDATED:
The statement getting flagged is:
NSDictionary *conversation = self.data[indexPath.row];
Thanks!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ConversationTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"conversationCell" forIndexPath:indexPath];
// Get data from array at position of the row
NSDictionary *conversation = self.data[indexPath.row];
// Apply the data to each row
cell.conversationRecipients.text = [conversation valueForKey:#"recipients"];
cell.conversationPreview.text = [conversation valueForKey:#"last_message"];
cell.conversationTime.text = [conversation valueForKey:#"last_thread_post_short"];
//Set conversation thumbnail
[cell.conversationThumbnail sd_setImageWithURL:[conversation valueForKey:#"sender_avatar"]];
return cell;
}
Here's where I'm setting self.data:
// Successful Login
// Create the URL from a string.
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"URLISHERE"]];
NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60];
[request setHTTPMethod:#"GET"];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
// Prepare for the response back from the server
NSHTTPURLResponse *response = nil;
NSError *error = nil;
// Send a synchronous request to the server (i.e. sit and wait for the response)
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSError *serializeError;
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&serializeError];
// Get response
self.data = json;
NSLog(#"%#", self.data);
// Reload data after Get
[self.tableView reloadData];
self.data needs to be of type NSArray not NSDictionary then it will work.
Related
I have have some trouble in understanding what is needed to fetch a JSON file with mantle.h from a URL.
Can someone give me an example of how it works?
For example:
-I have a URL www.example.com with a JSONFile as follows:
{
"name": "michael"
}
How could I fetch it?
I use this process for fetching JSON:
NSURL *s = url;//Put your desird url here
NSURLRequest *requestURL = [NSURLRequest requestWithURL:s cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.00];
NSHTTPURLResponse *response;
NSError *error = [[NSError alloc]init];
NSData *apiData = [NSURLConnection sendSynchronousRequest:requestURL returningResponse:&response error:&error];
dictionaryData = [NSJSONSerialization JSONObjectWithData:apiData options:kNilOptions error:&error];
Now the dictionaryData contains your JSON. You can fetch it by:
NSString *name = [dictionaryData valueForKey:#"name"];
And make sure you are making async request. For this put the code within this block:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
//Put the code here
});
Hope this helps.. :)
Call it with following method
[super getRequestDataWithURL:urlString
andRequestName:sometext];
You will get response in the following method if successful
- (void)successWithRequest:(AFHTTPRequestOperation *)operation withRespose:(id)responseObject withRequestName:(NSString *)requestName {
NSString *response = operation.responseString;
id jsonObject = [response objectFromJSONString];
if(![super checkforServerRequestFailureErrorMessage:jsonObject]) {
[self.leaderboardProxyDelegate leaderboardListSuccessful:jsonObject];
}
}
You will get dictionary in jsonObject
I'm really having trouble figuring this out. I'm parsing JSON into an array asynchronously. Running NSLog on the async function prints out an array with multiple objects, which is what I want. But when I run the NSLog on the returned array in the ViewController it only prints out the last object of the array. I then run a count on it and there is, in fact, only 1 object in the array. Why is it only returning an array with one object from an array with multiple objects? Below is my code. Thanks for any input you might have.
Function performed asynchronously
- (NSArray *)locationsFromJSONFile:(NSURL *)url {
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:30.0];
NSURLResponse *response;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
NSError *error;
NSMutableDictionary *allTeams = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:&error];
if( error )
{
NSLog(#"%#", [error localizedDescription]);
}
else {
team = allTeams[#"10"];
for ( NSDictionary *teamArray in team )
{
teams = [NSArray arrayWithObjects: teamArray[#"team"], nil];
}
}
return teams;
}
ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
JSONLoader *jsonLoader = [[JSONLoader alloc] init];
NSURL *url = [[NSBundle mainBundle] URLForResource:#"teams" withExtension:#"json"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
teams = [jsonLoader locationsFromJSONFile:url];
int i = [teams count];
NSString *string = [NSString stringWithFormat:#"%d", i];
NSLog(#"%#", string);
});
}
You need to add object to the existing array instead of reinitalizing it everytime
teams = [NSArray arrayWithObjects: teamArray[#"team"], nil];
should be
else {
team = allTeams[#"10"];
teams = [NSMutableArray array];
for ( NSDictionary *teamArray in team )
{
[teams addObject:teamArray[#"team"]];
}
Also you are sending synchronous request using this code
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
you should use the sendAsynchronous methods. Synchronous request can be terminated by the OS itself and can lead to some confusion and bugs later on
I am trying to store data from server to NSMutable array to display them as news feeds in table view like shown in this image. Basically like twitter news feeds. What I wanna do is get the data from the server in the NSMutable array and use that array to display in my table view. I don't know if this is the right way to do it. I tried adding statically and it works but I really don't know how to do it dynamically since I'm a newbie to Objective C. Sorry if this question seems really stupid. Thanks in advance!
Parse data using JSON:
dispatch_queue_t jsonParsingQueue = dispatch_queue_create("jsonParsingQueue", NULL);
// execute a task on that queue asynchronously
dispatch_async(jsonParsingQueue, ^{
NSString *urlStr = #"YourURL";
NSURL *url = [NSURL URLWithString:[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL: url];
[request setHTTPMethod: #"GET"];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *responseStr = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSData * jsonData = [responseStr dataUsingEncoding:NSUTF8StringEncoding];
NSMutableArray *tempResults = [NSMutableArray alloc];
NSError *jsonParsingError = nil;
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&jsonParsingError];
tempResults = jsonObject[#"posts"]; //Add the json key you would like to get
self.arrayToDisplay = [tempResults copy]; //copy them to your NSMutableArray
// some code on a main thread (delegates, notifications, UI updates...)
dispatch_async(dispatch_get_main_queue(), ^{
[self.myTableView reloadData];
});
});
I get an self.usersArray with 2 elements in the format:
(
{
userCreated = "2012-01-05 12:27:22";
username = Simulator;
},
{
userCreated = "2013-01-01 14:27:22";
username = "joey ";
}
)
This is gotten in a completion block after which I call another method to fetch points for these 2 users through a helper class:
-(void)getPoints{
self.usersPointsArray = [[NSMutableArray alloc] init];
for (NSDictionary *usersDictionary in self.usersArray) {
[SantiappsHelper fetchPointsForUser:[usersDictionary objectForKey:#"username"] WithCompletionHandler:^(NSArray *points){
if ([points count] > 0) {
[self.usersPointsArray addObject:[points objectAtIndex:0]];
}
NSLog(#"self.usersPointsArray %#", self.usersPointsArray);
}];
}
}
The final self.usersPointsArray log looks like:
(
{
PUNTOS = 5;
username = Simulator;
},
{
PUNTOS = 2;
username = joey;
}
)
But the problem is that the way the call for points is structured, the self.usersPointsArray is returned twice, each time with an additional object, due to the for loop, I know.
Here is the Helper class method:
+(void)fetchPointsForUser:(NSString*)usuario WithCompletionHandler:(Handler2)handler{
NSURL *url = [NSURL URLWithString:#"http://myserver.com/myapp/readpoints.php"];
NSDictionary *postDict = [NSDictionary dictionaryWithObjectsAndKeys:usuario, #"userNa", nil];
NSData *postData = [self encodeDictionary:postDict];
// Create the request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d", postData.length] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
__block NSArray *pointsArray = [[NSArray alloc] init];
dispatch_async(dispatch_get_main_queue(), ^{
// Peform the request
NSURLResponse *response;
NSError *error = nil;
NSData *receivedData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (error) {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSLog(#"HTTP Error: %d %#", httpResponse.statusCode, error);
return;
}
return;
}
NSString *responseString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
pointsArray = [NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSASCIIStringEncoding] options:0 error:nil];
if (handler)
handler(pointsArray);
});
}
I cannot use the self.usersPointsArray with the initial objects, only with the finalized object. It wont always be 2 elements, i actually dont know how many it will be.
What would be the way to structure it so I get a final call when the self.usersPointsArray is complete and then I reload my tableview?
I think of your problem as a standard consumer-producer problem. You can create a queue count for the amount of items that will be processed (int totalToProcess=self.usersArray.count). Each time the completion handler is hit, it will do totalToProcess--. When totalToProcess reaches 0 you have processed all of the elements in your queue and can refresh your table.
If I understand your question correctly I believe this solves your problem. If not, hopefully I can with a bit more information.
I've been reading for hours and I can't figure out why my table won't reload itself with the updated data, here is the request I am making in block form:
ASIHTTPRequest *_request= [ASIHTTPRequest requestWithURL:url];
__weak ASIHTTPRequest *request = _request;
request.requestMethod = #"POST";
[request addRequestHeader:#"Content-Type" value:#"application/json"];
[request setDelegate:self];
[request setCompletionBlock:^{
NSString *responseString = [request responseString];
NSData *responseData = [request responseData];
NSLog(#"Response: %#", responseString);
NSError* error;
json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
NSLog(#"request finished");
[CommMTable reloadData];
}];
[request setFailedBlock:^{
NSError *error = [request error];
NSLog(#"Error: %#", error.localizedDescription);
}];
[request startAsynchronous];
It gets the json object successfully as it is printed in my console but the table doesn't update!
here is my table pragma section
(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.json count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier=#"Cell";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
NSDictionary *tempDictionary= [self.json objectAtIndex:indexPath.row];
if(cell==nil) {
cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.accessoryType=UITableViewCellAccessoryDetailDisclosureButton;
cell.textLabel.text = [tempDictionary objectForKey:#"title"];
return cell;
}
any help is appreciated, this is really frustrating :(
Have you checked whether json array has been updated or not? And you have used json array as property(self.json) in pragma sections not in inside blocks.
json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
On doing this, the json array will be available only in the scope of setCompletionBlock.
Since you have synthesized json array, you need to assign it like
self.json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
If this was also not worked, just check whether the format of json was correct and you are parsing the json properly in cellForRowAtIndexPath.
I found the problem, I was doing everything correctly (json format and stuff were properly set). The problem was that for some reason the table got disconnected from it's delegate and datasource, for the people who had a similar problem try this solution.
In the xib file just ctrl + drag the tableview to the File Owner and connect it to the delegate and datasource.
or you can do it with just code if you don't like the interface builder with the following lines
[myTableView setDataSource:self];
[myTableView setDelegate:self];
or
self.tableView.delegate = self.tableDelegate;
self.tableView.datasource = self.tableDelegate;
both either/or should work.