I'm struggling to populate a Table View using JSON Data from Youtube (V 2.1) which has been parsed(Logged the output in the console)
Every time I am loading the Table View Controller, nothing is populated. I have even created a 'Video' class (NSObject). I'm struggling to understand what I'm doing wrong.
The following is my code:
Video.h
#import <Foundation/Foundation.h>
#interface Video : NSObject
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSString *description;
#property (nonatomic, strong) NSString *thumbnail;
#property (nonatomic, strong) NSString *uploadedDate;
#property (nonatomic, strong) NSURL *url;
// Designated Initializer
- (id) initWithTitle:(NSString *)title;
+ (id) videoWithTitle:(NSString *)title;
- (NSURL *) thumbnailURL;
- (NSString *) formattedDate;
#end
Video.m
import "Video.h"
#implementation Video
- (id) initWithTitle:(NSString *)title {
self = [super init];
if ( self ){
self.title = title;
self.thumbnail = nil;
}
return self;
}
+ (id) videoWithTitle:(NSString *)title {
return [[self alloc] initWithTitle:title];
}
- (NSURL *) thumbnailURL {
// NSLog(#"%#",[self.thumbnail class]);
return [NSURL URLWithString:self.thumbnail];
}
- (NSString *) formattedDate {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *tempDate = [dateFormatter dateFromString:self.uploadedDate];
[dateFormatter setDateFormat:#"EE MMM,dd"];
return [dateFormatter stringFromDate:tempDate];
}
#end
Table View Controller implementation file (the one I'm trying to populate)
#import "FilmyViewController.h"
#import "Video.h"
#interface FilmyViewController ()
#end
#implementation FilmyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *videoURL = [NSURL URLWithString:#"http://gdata.youtube.com/feeds/api/users/OrtoForum/uploads?v=2&alt=jsonc"];
NSData *jsonData = [NSData dataWithContentsOfURL:videoURL];
NSError *error = nil;
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
NSLog(#"%#",dataDictionary);
self.videoArray = [NSMutableArray array];
NSArray *videosArray = [dataDictionary objectForKey:#"items"];
for (NSDictionary *vDictionary in videosArray) {
Video *video = [Video videoWithTitle:[vDictionary objectForKey:#"title"]];
video.title = [vDictionary objectForKey:#"title"];
video.description = [vDictionary objectForKey:#"author"];
video.uploadedDate = [vDictionary objectForKey:#"uploaded"];
video.url = [NSURL URLWithString:[vDictionary objectForKey:#"url"]];
[self.videoArray addObject:video];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.videoArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Video *video = [self.videoArray objectAtIndex:indexPath.row];
// Configure the cell...
cell.textLabel.text = video.title;
cell.textLabel.text = video.description;
return cell;
}
/*
#pragma mark - Navigation
// In a story board-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
Here's the JSON which I'm trying to extract from.
I looked for similar topics but didn't get any appropriate solution for this.
Research Link-one and Link-two is what i have been trying to follow.
Please let me know if there is any better approach for this.
What am i missing here?
Solution
Changed
NSArray *videosArray = [dataDictionary objectForKey:#"items"];
to:
NSArray *videosArray = dataDictionary[#"data"][#"items"];
Change
NSArray *videosArray = [dataDictionary objectForKey:#"items"];
to
NSArray *videosArray = dataDictionary[#"data"][#"items"];
Your items array is in the second level: rootJSON -> data -> items
Related
I am using Tableview to display Name from recipes Array which works great and displays all name in table view from recipes Array. When i tap on one of the recipe it displays the name on detailed view.
What i am stuck of is, how to display other fields in the detailed view.I have an Array ( array name: ingredients ) which has contents of that specific recipe, example ingredients.
I tried with
cell.textLabel.text = [ingredients objectAtIndex:indexPath.row];
RecipeDetailViewController.h
#import <UIKit/UIKit.h>
#interface RecipeDetailViewController : UIViewController
#property (nonatomic, strong) IBOutlet UILabel *recipeLabel;
#property (nonatomic, strong) NSString *recipeName;
#property (strong, nonatomic) IBOutlet UILabel *recipeCountry;
#property (nonatomic, strong) NSString *recipeCountryName;
#end
but it doesn't show anything in RecipeBookViewController.m
Here is my Original code
#import "RecipeBookViewController.h"
#import "RecipeDetailViewController.h"
#interface RecipeBookViewController ()
#end
#implementation RecipeBookViewController {
NSArray *recipes;
}
#synthesize tableView;
- (void)viewDidLoad
{
[super viewDidLoad];
NSData *allCourseData=[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://api.kivaws.org/v1/loans/search.json?status=fundraising"]];
NSError *error;
NSMutableDictionary *JsonObject = [NSJSONSerialization
JSONObjectWithData:allCourseData options:NSJSONReadingMutableContainers
error:&error];
NSArray *loans = JsonObject[#"loans"];
// Create a new loans array for store the new items
NSMutableArray *newLoans = [NSMutableArray array];
NSMutableArray *arrCountry = [NSMutableArray array];
for (NSDictionary *loan in loans) {
NSNumber *ident = loan[#"id"];
NSString *name = loan[#"name"];
NSDictionary *description = loan[#"description"];
NSDictionary *location = loan[#"location"];
NSString *country = location[#"country"];
NSString *status = loan[#"status"];
NSDictionary *geo = location[#"geo"];
NSString *geoprint = geo[#"pairs"];
[newLoans addObject:name];
[arrCountry addObject:country];
}
recipes=newLoans;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [recipes count];
}
//Display Name in Detail View
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"RecipeCell";
//Displays name
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [recipes objectAtIndex:indexPath.row];
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showRecipeDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
RecipeDetailViewController *destViewController = segue.destinationViewController;
destViewController.recipeName = [recipes objectAtIndex:indexPath.row];
}
}
#end
RecipeDetailViewController.m
#import "RecipeDetailViewController.h"
#interface RecipeDetailViewController ()
#end
#implementation RecipeDetailViewController
#synthesize recipeLabel;
#synthesize recipeName;
#synthesize recipeCountry;
#synthesize recipeCountryName;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Set the Label text with the selected recipe
recipeLabel.text = recipeName;
recipeCountry.text=recipeCountryName;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Here are the screenshots of both Views
Changes in your loop;
for (NSDictionary *loan in loans) {
NSNumber *ident = loan[#"id"];
NSString *name = loan[#"name"];
NSDictionary *description = loan[#"description"];
NSDictionary *location = loan[#"location"];
NSString *country = location[#"country"];
NSString *status = loan[#"status"];
NSDictionary *geo = location[#"geo"];
NSString *geoprint = geo[#"pairs"];
[newLoans addObject:#[
#"name":name,
#"description":description,
#"country ":country
]]; // Same way add all keys
//Or
/*
NSMutableDictionary* dicData = [NSMutableDictionary dictionary];
newLoans[#"name"] = name;
newLoans[#"description"] = description;
newLoans[#"country"] = country;
[newLoans addObject:dicData];
*/
}
recipes=newLoans;
Change when retrieving;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
. . .
NSDictionary * dict = [recipes objectAtIndex:indexPath.row];
cell.textLabel.text = dict[#"name"];
return cell;
}
Same way pass the complete dictionary to the RecipeDetailViewController and show other information there.
I am new to iOS programming and I need some advice. I want to create a table view with sections to learn how it works. I have some objects from a model class user. I fill data in the table view using dictionaries. The table view is in a view Controller in my storyboard. The code works, but I don't know if this is a good way to handle the data in my table. Is this a semantic mistake to do this like I did?
Please take a Look at my code and give me some advice.
My user object (User.h):
#interface User : NSObject
#property (nonatomic, strong) NSString *email;
#property (nonatomic, strong) NSString *firstName;
#property (nonatomic, strong) NSString *lastName;
#property (nonatomic, strong) NSString *city;
#end
Dummy function to fill users into an array (in a helper class):
- (NSMutableArray *) createUser
{
NSMutableArray *userArray = [[NSMutableArray alloc] init];
User *user1 = [[User alloc] init];
user1.firstName = #"Donald";
user1.lastName = #"Duck";
user1.email = #"donald_duck#disney.com";
user1.city = #"Entenhausen";
User *user2 = [[User alloc] init];
user2.firstName = #"Micky";
user2.lastName = #"Maus";
user2.email = #"micky#disney.com";
user2.city = #"Entenhausen";
User *user3 = [[User alloc] init];
user3.firstName = #"Daisy";
user3.lastName = #"Duck";
user3.email = #"daisy_duck#disney.com";
user3.city = #"Frankfurt";
User *user4 = [[User alloc] init];
user4.firstName = #"Goofy";
user4.lastName = #"Goof";
user4.email = #"goofy#disney.com";
user4.city = #"Berlin";
User *user5 = [[User alloc] init];
user5.firstName = #"Some";
user5.lastName = #"Body";
user5.email = #"somebody#disney.com";
user5.city = #"Somewhere";
User *user6 = [[User alloc] init];
user6.firstName = #"Dagobert";
user6.lastName = #"Duck";
user6.email = #"dagobert#disney.com";
user6.city = #"Mainz";
[userArray addObject:user1];
[userArray addObject:user2];
[userArray addObject:user3];
[userArray addObject:user4];
[userArray addObject:user5];
[userArray addObject:user6];
return userArray;
}
Function to create a dictionary object (in a helper class):
- (NSMutableDictionary *) createDictionaryFromArray: (NSMutableArray *) allData
{
NSArray *arrayKeys = [[NSArray alloc] initWithObjects:#"Entenhausen", #"Frankfurt", #"Berlin", #"Mainz", nil];
NSMutableDictionary *collection = [[NSMutableDictionary alloc] init];
for (int i=0; i < arrayKeys.count; i++) {
NSString *key = [arrayKeys objectAtIndex:i];
NSMutableArray *allValues = [[NSMutableArray alloc] init];
for (User *usr in allData) {
if([usr.city isEqualToString:key]) {
[allValues addObject:usr];
}
}
[collection setObject:allValues forKey:key];
}
return collection;
}
My table view controller class (TableViewController.h):
#import <UIKit/UIKit.h>
#import "HelperClass.h"
#interface TableViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource> {
HelperClass *helper;
NSMutableArray *users;
NSArray *allKeys;
NSDictionary *dictionaryUsers;
}
TableViewController.m:
#import "TableViewController.h"
#implementation TableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
helper = [[HelperClass alloc] init];
users = [[NSMutableArray alloc] init];
users = [helper createUser];
dictionaryUsers = [[NSMutableDictionary alloc] init];
dictionaryUsers = [helper createDictionaryFromArray:users];
allKeys = [NSArray array];
allKeys = [dictionaryUsers allKeys];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{ // Return the number of sections.
return [allKeys count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSMutableArray *arrayValuesUsers = [[NSMutableArray alloc] init];
arrayValuesUsers = [dictionaryUsers objectForKey:[allKeys objectAtIndex:section]];
return [arrayValuesUsers count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [allKeys objectAtIndex:section];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
User *user = [[User alloc] init];
NSMutableArray *usersInSection = [dictionaryUsers objectForKey:[allKeys objectAtIndex:indexPath.section]];
user = [usersInSection objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%#, %#", user.lastName, user.firstName];
cell.detailTextLabel.text = user.email;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *usersInSection = [dictionaryUsers objectForKey:[allKeys objectAtIndex:indexPath.section]];
User *usr = [usersInSection objectAtIndex:indexPath.row];
NSLog(#"user: %#, %#", usr.lastName, usr.firstName);
}
#end
First of all thumbs up for using a HelperClass for implementing general functions. Only when you do it, make it at least a singleton, so that you not always have to call:
helper = [[HelperClass alloc] init];
Or if you only have functions like createUser, these methods should be class methods.
Here are two general hints, which came to my mind, when looking at your code:
You have too many allocations in your code. For example in your TableViewController you do:
users = [[NSMutableArray alloc] init];
users = [helper createUser];
So first you allocate a new array and the first thing the createUser function does is to allocate another array in memory, which is then returned. Your first allocated memory space is never used.
When it comes to tableViews don't use dictionaries. Always stick with arrays. A dictionary is not ordered and when iterating through a dictionary you might get different results each time. An array is ordered and objectOfIndex:i will always return the same object.
So I adjusted your code to have a dynamic tableView sorting your users into sections by their city and sorting them alphabetically. (I guess this was what you wanted to achieve). The new code is not completely clean. You could try to use NSArray instead of NSMutableArray everywhere to save some memory for example.
Your User.h is untouched.
Here is the new HelperClass.h
// HelperClass.h
#import <Foundation/Foundation.h>
#interface HelperClass : NSObject
+ (HelperClass *)sharedHelperClass;
+ (NSMutableArray *) createUser;
+ (NSMutableArray *) getAllCitiesFromUserArray: (NSMutableArray *)userArray;
+ (NSMutableArray *)getUsersOfUsersArray: (NSMutableArray *)userArray fromCity: (NSString *)city;
#end
And the HelperClass.m
// HelperClass.m
#import "HelperClass.h"
#import "User.h"
#implementation HelperClass
+ (HelperClass *)sharedHelperClass
{
//This returns always the same object of HelperClass
static dispatch_once_t pred;
static HelperClass *_sharedHelperClass = nil;
dispatch_once(&pred, ^{ _sharedHelperClass = [[self alloc] init]; });
return _sharedHelperClass;
}
- (id)init{
self = [super init];
if (!self) {
return nil;
}
return self;
}
+ (NSMutableArray *) createUser
{
NSMutableArray *userArray = [[NSMutableArray alloc] init];
User *user1 = [[User alloc] init];
user1.firstName = #"Donald";
user1.lastName = #"Duck";
user1.email = #"donald_duck#disney.com";
user1.city = #"Entenhausen";
User *user2 = [[User alloc] init];
user2.firstName = #"Micky";
user2.lastName = #"Maus";
user2.email = #"micky#disney.com";
user2.city = #"Entenhausen";
User *user3 = [[User alloc] init];
user3.firstName = #"Daisy";
user3.lastName = #"Duck";
user3.email = #"daisy_duck#disney.com";
user3.city = #"Frankfurt";
User *user4 = [[User alloc] init];
user4.firstName = #"Goofy";
user4.lastName = #"Goof";
user4.email = #"goofy#disney.com";
user4.city = #"Berlin";
User *user5 = [[User alloc] init];
user5.firstName = #"Some";
user5.lastName = #"Body";
user5.email = #"somebody#disney.com";
user5.city = #"Somewhere";
User *user6 = [[User alloc] init];
user6.firstName = #"Dagobert";
user6.lastName = #"Duck";
user6.email = #"dagobert#disney.com";
user6.city = #"Mainz";
[userArray addObject:user1];
[userArray addObject:user2];
[userArray addObject:user3];
[userArray addObject:user4];
[userArray addObject:user5];
[userArray addObject:user6];
return userArray;
}
+ (NSMutableArray *) getAllCitiesFromUserArray: (NSMutableArray *)userArray{
NSMutableArray *cityArray = [[NSMutableArray alloc] init];
for (User *user in userArray) {
if (![cityArray containsObject: user.city]){
[cityArray addObject:user.city];
}
}
//Sort the city array alphabetically (localizedCaseInsensitiveCompare even regards Umlaute)
[cityArray sortUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
return cityArray;
}
+ (NSMutableArray *)getUsersOfUsersArray: (NSMutableArray *)userArray fromCity: (NSString *)city{
NSMutableArray *usersOfCityArray = [[NSMutableArray alloc] init];
for (User *user in userArray) {
if ([user.city isEqualToString:city]){
[usersOfCityArray addObject:user];
}
}
//Sort the array of custom objects by key lastName
NSSortDescriptor *sortDescriptor =
[NSSortDescriptor sortDescriptorWithKey:#"lastName"
ascending:YES
selector:#selector(localizedCaseInsensitiveCompare:)];
usersOfCityArray = [[usersOfCityArray sortedArrayUsingDescriptors:#[sortDescriptor]]mutableCopy];
return usersOfCityArray;
}
#end
The new TableViewController.h
// TableViewController.h
#import <UIKit/UIKit.h>
#interface TableViewController : UITableViewController
#end
And the new TableViewController.m
// TableViewController.m
#import "TableViewController.h"
#import "HelperClass.h"
#import "User.h"
#interface TableViewController ()
#property (nonatomic,strong) NSMutableArray *users;
#property (nonatomic,strong) NSMutableArray *sectionHeaders;
#end
#implementation TableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//This gets the Array of Users from the HelperClass class method
//You could access the HelperClass Singleton with [HelperClass sharedHelperClass], but this is not needed in this case.
self.users = [HelperClass createUser];
self.sectionHeaders = [HelperClass getAllCitiesFromUserArray:self.users];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [self.sectionHeaders count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//Get the current section city
NSString *city = [self.sectionHeaders objectAtIndex:section];
NSMutableArray *sectionUsers =[HelperClass getUsersOfUsersArray:self.users fromCity:city];
return sectionUsers.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [self.sectionHeaders objectAtIndex:section];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
//Get the current section city
NSString *city = [self.sectionHeaders objectAtIndex:indexPath.section];
//Get users for the current city
NSMutableArray *sectionUsers =[HelperClass getUsersOfUsersArray:self.users fromCity:city];
//Get the user for the current cell
User *user = [sectionUsers objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%#, %#", user.lastName, user.firstName];
cell.detailTextLabel.text = user.email;
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Get the current section city
NSString *city = [self.sectionHeaders objectAtIndex:indexPath.section];
//Get users for the current city
NSMutableArray *sectionUsers =[HelperClass getUsersOfUsersArray:self.users fromCity:city];
//Get the user for the current cell
User *user = [sectionUsers objectAtIndex:indexPath.row];
NSLog(#"user: %#, %#", user.lastName, user.firstName);
}
#end
there is a strange problem I have not met ever
there is an array() including some custom object named MyClass parsed by JSONKit;
when I keep scrolling the tableview the memory will keeping increasing too.
but when replace
cell.textLabel.text = myclass.name;
with
cell.textLabel.text = #"cool";
or
cell.textLabel.text = [NSString stringWithFormate:#"a-%d", indexPath.row];
it's ok the memory with keep stable
but if I use
cell.textLabel.text = [NSString stringWithFormate:#"a-%#-i",myclass.name, indexPath.row];
it also keep increasing;
It will drive my crazy!!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Singers";
OMTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
MyClass *myclass = [self.data objectAtIndex:indexPath.row];
if (cell == nil){
cell = [[[OMTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
}
cell.textLabel.text = myclass.name;
return cell;
}
MyClass
there is two class one Base another inherit
Base:
#interface OMBase : NSObject {
NSMutableDictionary *data;
NSString *name;
NSArray *keys;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, copy) NSMutableDictionary *data;
#implementation OMBase
#synthesize data, name;
- (void)setData:(NSMutableDictionary *)adata{
if (data){
[data release];
data = nil;
}
data = [adata mutableCopy];
}
- (void)dealloc{
if (keys){
[keys release];
}
[data release];
[super dealloc];
}
- (id)init{
if (self = [super init]){
self.data = [[[NSMutableDictionary alloc] initWithCapacity:20] autorelease];
}
return self;
}
inherit:
#import "OMBase.h"
#interface OMLyric : OMBase
- (NSString *)songid;
- (NSString *)content;
#import "OMLyric.h"
#implementation OMLyric
- (NSString *)songid{
return [data objectForKey:#"songid"];
}
- (NSString *)content{
return [data objectForKey:#"content"];
}
Seems like your myclass.name getter returns a new allocated object. We can't say more without seeing myclass.
If one had a NSString that needed a userid to be used as a URL for a request:
And one had a NSMutableArray that he wanted to Queue into the above call one at a time? So basically make 3 calls of NSString from the NSMutableArray .
One can check multiple UITableView cells and once completed I can index which cell rows were pushed. That is what userIDArray is used for now I want to make a call with the userID's I got back from userIDArray.
for (NSDictionary* userIDDict in userIDArray)
{
userIDArray = [[NSMutableArray alloc] init]; //I put this line in my viewdidload
NSNumber* userID = [userIDDict objectForKey:#"UserID"];
}
UserIDArray is the NSMutableArray .
This would be the NSLog from the NSMutableArray The Integer would be 1, 2 and 3.
UserID: 1
UserID: 2
UserID: 3
So in other words I would like to take the results from my NSMultiTableArray 1,2 and 3 to use within the NSString :
NSString *userProfile = [NSString stringWithFormat:#"http://example.com/userid=1"];
NSString *userProfile = [NSString stringWithFormat:#"http://example.com/userid=2"];
NSString *userProfile = [NSString stringWithFormat:#"http://example.com/userid=3"];
So I would make the first call and wait for a result, and then the second and finally the third.
Can this be done? I have search this link about Queues and this one but I am unsure if those are what I need?
UserDetailViewController.h file:
#interface UserDetailViewController : UIViewController <UITableViewDelegate>{
long long expectedLength;
long long currentLength;
UITableView *userTableView;
NSIndexPath* checkedIndexPath;
}
#property (nonatomic, retain) NSArray *userIDJson;
#property (strong, nonatomic) NSDictionary *userIDDict;
#property (nonatomic, retain) NSIndexPath* checkedIndexPath;
#property (nonatomic, strong) NSMutableArray *userIDArray;
#property (nonatomic) NSInteger currentUserIndex;
#end
UserDetailViewController.m file:
#interface UserDetailViewController ()
#end
#implementation UserDetailViewController
#synthesize userIDJson;
#synthesize userIDDict;
#synthesize checkedIndexPath;
#synthesize userIDArray;
#synthesize currentUserIndex;
- (void)viewDidLoad
{
[super viewDidLoad];
userIDArray = [[NSMutableArray alloc] init];
[self.navigationController setNavigationBarHidden:NO];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//return self.loadedSearches.count;
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.userIDJson.count;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
}
cell.textLabel.text = self.userIDJson[indexPath.row][#"UserName"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if([self.checkedIndexPath isEqual:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
NSString *userStringIndex = [self.userIDJson objectAtIndex:indexPath.row];
if (thisCell.accessoryType == UITableViewCellAccessoryNone)
{
thisCell.accessoryType = UITableViewCellAccessoryCheckmark;
[userIDArray addObject:userStringIndex];
}
else
{
thisCell.accessoryType = UITableViewCellAccessoryNone;
[userIDArray removeObject:userStringIndex];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (self.currentUserIndex < userIDArray.count) {
NSNumber* userID = [[userIDArray objectForIndex:currentUserIndex]objectForKey:#"UserID"];
//Make the actual request here, and assign the delegate.
NSString *userProfile = [NSString stringWithFormat:#"http://example.com/userid=%#",userID];
self.currentUserIndex++;
NSData *dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString:userProfile]];
NSString *userResult = [[NSString alloc] initWithData:dataURL encoding:NSUTF8StringEncoding];
NSURL *url = [[NSURL alloc] initWithString: userProfile];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
userIDJson = [NSJSONSerialization JSONObjectWithData:dataURL
options:kNilOptions
error:&error];
}
}
for (userIDDict in userIDArray)
{
NSNumber* userID = [userIDDict objectForKey:#"UserID"];
NSLog(#"%#", userID);
NSArray* userName = [userIDDict objectForKey:#"UserName"];
}
NSURLConnection can take a delegate through the constructor initWithRequest:delegate:. So you need the object that makes the calls conform to that protocol, I'll assume it's a UIViewController. You can use one of the required methods in the delegate to fire up the next request.
For example, assume you have property to indicate the current index.
#property (nonatomic) NSInteger currentUserIndex;
Then in the place that will fire the first request, make the call for the first user. In some delegate method, say connectionDidFinishLoading:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (self.currentUserIndex < self.userIDArray.count) {
NSNumber* userID = [[self.userIDArray objectAtIndex:self.currentUserIndex] objectForKey:#"UserID"];
self.currentUserIndex++;
//Make the actual request here, and assign the delegate.
}
}
Of course, if your connection calls don't have to be synchronous, you can do it in an easier way.
I think just showing my whole code is better than my explanation.. actually I'm not good at expressing something in English.X(
this code is .h file for .m file below.
#import <UIKit/UIKit.h>
#define kImageValueTag 0
#define kNameValueTag 1
#define kSubtitleValueTag 2
#define kMemoValueTag 3
#class PhonebookDetailedViewController;
#interface PhonebookViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
UITableViewCell *tvCell;
UITableView *tableView;
UISearchBar *searchBar;
NSString *fullName;
NSMutableDictionary *names, *pictures;
NSArray *keys, *sortedKeys, *sortedAllValues;
PhonebookDetailedViewController *childController;
}
#property (nonatomic, retain) IBOutlet UITableViewCell *tvCell;
#property (nonatomic, retain) IBOutlet UISearchBar *searchBar;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
#property (nonatomic, retain) UIImage *phoneImage;
#property (nonatomic, retain) NSString *fullName;
#property (nonatomic, retain) NSMutableDictionary *names;
#property (nonatomic, retain) NSMutableDictionary *pictures;
#property (nonatomic, retain) NSArray *keys;
#property (nonatomic, retain) NSArray *sortedKeys;
#property (nonatomic, retain) NSArray *sortedAllValues;
#end
this code is for the .m file that implement showing a table. When I try to scroll the table down, the error named EXC_BAD_ACCESS is suddenly called at - (NSString *)tableView: titleForHeaderInSection: method. I guess sortedKeys releases at somewhere because I can do [sortedKeys count] before error, but cannot when error comes. I don't know where it releases and why it releases, however. Please show your ideas to me. Any ideas are okay. Thank you in advance.
#import "PhonebookViewController.h"
#import "PhonebookDetailedViewController.h"
#import "NSString-SortForIndex.h"
#implementation PhonebookViewController
#synthesize tvCell;
#synthesize searchBar;
#synthesize tableView;
#synthesize phoneImage;
#synthesize fullName;
#synthesize names, pictures;
#synthesize keys, sortedAllValues, sortedKeys;
//- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
//{
// self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
// if (self) {
// // Custom initialization
// }
// return self;
//}
//- (void)didReceiveMemoryWarning
//{
// // Releases the view if it doesn't have a superview.
// [super didReceiveMemoryWarning];
//
// // Release any cached data, images, etc that aren't in use.
//}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect bounds = self.tableView.bounds;
bounds.origin.y = bounds.origin.y + searchBar.bounds.size.height;
self.tableView.bounds = bounds;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *nameFilePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"nameContacts.dict"];
NSString *pictureFilePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"imageContacts.dict"];
self.names = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:nameFilePath];
self.pictures = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:pictureFilePath];
self.keys = [self.names allKeys];
sortedKeys = [self.keys sortedArrayUsingSelector:#selector(sortForIndex:)];
sortedAllValues = [[NSArray alloc] init];
for (NSString *sortedKey in sortedKeys)
{
NSArray *selectedValues = [self.names valueForKey:sortedKey];
for (NSString *selectedValue in selectedValues)
sortedAllValues = [sortedAllValues arrayByAddingObject:selectedValue];
}
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.tableView = nil;
self.searchBar = nil;
self.tvCell = nil;
self.fullName = nil;
self.names = nil;
self.pictures = nil;
self.keys = nil;
self.sortedKeys = nil;
self.sortedAllValues = nil;
}
- (void)dealloc
{
[tableView release];
[searchBar release];
[tvCell release];
[fullName release];
[names release];
[pictures release];
[keys release];
[sortedKeys release];
[sortedAllValues release];
[super dealloc];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table Data Source Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [sortedKeys count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *key = [sortedKeys objectAtIndex:section];
NSArray *nameSection = [names objectForKey:key];
return [nameSection count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CustomCellIdentifier = #"CustomCellIdentifier";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CustomCellIdentifier];
if ( cell == nil )
{
NSArray *nib = [[NSBundle mainBundle]
loadNibNamed:#"CustomPhonebookCell"
owner:self
options:nil];
if (nib.count > 0)
{
cell = self.tvCell;
} else
{
NSLog(#"Failed to load CustomPhonebookCell nib file!");
}
}
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
NSUInteger row = [indexPath row];
NSUInteger section = [indexPath section];
NSString *foundKey = [sortedKeys objectAtIndex:section];
NSArray *nameSection = [self.names objectForKey:foundKey];
UILabel *nameLabel = (UILabel *)[cell viewWithTag:kNameValueTag];
nameLabel.text = [nameSection objectAtIndex:row];
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *key = [sortedKeys objectAtIndex:section]; // EXC_BAD_ACCESS error at here
return key;
}
sortedKeys is not properly retained. When you set it use self.
self.sortedKeys = [self.keys sortedArrayUsingSelector:#selector(sortForIndex:)];