Get only certain Strings from plist iOS - ios

I have a plist and I want ot grab only the items which 'Name' string begins with 'A'. I want then display these in my UITableView, along with the 'NameOrigin' included in the item. I have included a screen shot of my plist. Thanks
My code so far, I am able to display all of the plist items, but I would like to filter the items displayed to ones with string 'Name' being with the letter 'A'?
-(NSArray *)content
{
//if (!_content) {
_content = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"MyPLIST" ofType:#"plist"]];
// }
return _content;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [TableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [[self.content objectAtIndex:indexPath.row] objectForKey:#"Name"];
cell.detailTextLabel.text = [[self.content objectAtIndex:indexPath.row] valueForKey:#"NameOrigin"];
return cell;
}

If you want to filter for only elements where Name begins with "A", try this:
NSArray *filteredArray = [self.content filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"Name beginswith %#", #"A"]];
While we're at it: you should consider refactoring your code a bit. Re-loading the data from file every time you call [self content] is a bad idea, performance wise. Instead try this:
// Create a property called content in your class extension on the top of the .m file of your table view controller
#interface YourTableViewController ()
#property (nonatomic, strong) NSArray *content;
#end
Next, add this code in your viewDidLoad callback:
_content = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"MyPLIST" ofType:#"plist"]];
and delete the custom content method.

Related

objective c - table view not able to show the data in the screen

I have an array of data. And wr my data are not displaying in the screen. Not sure, what i am missing.
#property NSMutableArray *NotifTotal;
#interface HomeVC ()<UITableViewDelegate, UITableViewDataSource>
#end
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.NotifTotal count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"FilterTableViewCell";
FilterTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDictionary *dict;
dict = [self.NotifTotal objectAtIndex:indexPath.row];
NSLog(#"%#", dict); // data is coming.
NSString* salt = [dict objectForKey:#"salt"];
NSString* name = [dict objectForKey:#"Name"];
NSLog(#"%#%#", name,swerk); // in console i can print the data
cell.sLabel.text = [NSString stringWithFormat: #"%#", salt];
cell.nLabel.text = [NSString stringWithFormat: #"%#", name];
return cell;
}
Why my data is not showing in my screen.I added the delegate, data source also in my screen.Any solution ?
You said "I added the delegate, data source also in my screen" but it is not very clear to me by that you meant conforming your HomeVC to UITableViewDelegate and UITableViewDataSource as your posted code or you actually set the delegate of your UITableView to HomeVC. So here are something you should check:
Set datasource of your UITableView to HomeVC using Interface Builder or following code:
self.tableView.dataSource = self; // I am assuming self == HomeVC instance
Make sure [self.NotifTotal count] > 0.
Make sure it is not about UITableView's configuration issue by adding a break point to cellForRowAtIndexPath and confirm it called.
If it isn't: go back to 2 points above.
If it is: this is UI issue, let's check if your cells's height is near 0 or they have a transparent color and so on. You can use Xcode's View Debugging tool to debug the issue.
Since you haven't mentioned having registered the cell identifier yet, I assume that's the problem. One way to do this is in your storyboard or xib. Select the prototype cell in your tableview, and set the "identifier" field (in the Attributes inspector pane of Interface Builder). Set it to "FilterTableViewCell".
This looks like a xib problem. I added a bit of code in the middle.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"FilterTableViewCell";
FilterTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//Add this part
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"FilterTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
//end
NSDictionary *dict;
dict = [self.NotifTotal objectAtIndex:indexPath.row];
NSLog(#"%#", dict); // data is coming.
NSString* salt = [dict objectForKey:#"salt"];
NSString* name = [dict objectForKey:#"Name"];
NSLog(#"%#%#", name,swerk); // in console i can print the data
cell.sLabel.text = [NSString stringWithFormat: #"%#", salt];
cell.nLabel.text = [NSString stringWithFormat: #"%#", name];
return cell;
}

NSDictionary allkeys to UITableViewCell

I am trying to get my NSdictionary values into a UITableViewCell. Here is my dictionary format:
{
date = "3/4/14, 3:33:01 PM Pacific Standard Time";
weight = 244;
}
Here is the code I'm using to populate my uitableview (which is not working).
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"WeightCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
NSArray* allKeys = [weights allKeys];
NSDictionary *obj = [allKeys objectAtIndex: indexPath.row];
cell.textLabel.text = [obj objectForKey: #"date"];
cell.detailTextLabel.text = [obj objectForKey:#"weight"];
return cell;
}
You should try initialising the array for the tableView outside of the tableView itself... something along the lines of
- (void)viewDidLoad
{
[super viewDidLoad];
_allKeys = [[NSMutableArray alloc] initWithArray:[weights allKeys]];
}
Once you have initialised that data you can access it throughout the process. Also to find out how many rows your tableview needs.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_allKeys count];
}
Then when you access the array into a dictionary it has retained the row count and can access it properly.
NSDictionary *obj = [_allKeys objectAtIndex: indexPath.row];
cell.textLabel.text = [obj objectForKey: #"date"];
cell.detailTextLabel.text = [obj objectForKey:#"weight"];
From what I can see the dictionary cant access the array at your indexPath.row because you haven't initialised the array anywhere before you use it in your tableView.
Hope that helps, T
Some of the other posters have good suggestions. However, this line:
NSDictionary *obj = [allKeys objectAtIndex: indexPath.row];
Is wrong. allKeys is an array of your dictionary keys, which are presumably strings.
So, you want code like this instead:
NSString *thisKey = allKeys[indexPath.row];
NSDictionary *obj = weights[thisKey];
Note that I am using the new Objective C literal syntax. The expression weights[thisKey] is equivalent to [weights objectForKey: thisKey]
I don't see the definition of the weights object. If you want to keep adding NSDictionary's to an array, you need to use an NSMutableArray, and you'll probably want to do that by setting it as a #property on your class. Let's say you added it like this:
#property (strong, nonatomic) NSMutableArray *weights;
Then in your tableView:cellForRowAtIndexPath: method you'll want to get the NSDictionary corresponding to that line by using self.weights[indexPath.row]. Also don't forget to instantiate weights before using it, otherwise it will return nil and no objects are going to be added to it.
P.S.: the user provided some context here and what he probably needs is Core Data.

How to make a tableview divided into sections by letter like the contacts app

I'm trying to replicate the contacts table view in my app. So I have a list of contacts displayed in a table view however I would like the table view to be sectioned into all the letters of the alphabet and the names of the contacts to be placed in the section related to the lister letter of their first name. Like this
How do I get that view? So far this is all I have done.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [displayNames count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"ContactsCell";
/*ContactCell *cell = (ContactCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ContactCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}*/
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
// cell.name.text = [displayNames
// objectAtIndex:indexPath.row];
UILabel *namer = (UILabel *)[cell viewWithTag:101];
namer.text=[displayNames
objectAtIndex:indexPath.row];
/*
Get the picture urls from the picture array and then
I loop through the array and initialize all the urls with
a NSUrl and place the loaded urls in anouther nsmutable array
*/
urls = [[NSMutableArray alloc] init];
for (id object in pictures) {
//NSDictionary *names = res[#"image"];
NSString *name = object;
NSURL *url=[[NSURL alloc] initWithString:name];
[urls addObject:url];
}
// cell.profile.image= [UIImage imageWithData:[NSData dataWithContentsOfURL: [urls objectAtIndex:indexPath.row]]];
UIImageView *profiler = (UIImageView *)[cell viewWithTag:100];
profiler.image= [UIImage imageWithData:[NSData dataWithContentsOfURL: [urls objectAtIndex:indexPath.row]]];
return cell;
}
Here is an easy solution using the 3rd party TLIndexPathTools data model class TLIndexPathDataModel. It is specifically designed for working with index paths and sections, so you can accomplish what you need with minimal complexity. And here is a full, working demo.
First define a class to represent a contact. This gives you a place to define firstName, lastName, displayName and sectionName:
#interface Contact : NSObject
#property (strong, nonatomic, readonly) NSString *firstName;
#property (strong, nonatomic, readonly) NSString *lastName;
#property (strong, nonatomic, readonly) NSString *displayName;
#property (strong, nonatomic, readonly) NSString *sectionName;
- (instancetype)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName;
#end
The sectionName property just returns the first character of the firstName. Then if your table view subclasses TLTableViewController, the implementation would look something like this:
#implementation ContactsTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *contacts = [NSMutableArray array];
//get actual list of contacts here...
[contacts addObject:[[Contact alloc] initWithFirstName:#"John" lastName:#"Doe"]];
[contacts addObject:[[Contact alloc] initWithFirstName:#"Sally" lastName:#"Smith"]];
[contacts addObject:[[Contact alloc] initWithFirstName:#"Bob" lastName:#"Marley"]];
[contacts addObject:[[Contact alloc] initWithFirstName:#"Tim" lastName:#"Cook"]];
[contacts addObject:[[Contact alloc] initWithFirstName:#"Jony" lastName:#"Ives"]];
[contacts addObject:[[Contact alloc] initWithFirstName:#"Henry" lastName:#"Ford"]];
//sort by section name
[contacts sortUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"sectionName" ascending:YES]]];
//set the data model
self.indexPathController.dataModel = [[TLIndexPathDataModel alloc] initWithItems:contacts sectionNameKeyPath:#"sectionName" identifierKeyPath:nil];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
//get contact for index path from data model and configure cell
Contact *contact = [self.indexPathController.dataModel itemAtIndexPath:indexPath];
cell.textLabel.text = contact.displayName;
return cell;
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return self.indexPathController.dataModel.sectionNames;
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
return index;
}
#end
The key thing is that TLIndexPathDataModel automatically organizes your data into sections using the sectionNameKeyPath set to #"sectionName". Then in your view controller logic, you can easily access the contact for a given index path by calling:
Contact *contact = [self.indexPathController.dataModel itemAtIndexPath:indexPath];
update
You'd actually want to do a second-level sort on display name:
[contacts sortUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"sectionName" ascending:YES], [NSSortDescriptor sortDescriptorWithKey:#"displayName" ascending:YES]]];
update #2
There is a new block-based initializer for TLIndexPathDataModel that makes this a lot easier if you don't want to define a custom data object just to add a sectionNameKeyPath property. For example, one can use the new initializer to organize a list of strings as illustrated in the "Blocks" sample project:
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *items = [#[
#"Fredricksburg",
#"Jelly Bean",
...
#"Metadata",
#"Fundamental",
#"Cellar Door"] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
//generate section names by taking the first letter of each item
self.indexPathController.dataModel = [[TLIndexPathDataModel alloc] initWithItems:items
sectionNameBlock:^NSString *(id item) {
return [((NSString *)item) substringToIndex:1];
} identifierBlock:nil];
}

Displaying data in UITableView

I have a split view controller for iPad with a drill-down table on the left. I am able to populate my first table view and when I click on a cell this takes me to my second table view. I am able to see a count of records returned and the actual data I expect to see in the table view output in the command widow with the NSLog command. What I don't see is the actual data in the table view. Instead I see UITableViewCellAccessoryDisclosureIndicator for each row that is returned but no actual data.
I am using xib files and I have created this file for my products I want displayed in the drill-down. In my Product.xib file I have the File's Owner Outlets as productsTableView linked to products (my UITableView control) and view linked to View. Referencing Outlets for the View have dataSource linked to products, delegate linked to products and finally view linked to File's Owner.
Am I missing something here? Like I said I get all the data back it just isn't binding to the grid.
#interface ProductViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
NSMutableArray *listOfItems;
NSMutableArray *dataArray;
IBOutlet UITableView *productsTableView;
}
#property(nonatomic, strong) IBOutlet UITableView *productsTableView;
#end
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Set up the cell...
NSString *cellValue = [listOfItems objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = cellValue;
return cell;
}
In the interest of being thorough I will post this as well to show where I am getting my data back and how I am doing this...
-(void) connectionDidFinishLoading:(NSURLConnection *)connection {
NSError *error = nil;
// Get the JSON data from the website
id result = [NSJSONSerialization JSONObjectWithData:receivedData options:kNilOptions error:&error];
if ([result isKindOfClass:[NSArray class]]) {
for (NSArray *item in result) {
NSArray *products = [item valueForKey:#"ProductDescription"];
[dataArray addObject:products];
[listOfItems addObject:products];
}
}
else {
NSDictionary *jsonDictionary = (NSDictionary *)result;
for(NSDictionary *item in jsonDictionary)
NSLog(#"Item: %#", item);
}
[self performSelector:(#selector(refreshDisplay:)) withObject:(self.productsTableView) afterDelay:1.0];
NSLog(#"Finished");
}
My NSLog is here:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"Dictionary: %#", dataArray);
return [dataArray count];
}
Simple mixup...
NSString *cellValue = [dataArray objectAtIndex:indexPath.row];
instead of
NSString *cellValue = [listOfItems objectAtIndex:indexPath.row];
You are adding products (which is an NSArray) to listOfItems. Later in cellForRowAtIndexPath, you are saying cellValue (NSString) = [listOfItems objectAtIndex:indexPath.row] (which is potentially an `NSArray'). How would that work?

Accessing dictionaries in PList for UITableView

I'd like to create a simple reference app that lists a group of people, their job title, and their portrait. What I have so far is the list of people and their job title. It works alright, but I think I should have done it differently.
From reading other posts, I suppose I should be using dictionaries. This is how my PList currently looks:
And this is how the important bits of my code look:
#implementation RootViewController
#synthesize staffArray, subtitleArray;
- (void)viewDidLoad
{
[super viewDidLoad];
NSString* path = [[NSBundle mainBundle] pathForResource:#"StaffData" ofType:#"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSMutableArray *tmpNameArray = [dict objectForKey:#"Root"];
self.staffArray = [[NSMutableArray alloc] initWithArray:tmpNameArray copyItems:YES];
NSMutableArray* tmpSubtitleArray = [dict objectForKey:#"Subs"];
self.subtitleArray = [[NSMutableArray alloc] initWithArray:tmpSubtitleArray copyItems:YES];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [staffArray count];
}
// Customize the appearance of table view cells.
- (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] autorelease];
}
// Configure the cell.
cell.textLabel.text = [staffArray objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [subtitleArray objectAtIndex:indexPath.row];
return cell;
}
Using two arrays kind of defeats the purpose of OOP, I think, because in this case the people aren't connected to their job titles; they just happen to be in the same order. I'd like to create for example:
Array called Jonas, first value = job title, second value = pathToImage.png.
Another array called Andreas, etc etc etc.
What do I do?
I think that as a start, your design lacks an "Employee" object, that has data members like "Name", "JobTitle", etc... After you have this set up, just create an array of people and take whatever you need from there, by index.

Resources