Currently I'm trying to parse responseObject to populate my table view, but I've been having some problem with parsing the array in the responseObject. I want to populate my cell with values from responseObject[#"test"].
Request operation:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:[kBaseURL stringByAppendingString:#"directori/member_list"]parameters:params
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"RESPONSE: %#", responseObject);
if ([responseObject[#"status_reason"] isEqualToString:#"Success"]) {
self.allMembers = responseObject[#"test"];
NSLog(#"MEMBERS: %#", self.allMembers);
} else {
// handle error
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"ERROR: %#", error);
}];
As you can see below, test is an array of objects.
Sample responseObject:
RESPONSE: {
test = (
{
img = "http://test.com/assets_api/images/no_image.png";
location = "test location";
name = "test user";
position = "test";
}
);
"audit_no" = "";
"status_code" = 200;
"status_reason" = Success;
}
And here's is my table view data source.
Table View Data Source
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"DirectoryCell";
DirectoryViewCell *cell = (DirectoryViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
cell = [[DirectoryViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *member = [self.allMembers objectAtIndex:indexPath.row];
NSLog(#"MEMBER: %#", member);
return cell;
}
allMembers is of type NSArray while member is of type NSDictionary.
When I try to log the value of member it returns null. Where did it go wrong?
You Should try this
NSDictionary *member = [[self.allMembers objectAtIndex:indexPath.row]objectAtIndex:0];
Related
This is a question hard to ask but I'm going to give it a shot anyways. I'm trying to retrieving the contents of an NSDictionary outside of the UITableCell loop. Right now, when I do retrieve its content via:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
everything works fine. But outside of that loop, in a void function of its own, the number retrieved is 0.
- (void)getVideoList{
NSString *ensdsds = #"z9yDgV3ONSU";
for (int i=0; i< [self.youtubePaginator.results count]; i++){
NSDictionary *photoshoots = [self.youtubePaginator.results objectAtIndex:i];
NSString * videoId = photoshoots[#"videoID"];
NSLog(#"Newly %#: ", videoId);
NSString *urlStrings = [NSString stringWithFormat:#"https://www.googleapis.com/youtube/v3/videos?part=id%%2C+snippet%%2C+contentDetails%%2C+statistics&id=%#&key=78587868", videoId];
NSLog(#"Arries %#", urlStrings);
NSURL *urlstats = [NSURL URLWithString:urlStrings];
NSURLRequest *requeststats = [NSURLRequest requestWithURL:urlstats];
AFHTTPRequestOperation *operationtwo = [[AFHTTPRequestOperation alloc] initWithRequest:requeststats];
operationtwo.responseSerializer = [AFJSONResponseSerializer serializer];
[operationtwo setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operationtwo, id responseObjected)
{
NSDictionary *itemed = [responseObjected objectForKey:#"items"];
for (NSDictionary *itemest in itemed )
{
YouTubeVideo *youTubeVideo = [[YouTubeVideo alloc] init];
NSDictionary* stats = [itemest objectForKey:#"statistics"];
youTubeVideo.likesCount = [stats objectForKey:#"likeCount"];
youTubeVideo.viewsCount = [stats objectForKey:#"viewCount"];
NSDictionary* channelInfo = [itemest objectForKey:#"snippet"];
youTubeVideo.channelInfo = [channelInfo objectForKey:#"channelId"];
youTubeVideo.videoUploader = [channelInfo objectForKey:#"channelTitle"];
NSLog(#"True To: %#", youTubeVideo.videoUploader);
[self.thunder addObject:youTubeVideo];
}} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Error loading %#", error);
}];
[operationtwo start]; }
}
The above code returns nothing. How do I incorporate NSIndexPath in the void function and still be able to call [self getVideoList]; in viewDidLoad.
Hope that makes sense? :/
You can get the imageURL in getVideoList by passing NSIndexPath as a parameter , you just need to create a global NSString object if you want to access it globally or you can return extracted imageURL as a return value.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString * imageURL = [self getVideoList:indexPath];
// Write your code to perform operation with the image URL.
}
Here is the getVideoList method
- (NSString *)getVideoList:(NSIndexPath *)indexPath{
NSDictionary *photoshoots = [self.youtubePaginator.results objectAtIndex:indexPath.Row];
NSString * imageURL = photoshoots[#"avatar_url"];
NSLog(#"Newly %#: ", imageURL);
NSLog(#"To find us: [%d]:%#",i,self.youtubePaginator.results[i]);
return imageURL;
}
You can update the code as per your requirement.
I'm trying to remove cells from UICollectionView in for.. in loop and every time I get NSRangeException. I can't understand why does it happen because firstly I sort my array and then trying to remove. So the problem is that I firstly try to send request to the server and only if response is succes my UICollectionView cells and array elements are removes. Here is my code:
Pass elements through the loop:
- (IBAction)deletePictures:(id)sender {
int i = 0;
if (selectedPhotosURL.count>0){
loadCount = (int)selectedPhotosURL.count;
//sorting an array (it works fine)
NSArray *indexPaths = sortMediaCollection.indexPathsForSelectedItems;
NSMutableArray *pathes = [NSMutableArray arrayWithArray:indexPaths];
NSSortDescriptor *highestToLowest = [NSSortDescriptor sortDescriptorWithKey:#"self" ascending:NO];
[pathes sortUsingDescriptors:[NSArray arrayWithObject:highestToLowest]];
[selecedCellsArray sortUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2) {
return [str2 compare:str1 options:(NSNumericSearch)];
}];
NSLog(#"selectedCElls %#",selecedCellsArray);
for(NSIndexPath *indexPath in pathes) {
NSLog(#"indexPath in pathes is %ld",(long)indexPath.row);
AVMSMCell *cell = (AVMSMCell *)[sortMediaCollection cellForItemAtIndexPath:indexPath];
AVMDataStore *oneItem = [smArray objectAtIndex:indexPath.row];
NSString *contentId = oneItem.fileId;
if (i<selectedPhotosURL.count){
NSLog(#"indexPath second loop is %ld",(long)indexPath.row);
[self deleteUserPhotos:contentId : indexPath.row : cell]; // send request to the server it's ok too.
i++;
}
}
} else {
[self selectAtLeastOneFirst];
}
}
For example here I select 6 cells and my array sort with right order from up to down (5,4,3,2,1,0). Then I pass this elements in method with this order.
Request send method:
-(void)deleteUserPhotos : (NSString *)contentId : (NSInteger )pathRow : (AVMSMCell *) cell{
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:(unsigned int)pathRow];
if (([selecedCellsArray containsObject:[NSString stringWithFormat:#"%#",rowNsNum]]) )
{
cell.selectedBG.backgroundColor = DANGER;
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSString *token = [defaults objectForKey:#"token"];
NSString *header = [NSString stringWithFormat:#"Bearer %#",token];
NSDictionary *params = #{#"lang": #"en",#"content_id":contentId,#"project_id":[defaults objectForKey:#"project_id"]};
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager.requestSerializer setValue:header forHTTPHeaderField:#"Authorization"];
[manager POST:#"http://example.com/api/project/delete-content" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"JSON: %#", responseObject);
if ([[responseObject objectForKey:#"result"] isEqualToString:#"success"]){
#try{
NSLog(#"pathRow in TRY %ld",(long)pathRow); // HERE I get wrong number after two or three elements already passed
[smArray removeObjectAtIndex:(unsigned int)pathRow];
[selecedCellsArray removeObject:[NSString stringWithFormat:#"%ld",(long)pathRow]];
cell.selectedBG.hidden = YES;
[sortMediaCollection reloadSections:[NSIndexSet indexSetWithIndex:0]];
loadCount--;
}
} #catch (NSException *e){
NSLog(#"something is bad %#",e);
[SVProgressHUD dismiss];
if (smArray.count<pathRow-1){
[smArray removeObjectAtIndex:(unsigned int)pathRow-1];
}
} #finally {
cell.selectedBG.hidden = YES;
[sortMediaCollection reloadSections:[NSIndexSet indexSetWithIndex:0]];
}
} else {
NSLog(#"can't delete photo!");
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"Error: %#", error);
errorEndSpinner
}];
}
}
So in method above I get wrong element number after two or three elements already passed i.e frist element is 5,then 4, then 2, 3,1,0.
And at this moment my #catch handle exception and trying to remove element with [smArray removeObjectAtIndex:(unsigned int)pathRow-1]; and then I get NSRangeException and my app crashing. What I do wrong?
I solved my problem with this answer and little bit modified my code.
I've got an NSRangeException because I removed my UICollectionView items through the loop. Instead I should better use multiple deleting instantly like this:
// Delete the items from the data source.
[self deleteItemsFromDataSourceAtIndexPaths:selectedItemsIndexPaths];
// Now delete the items from the collection view.
[sortMediaCollection deleteItemsAtIndexPaths:selectedItemsIndexPaths];
So now my code looks like:
Pass through the loop:
- (IBAction)deletePictures:(id)sender {
int i = 0;
if (selectedPhotosURL.count>0){
[SVProgressHUD showWithStatus:#"Deleting" maskType:SVProgressHUDMaskTypeBlack];
loadCount = (int)selectedPhotosURL.count;
NSArray *indexPaths = sortMediaCollection.indexPathsForSelectedItems;
NSMutableArray *pathes = [NSMutableArray arrayWithArray:indexPaths];
NSSortDescriptor *highestToLowest = [NSSortDescriptor sortDescriptorWithKey:#"self" ascending:NO];
[pathes sortUsingDescriptors:[NSArray arrayWithObject:highestToLowest]];
[selecedCellsArray sortUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2) {
return [str2 compare:str1 options:(NSNumericSearch)];
}];
for(NSIndexPath *indexPath in pathes) {
AVMSMCell *cell = (AVMSMCell *)[sortMediaCollection cellForItemAtIndexPath:indexPath];
AVMDataStore *oneItem = [smArray objectAtIndex:indexPath.row];
NSString *contentId = oneItem.fileId;
if (i<selectedPhotosURL.count){
[self deleteUserPhotos:contentId : indexPath.row : cell pathes:pathes]; //pass array with pathes into 'deleteUserPhotos'
i++;
}
}
} else {
[self selectAtLeastOneFirst];
}
}
Main method:
-(void)deleteItemsFromDataSourceAtIndexPaths:(NSArray *)itemPaths {
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
for (NSIndexPath *itemPath in itemPaths) {
[indexSet addIndex:itemPath.row];
}
[smArray removeObjectsAtIndexes:indexSet];
}
-(void)deleteUserPhotos : (NSString *)contentId : (NSInteger )pathRow : (AVMSMCell *) cell pathes:(NSMutableArray*)selectedItemsIndexPaths{
NSNumber *rowNsNum = [NSNumber numberWithUnsignedInt:(unsigned int)pathRow];
if (([selecedCellsArray containsObject:[NSString stringWithFormat:#"%#",rowNsNum]]))
{
cell.selectedBG.backgroundColor = DANGER;
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSString *token = [defaults objectForKey:#"token"];
NSString *header = [NSString stringWithFormat:#"Bearer %#",token];
NSDictionary *params = #{#"lang": #"en",#"content_id":contentId,#"project_id":[defaults objectForKey:#"project_id"]};
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager.requestSerializer setValue:header forHTTPHeaderField:#"Authorization"];
[manager POST:#"http://example.com/api/project/delete-content" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"JSON: %#", responseObject);
if ([[responseObject objectForKey:#"result"] isEqualToString:#"success"]){
#try{
[selecedCellsArray removeObject:[NSString stringWithFormat:#"%ld",(long)pathRow]];
loadCount--;
if (loadCount==0){ //only there remove items from collectionview
// Delete the items from the data source.
[self deleteItemsFromDataSourceAtIndexPaths:selectedItemsIndexPaths];
// Now delete the items from the collection view.
[sortMediaCollection deleteItemsAtIndexPaths:selectedItemsIndexPaths];
[selectedPhotosURL removeAllObjects];
}
} #catch (NSException *e){
NSLog(#"something is bad %#",e);
[SVProgressHUD dismiss];
if (smArray.count<pathRow-1){
[smArray removeObjectAtIndex:(unsigned int)pathRow-1];
}
} #finally {
cell.selectedBG.hidden = YES;
[sortMediaCollection reloadSections:[NSIndexSet indexSetWithIndex:0]];
}
} else {
NSLog(#"can't delete photo!");
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"Error: %#", error);
errorEndSpinner
}];
}
}
Hope this will be helpful for somebody.
I was getting the same error but found that it had to do with a different class having a mirrored copy of the array, and that class accessing a deleted index.
You can add an Exception Breakpoint to see exactly where the exception is coming from. Useful for differentiating errors in your code with errors coming from the iOS SDK: NSRangeException when deleting last UICollectionViewCell
I've been stuck on a problem for a few days now. I have searched the internet and found many answers, but nothing that seems to work - I may not grasp how to modify my own code.
I have a JSON connection which I make a dictionary. This all works very well when I dont have a multilevel dictionary, but as soon as I have:
{
"Table": [
{
"MENUID": 1072.0,
"MENUDESC": "HOME ",
"PARENTMENUID": null,
"NAVIGATETO": "content.aspx?item=1072&pid=0",
"NAVIGATETO2": "default.aspx?item=1072&pid=0",
"PROTECTED": null,
"parentmenuid2": null
},
{
"MENUID": 1073.0,
"MENUDESC": "PRODUCTS & SERVICES",
"PARENTMENUID": null,
"NAVIGATETO": "#",
"NAVIGATETO2": "default.aspx?item=1073&pid=0",
"PROTECTED": null,
"parentmenuid2": null
}
]
}
I adapt my code as follows:
- (void)fetchTweets
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:
[NSURL URLWithString: #"http://adhoc.nyxtek.co.za/spfjsonws/default2.aspx"]];
NSError* error;
menuItems = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
NSArray * allKeys = [menuItems allKeys];
NSLog(#"Count : %d", [allKeys count]);
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return menuItems.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TweetCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *tweet = (NSDictionary *)[menuItems objectForKey:#"Table"];
NSArray * allKeys = [tweet allKeys];
NSLog(#"Count : %d", [allKeys count]);
//NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
NSString *text = [tweet objectForKey:#"MENUDESC"];
NSString *name = [tweet objectForKey:#"MENUID"];
cell.textLabel.text = text;
cell.detailTextLabel.text = [NSString stringWithFormat:#"by %#", name];
return cell;
}
Specifically this line of code is not working:
NSDictionary *tweet = (NSDictionary *)[menuItems objectForKey:#"Table"];
My first count of the outer dictionary is 1 which is correct, but my second count of the new above dictionary is 0 which is wrong.
I have applied much of this from researching previous questions as I understand the importance of research, but I still cant seem to find a specific fault.
Any assistance would be appreciated.
Table is an array (of dictionaries):
"Table": [
...
]
So the code should be:
NSArray *tweet = (NSArray *)[menuItems objectForKey:#"Table"];
I have a view controller with a table view. in each cell of the table view, i have an image which is fetched from the net - but many of them have the same image. so, what i'm doing currently is storing the fetched images in a NSCache object. it happens this way:
- (void)fetchAvatarForUser:(NSString *)uid completion:(void (^)(BOOL))compBlock
{
if (!imageCache) {
imageCache = [[NSCache alloc] init];
}
if (!avatarsFetched) {
avatarsFetched = [[NSMutableArray alloc] initWithCapacity:0];
}
if ([avatarsFetched indexOfObject:uid] != NSNotFound) {
// its already being fetched
} else {
[avatarsFetched addObject:uid];
NSString *key = [NSString stringWithFormat:#"user%#",uid];
NSString *path = [NSString stringWithFormat:#"users/%#/avatar",uid];
[crudClient getPath:path parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%#",[operation.response allHeaderFields]);
UIImage *resImage = [UIImage imageWithData:[operation responseData]];
[imageCache setObject:resImage forKey:key];
compBlock(YES);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Got error: %#", error);
compBlock(NO);
}];
}
}
- (UIImage *)getAvatarForUser:(NSString *)uid
{
NSString *key = [NSString stringWithFormat:#"user%#",uid];
NSLog(#"Image cache has: %#",[imageCache objectForKey:key]);
return [imageCache objectForKey:key];
}
imageCache is an instance variable, and also avatarsFetched, crudClient is an AFHTTPClient object.
and, in the table view:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
PostCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[PostCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Post *curPost = [displayedPosts objectAtIndex:indexPath.section];
cell.nickname.text = [curPost nickname];
UIImage *avatarImage = [self.delegateRef.hangiesCommunicator getAvatarForUser:curPost.userID];
if (avatarImage) {
cell.avatar.image = avatarImage;
NSLog(#"Its not null");
} else {
cell.avatar.image = [UIImage imageNamed:#"20x20-user-black"];
}
}
self.delegateRef.hangiesCommunicator returns the object (which is a retained property of the app delegate) with the imageCache as an instance variable, and the two methods at the top.
When i scroll, i see the #"Its not null" in the console, yet i don't see the fetched image but the default 20x20-user-black image. does anybody have an idea, why is this happening? what am i doing wrong?
thanks!
Your code is missing some things. I can't see where you ever call the fetchAvatarForUser:completion: method on your hangiesCommunicator and your tableView:cellForRowAtIndexPath: method is not returning the cell, so I don't think the code you posted will compile cleanly.
Please consider this code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSURL *url = [NSURL URLWithString:#"http://localhost/faq.php?faqType=2"]; // Modify this to
NSString *jsonreturn = [[NSString alloc] initWithContentsOfURL:url]; // Pulls the URL
NSLog(#"jsonreturn=%#",jsonreturn); // Look at the console and you can see what the restults are
NSData *jsonData = [jsonreturn dataUsingEncoding:NSUTF32BigEndianStringEncoding];
NSError *error = nil;
// In "real" code you should surround this with try and catch
NSDictionary *dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error];
if (dict)
{
rows = [[dict objectForKey:#"faq"] retain];
}
[jsonreturn release];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Configure the cell.
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
NSDictionary *dict1 = [rows objectAtIndex:indexPath.row];
NSLog(#"%#", dict1);
cell.textLabel.text = [dict1 objectForKey:#"faqQues"];
}
//if it is not getting NULL value then UItableView is ok
{"faq":[{"faqQues":"this is mr.mack?"},{"faqQues":"is he good man?"}]}
//but if the data is like NULL
{"faq":[{"faqQues":"this is mr.mack?"},{"faqQues":null}]} // then it is creating EXEC_BAD_ACCESS error,
so how to avoid NULL or check null value, or how can i fix this issue?
You can query the value before using it.
if ([dict objectForKey:#"faqQues"] == [NSNull null]) {
// value is null, use your own value here
} else {
// good value to use
}
You can also do this while enumerating as well.
for (id value in dict) {
if (value == [NSNull null]) {
// null
}
}
The docs of TouchJSON state, that JSON null values are represented using the NSNull singleton (usually used to represent nil in collections - where nil is not allowed). So you have to check against [NSNull null].
But TouchJSON allows to override the default null object:
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.nullObject = NULL;
Details https://github.com/TouchCode/TouchJSON (see the "Avoiding NSNull values in output." section)
My fellow programmer Conrad Kramer actually came up with this: https://gist.github.com/3362607
I would change it to a function and replace NULL values with #""