There are many question asked in regard to this topic but i haven't been able to find the answer.
I am working on a react native app and I need to covert this dictionary:
NSDictionary *title = #{ #"title": #"a journey to heaven",
#"title": #"history of gun Powder",
#"title": #"intro to Java"} ;
I want to be able to convert this into JSON so that I can reference the elements in table view as array.title
Please help, Thanks!
Its not entirely clear why you want to convert to JSON. But I think I understand that you want to be able to reference your collection in a tableview, right? If thats all you need to do, you dont need JSON, you just need an array. You could just do this - first declare a class property (means the entire class can access it, declared in the header file)
#property (strong, nonatomic) NSArray *titles;
Then declare the array in an initial array like viewDidLoad :
- (void) viewDidLoad {
self.titles = #[#"a journey to heaven", #"history of gun Powder", #"intro to Java"];
}
In the numberOfRowsInSection method, return the size of the array, eg :
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.titles.count;
}
Then finally in the cellForRowAtIndexPath method, access your array to populate the cell in the tableview :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
cell.textLabel.text = [self.titles objectAtIndex:indexPath.row];
return cell;
}
Thats not everything you need for a tableview but its the most important bits. Have a look at a tableview tutorial, of which there are thousands on the net.
In my experience, you only need to think about converting to JSON (string for eg) when either saving a file to disc or posting it to a web service. You didnt mention doing that though, so Im hoping this is what you need.
Related
I have an app, in which I have 7 different UITableViewControllers. All 7 are linked through a tabBarController. I am looking for a way to have a single custom class to be used throughout all 7 UITableViewControllers. I have 7 different arrays that all hold a specific number of objects. I need to know how to:
Change the number of rows in the tableView, depending on the array that I'm using as my data source.
Change the array that is being used as the data source based on which ViewController the user is currently looking at (Can this even be done?)
Change the contents of a cell, based on the array being used as the data source.
I'm familiar with using UITableView with a single data source, but I really don't know how to approach it with multiple data sources.
Thanks!
You can have one class be the dataSource for all of the UITableViewControllers
You might implement this by creating a custom subclass of UITabBarController which keeps an array of UITableViewControllers and a corresponding dictionary that maps a UITableVC to the array used by it's data source.
Set that as the data source for all the UITableViews and then handle each dataSource method like my example below.
Take a look at the UITableViewDataSource docs.
All of the methods pass in which tableView they're trying to get information about.
For example:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Here you could compare the tableView var to your array of tableViews to figure out which table view called this
//Based on that you could query your dictionary to find the array that houses the data for that tableView.
//Use the indexPath to find the data that you need to create and return the right cell
}
• Change the number of rows in the tableView, depending on the array
that I'm using as my data source.
You can accomplish this by conditions in tableView delegates
- (NSInteger)tableView:tableView numberOfRowsInSection:section
Inside this delegate you need to identify which dataSource for the particular tableView.
Check the table if its the one being refreshed like so:
- (NSInteger)tableView:tableView numberOfRowsInSection:section
{
if (tableView == self.firstTableView)
return self.firstTableDataSource.count;
if (tableView == self.secondTableView)
return self.secondTableDataSource.count;
//and so on..
}
• Change the array that is being used as the data source based on
which ViewController the user is currently looking at (Can this even
be done?)
Figuring which array you will be using for that particular table is up to you. You can use segement control, buttons, another table, it's up to you.
But the very important part is [tableView reloadData]; at your target table (table that is currently active) and again table delegates will be triggered and you will be doing all the filtering inside those delegates..
while you can check if the viewController is visible by:
if ([self/*viewController*/ isViewLoaded] && self/*viewController*/.view.window)
{
//visible
}
which was already discussed here
• Change the contents of a cell, based on the array being used as the
data source.
This one is not clear.
Is it just the content/values of the subviews of the cell like: cell.textLabel, cell.detailTextLabel and cell.imageView?
or the cell.contentView which is basically, you want to change the look of your cell?
If content/values again you just have to determine which is which, like this (using customCell):
assuming you have a dataSource that looks like:
{
data_source = (
{
text_label = test0;
detail_label = "this is just a text";
image_name = "your_image0.png";
},
{
text_label = test1;
detail_label = "this is just a another text";
image_name = "your_image1.png";
}
)
}
then in the delegate cellForRowAtIndexPath it'll be something like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = #"tableID";
self.customCell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (!self.customCell)
self.customCell = [[YourCustomCell alloc] initWithStyle:(UITableViewCellStyle) reuseIdentifier:cellID];
static NSString *dataSource = #"data_source";
static NSString *textLabel = #"text_label";
static NSString *detailLabel = #"detail_label";
static NSString *imageName = #"image_name";
if (tableView == self.firstTableView)
{
self.customCell.textLabel.text = [self.firstDataSource valueForKey:dataSource][indexPath.row][textLabel];
self.customCell.detailTextLabel.text = [self.firstDataSource valueForKey:dataSource][indexPath.row][detailLabel];
self.customCell.imageView.image = [UIImage imageNamed:[self.firstDataSource valueForKey:dataSource][indexPath.row][imageName]];
}
if (tableView == self.secondTableView)
{
self.customCell.textLabel.text = [self.secondDataSource valueForKey:dataSource][indexPath.row][textLabel];
self.customCell.detailTextLabel.text = [self.secondDataSource valueForKey:dataSource][indexPath.row][detailLabel];
self.customCell.imageView.image = [UIImage imageNamed:[self.secondDataSource valueForKey:dataSource][indexPath.row][imageName]];
}
// and so on...
}
To check all other methods, check apples documentation ,i hope this is useful for you and for others as well.. Happy coding.. :)
I'm using a webservice to fill an array of items, which then are used to fill cells of my table view.
Now i'm having an issue with the table view itself. When I check the " numberofrows" method, the array isn't loaded yet. For some reason it loads "right after" that (according to my nslogs & breakpoints), even though i've put every loading method as early as i could in that controller.
Now what i don't know is :
is there a way to delay the table view creation so i'm sure my array is loaded?
is there a way to load my array earlier? It's currently my first line in the viewDidLoad. (calling another class, which then calls the webservice and returns an array, but by then, the table view is already loaded and empty).
What i've tried : Putting a tableview reloadData. But it simply doesn't work. For some reason the compiler reads the line but doesn't load anything new, even though at that point the array is full.
Am i missing something?
(My tableview works just fine if I put hardcoded objects in my array)
I can edit and add some code that you guys would request, but since this looks like a school problem here, maybe i just forgot something.
Guys, i'm all ears !
Edit :
My different methods ; i've removed unecessary code for clearer reading.
The compiler NEVER goes in the cellForRow because numberOfRows is returning a zero number.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"CustomCellTableViewCell";
CustomCellTableViewCell *cell = [self.tbUpcomingEvents dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
cell.lbTitle = [_eventList objectAtIndex:indexPath.row];
return cell;
}
number of rows ; the nslog returns zero.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"numOfRows : %i", [_eventList count]);
return [_eventList count];
}
my webservice method, this is the method calle from the "webservice class" to load the data.
Here, the NSLog shows a full array.
- (void)loadData:(NSMutableArray*)arrayEvent
{
//arrayEvent is full from the internet data. eventList is also full on the NSLog.
_eventList = arrayEvent;
NSLog(#"LoadData : %i", [_eventList count]);
[self.tbUpcomingEvents reloadData];
}
my viewdidLoad method
- (void)viewDidLoad
{
[super viewDidLoad];
//Calling my UseCaseController to load the data from the internet.
UCC *sharedUCC = [UCC sharedUCC];
[sharedUCC getUserEventsInDbDis:self :_user];
}
As you said you are using webservices. So it is executing your code in the block which means it is running in separate thread. Now as per apple documentation UI updates should happen in main thread. So for table creation you need to include the same in below GCD code:-
dispatch_async(dispatch_get_main_queue,()^{
// write your code for table creation here
});
I am populating a tableview from data that is received from a server. The data is a list of user activities within a given timeframe. One such activity is "Login". I do not wish to populate my tableview with this string but I'm not sure how to skip it when populating my tableview.
Here is how I populate the cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
#try{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *action = [object valueForKey:#"theActionName"];
if ([action isEqualtoString:#"Login"]) {
return cell;
}
return cell;
}#catch (NSException *ex) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
}
As you can see I tried using return cell but as you probably know it gives me a blank cell when the table is displayed. I'm sure there is a simple line of code for this but I came up blank with the search terms I used. Could someone please enlighten me! Thanks!
P.S. you may be thinking I am not putting anything in any of the cells but I pulled out a bunch of code to keep this short.
UPDATE:
Thanks for the heads up on "isEqualtoString:" Everything worked fine with "isEqual" but I changed it given that I received so many suggestions to do so. But this is not what I am asking.
To be more clear if I had an array containing the terms: view, view, login, view. When my tableview was populated I would have 4 cells that said; view, view, login, view. I simply want to ignore the term login so that I would have 3 cells that all said view. Thanks!
There can be many way to do this.
I Belive that UITabelView should display what its datasource (here datasource is self.fetchedResultsController) contains.
What you can do is create another NSArray from self.fetchedResultsController which does not contain this object.
Try this:
NSMutableArray *newSource = [[NSMutableArray alloc] init];
for(int i = 0; i < self.fetchedResultsController.count ; i++)
{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *action = [object valueForKey:#"theActionName"];
if (![action isEqual:#"Login"])
{
[newSource addObject:action];
}
}
[tableView reloadData];
Now use newSource instead of self.fetchedResultsController
You might think that using one more array is not good. But believe it it is far easier than using the same array with condition. You don't have to worry about that condition when you perform some operation with your UITableView like remove object by using indexpath.
try using if ([action isEqualToString:#"Login"])
When you want to compare strings you need to use this isEqualToString .
Change this line
if ([action isEqualToString:#"Login"]) {
return cell;
}
You are using the wrong function to compare your input string and the given data variable.
They both are NSString objects so use :
if([action isEqualToString:#"Login"])
{
//enter your code here
}
#Ben : I am assuming that you have registered you cell through nib as you are using dequeueReusableCellWithIdentifier.
Make your tableview content as "Dynamic prototype" (You can see this in Attributes Inspector of table view) and change your table view cell style as custom (You can see this in Attributes Inspector of tableview cell).
I have this code:
#interface MyBusinessesController : UIViewController
{
NSDictionary *businesses;
NSArray *items_array;
}
#property (weak, nonatomic) IBOutlet UILabel *messageLabel;
- (IBAction)plan:(id)sender;
#property (weak, nonatomic) IBOutlet UITableView *itemList;
#end
and I set the UITableView and the NSArray in the header area of the .m file. Then I have a remote server call and get back JSON. I get the JSON data into an array like this:
items_array = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
Then I loop through the items like this:
for (int i = 0; i<= items_array.count - 1; i++)
{
NSDictionary *dict = [items_array objectAtIndex:i];
NSString *item_title = [dict objectForKey:#"item_title"];
NSString *item_id = [dict objectForKey:#"item_id"];
...
and then I would like to add it as a row in my UITableView, but I am struggling with how to do it now.
What I would want is to display the item_title to the user, and when the user presses the title that I would be able to know how to get the item_id of that item_title.
Thank you!
You need to implement the required methods in the UITableViewDataSource protocol, and set the dataSource property of the tableView to self.
Accordingly, implement the appropriate UITableViewDelegate methods, and set the delegate property of your tableView to self.
See the documentation for details on which methods are required, and which optional methods you might want to implement.
Don't forget to advertise in your .h file that your Class conforms to both protocols:
#interface MyBusinessesController : UIViewController <UITableViewDataSource, UITableViewDelegate>
You can make the tableView refresh its content by calling [itemList reloadData].
Table views work differently to what you appear to be used. You don't loop over your data and fill the table. Instead, you set yourself as table's delegate and then the table will ask you:"How much data do you have, what data do you want at row 5" and so on.
I'd really suggest you go over this great tutorial here:
http://kurrytran.blogspot.com/2011/10/ios-5-storyboard-uitableview-tutorial.html
Instead of looping through the array and pulling out the string values you can let the data source methods for UITableView handle this. So in cellForRowAtIndexPath method you would index your items_array with the index path as such:
NSDictionary *dict = [items_array objectAtIndex:[indexPath row]];
Then you would pull the strings out of the dictionary like you did in the loop and set the title for the cell to the string. For selecting the cell, you can write your code in the didSelectRowAtIndexPath method.
Here is an example from a project I was working on:
#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 [items_array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault)
reuseIdentifier:#"cell"];
NSDictionary *dict = [items_array objectAtIndex:[indexPath row]];
cell.textLabel.text = [dict objectForKey:#"item_name"];
return cell;
}
The first method specifies the number of sections you want in your table. If you want a very simple table this will be 1. The second method is the number of rows. This will be the number of items in your items_array so: [items_array count]. The third method creates a cell based on the index. It will go from section 0 to the number of sections you specify and from row 0 to number of rows per section you specify. So now instead of looping you can just index out your array. [indexPath section] gives the section number and [indexPath row] gives the row number.
*I know I should probably dequeue cells before making new ones but my array is very small.
My question is that is it possible to get text data and read it in my ViewController from php when the cell is tapped?
I'm guessing didSelectRowAtIndexPath is the key to do this, but I'm not sure how to write.
I am able to get data from php into my TableViewController as below;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [json count];
}
- (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];
}
NSDictionary *info = [json objectAtIndex:indexPath.row];
cell.textLabel.text = [info objectForKey:#"Artist"];
cell.detailTextLabel.text = [info objectForKey:#"Song"];
return cell;
}
The code you have written kind of contradicts what you explained in the beginning. However, This is how it should be done:
First off you will need to get the data you want to display. You can get this from an external website (php, as you call it), plist, xml or whatever you want. You can do this when you have your tableview initiated (e.g. using ASIHTTPRequest) or before you initiate your tableview and just send it in using a custom init method.
Second, you need to read the contents you have recieved. Usually it great to get is in a NSArray format. This depends on your implementation of the data source you are fetching data from.
If you are new to objective-c and cocoa-touch, you should start off with some quick tutorials regarding UITableView. I have written one myself, but currently I guess its (very) outdated. You could still have a look at it though: http://paulpeelen.com/2009/08/14/developing-with-iphone-3-0-x-simple-uitableview/
Your code is I think wrong. Check if there any data in json by checking
NSLog(#"%# and %#",[info objectForKey:#"Artist"], [info objectForKey:#"Song"]);
and tell me if any result comes out. if not then there is some mistake in your php else your data should show there.
use this method of code.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//retrive your data here.
}