How to save CustomCell data in an Array? - ios

i have a customcell in my UITableView. This custom cell has a label and text box. when the user fills in the data (4-5 fields) and clicks the Save button. I want to save the Data he inputs.
How can i do that??
I just have around 5-6 fields max. It would be great if you could give some examples on how i can get this done.

One way: Save your data in a dictionary.

Are you trying to pass the data back to the tableview? If so, you will have to save the info in a data structure and then pass it using a defined protocol.

Edit according to your comments:
In a case like this, Apple recommends to use the Delegate-Pattern. Basically, what you do is this:
#protocol FirstDataVCDelegate;
#interface FirstDataVC : UIViewController
#property (weak, nonatomic) id<FirstDataVCDelegate> delegate;
//...
#end
#protocol FirstDataVCDelegate <NSObject>
- (void)firstDataVC:(FirstDataVC *)dataVC didCollectData:(NSDictionary *)data;
#end
#interface RootVC: UIViewController<FirstDataVCDelegate>
//...
#end
#implementation RootVC
- (void)firstDataVC:(FirstDataVC *)dataVC didCollectData:(NSDictionary *)data
{
NSString *name = [data valueForKey:#"name"];
[self.completeData setValue:name forKey:#"name"];
}
#end
In this case RootVC would be the VC who wants to send the whole data. FirstDataVC is one of the VCs where the user inputs data.
Every VC that get userinput has to provide a protocol, that the RootVC implements.
Here is some more about delegation.

You can make a data Structure of the data that he will fill, after save button is clicked. set these values to the data structure
Also you can use NSMutableDictionary key-value storage
Example: let say we have 4 UITextFeilds textFeild1, textFeild2, textFeild3, textFeild14
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
[dic addObject: textFeild1.text forValue: #"val1"];
[dic addObject: textFeild2.text forValue: #"val2"];
[dic addObject: textFeild3.text forValue: #"val3"];
[dic addObject: textFeild4.text forValue: #"val4"];
//Now you have the values and can retrieve them by:
NSString *value1 = [dic valueForKey:#"val1"];

Try with below code:
- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.tabTeamDetails dequeueReusableCellWithIdentifier:#"customcellIdentifier"];
get UItextfeild and assign tag as below
textbox.tag = indexpath.row; //used to refer particular textfiled
}
In save button action:
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
//for(i=0;i<noofrowsintableview;i++){
NSString *text = (NSString *)[self.view viewWithTag:i];
[dic addObject:[NSString stringWithFormat:text] forValue: i];
}

Related

Getting NSmutableDictionary key from two mutable arrays

I have three mutable arrays
#interface PickeriviewAndTableViewController ()
//Create mutableArray for tableView
#property(strong,nonatomic)NSMutableArray *msgYear;
#property(strong,nonatomic)NSMutableArray *msgSeason;
#property(strong,nonatomic)NSMutableArray *msgCourse;
I want to add element to array msgCourse[ ] using the key generating from the first two arrays msgYear[ ] and msgSeason[ ].
Then I want to populate the msgCourse[] array using a button
- (IBAction)addCourse:(UIButton *)sender {
//To get value from pickerView, prepare for key and contents
NSInteger numRow=[picker selectedRowInComponent:kNumComponent];//0=1st,1=2nd,etc
NSInteger SeaRow=[picker selectedRowInComponent:kSeaComponent];//0=fall,1=spring,2=summer
NSInteger CourseRow=[picker selectedRowInComponent:kCourseComponent];
NSString *num=Number[numRow];
NSString *season=Season[SeaRow];
NSString *course=Course[CourseRow];
NSString *CourseToAdd=[[NSString alloc ]initWithFormat:#"%# ",course];
NSString *SeasonToAdd=[[NSString alloc ]initWithFormat:#"%# ",season];
NSString *YearToAdd=[[NSString alloc ]initWithFormat:#"%# ",num];
// Try to generate key from YearToAdd and SeasonToAdd and fill in content
NSMutableArray *keys = [[NSMutableArray alloc] init];
NSMutableDictionary *contents = [[NSMutableDictionary alloc] init];
NSString *keyFromYearAndSeason = #"Don't_know_what_to_do_here";
[contents setObject:[NSArray arrayWithObjects:#"Don't_know_how", nil] forKey:keyFromYearAndSeason];
[keys addObject:keyFromYearAndSeason];
[self setSectionKeys:keys];
[self setSectionContents:contents];
}
My question is: How to complete my code by replacing these "Don't know how" lines of code here please?
Update: To be more clear, key is generating from msgYear[ ] and msgSeason[ ] e.g. '2001 fall', dictionary is filled with course e.g. 'chemistry','math'.
The link to your other question helped provide context for what you are trying to achieve.
You don't need to create a dictionary or an array inside the addButtton method - you should have your dictionary as a property that is already initialised.
Then, in add button you retrieve the array associated with the key - if the value is nil then you create a new array and put the course in. If the value isn't nil simply add the course to the array.
#property (strong,nonatomic) NSMutableDictionary *tableEntries; // alloc/init this in viewDidLoad
- (IBAction)addCourse:(UIButton *)sender {
//To get value from pickerView, prepare for key and contents
NSInteger numRow=[picker selectedRowInComponent:kNumComponent];//0=1st,1=2nd,etc
NSInteger SeaRow=[picker selectedRowInComponent:kSeaComponent];//0=fall,1=spring,2=summer
NSInteger CourseRow=[picker selectedRowInComponent:kCourseComponent];
NSString *num=Number[numRow];
NSString *season=Season[SeaRow];
NSString *course=Course[CourseRow];
NSString *key=[NSString stringWithFormat:#"%# %#",num,season];
NSMutableArray *courses=self.tableEntries[key];
if (courses == nil) {
courses=[NSMutableArray new];
self.tableEntries[key]=courses;
}
[courses addObject:course];
}
NSDictionarys are unordered, so you need to give some thought to how you want to order the data in your table. You could use an array to hold the keys as in your original code and then sort this array.

How to Sort object by alphabet order for UITableViewCell?

I want to sort objects that i created & stored in NSMutableArray in AppDelegate.m.
Stations is NSObject Class
I want to show station names in another UIViewController in alphabet order(in UITableViewCell) & when i click on them i want to pass the object that contains station name,latitude,longitude to next UIViewController
Currently i have extracted station name from stationList(Global NSMutableArray) to another NSMutableArray on UIViewControllers Cell & sorted it via
[sortedArray sortUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
but when didSelectRowAtIndexPath is being called i have to get this name from cell & search it in the stationList array to pass lat,long which is not good i think.
stationList Array Log(It has 100 objects):-
<__NSArrayM 0x79a2f110>(
<Stations: 0x78743540>,
<Stations: 0x78743630>,
<Stations: 0x78743670>,
<Stations: 0x78743750>,
<Stations: 0x78743830>,
<Stations: 0x78743910>,
<Stations: 0x78743a10>,
<Stations: 0x78743af0>
}
-(void)loadStations
{
stationList = [[NSMutableArray alloc]init];
NSString *path = [[NSBundle mainBundle] pathForResource:#"stations" ofType:#"txt"];
NSString *content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
// NSLog(#"%#",content);
NSArray *tempArr = [content componentsSeparatedByString:#"\n"];
for (int i =0; i<[tempArr count]; i++)
{
NSString *rawData = [tempArr objectAtIndex:i];
if (rawData !=nil)
{
Stations *newStation = [[Stations alloc]init];
NSArray *data = [rawData componentsSeparatedByString:#"\t"];
newStation.sId = i+1;
newStation.name = [NSString stringWithFormat:#"%#",[data objectAtIndex:0]];
newStation.latitude = [[data objectAtIndex:1] doubleValue];
newStation.longitude = [[data objectAtIndex:2] doubleValue];
[stationList addObject:newStation];
}
}
}
Suggest me good practice/way for this, or maybe use Dictionary?
I see two solutions here:
1) you can retrieve object from your stationList based on indexPath.row
- (void) tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
Stations* station = stationsList[indexPath.row];
...
}
2) you can create custom UITableViewCell and store referenced object there:
#interface StationCell : UITableVIewCell
#property(weak) Stations* station;
#end
...
- (UITableViewCell*) tableView:(UITableVIew*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
StationCell* cell;
// dequeue StationCell
...
cell.station = stationList[indexPath.row];
}
...
- (void) tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
StationCell* cell = [tableView cellAtIndexPath:indexPath];
Stations* station = cell.station;
...
}
I would choose between solutions based on complexity of data displayed in cell - using custom UITableViewCell gives oportunity to move configuration of cell from view controller to cell implementation.
edit
As far as sorting stationsList, you can use e.g.:
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES];
stationsList = [stationsList sortedArrayUsingDescriptors:#[sort]];
I would advise against sorting an array of station names separate from your array stationList. Instead I would suggest sorting your stationList (or a copy of it if you only want to change the oder in the table view and need to maintain some other ordering elsewhere)
There are methods like sortUsingComparator: that takes comparator block as a parameter. You write a block that compares 2 elements in your array, and the method uses that block to figure out the ordering of your objects and sort the array. In your case it would simply be a matter of writing a block that compares the name properties of 2 station objects.

NSMutableArray not printing correct data - iOS/Objective C

I'm struggling to get my array to print the correct data.
I've got it linked to a button, so it gets the textfield data and adds it to a Person class which has a subclass called PhoneBookEntry which contains firstName, and then adds it to an NSMutableArray called entries. here's the button code:
PhonebookEntry *person = [[PhonebookEntry alloc] init];
self.firstName.text = person.firstName;
[self.entries addObject:person];
NSLog(#"%#", self.entries);
Here's the start where I initialise everything:
#interface ViewController ()
#property (nonatomic, strong) PhonebookEntry *person;
#property (nonatomic, strong) NSMutableArray *entries;
#end
in my viewDidLoad, this is the code to create the NSArray.
self.entries = [NSMutableArray arrayWithCapacity:1];
I've tested and it works fine when adding normally and prints etc, just not with the array.
Thanks
The output
test,
test2,
"<PhonebookEntry: 0x8c69770>"
It is printing correctly.
Actually you want something more from your code or Objective-C.
For this you need to override description in PhonebookEntry class to break to the level where NSLog can print. NSLog can't print person object values.
-(NSString *)description{
return [NSString stringWithFormat:#"%# , %#", self.firstName, self.lastName];
}
This self.firstName.text = person.firstName; should be the other way around, so change it to this:
person.firstName = self.firstName.text;

Populate UITableView with JSON array

I'm working in Storyboard but I presume now it's time to face the code...
I have a PHP file on my server which outputs the contents of my MySQL database table as an array in JSON format:
{
"id":"2",
"name":"The King's Arms",
"city":"London",
"day":"Tuesday",
}
I'll need all the data eventually, but for now I just want to output the city fields as a UITableView. How would I go about doing this?
I believe it was in the year 2012/2013 where Apple covered a fantastic video on code practices, one sub topic highlighted was a good smart way of handling JSON objects and creating data objects for them. I'm sorry I forgot the name of the actual video, if someone remembers it please do edit the answer for me.
What apple covered was to have a data object that stores each json object. We will then create an array to store these objects and access the required fields appropriately when populating our tableView. So in your case you would do something like this.
in your project navigator add a file of NSObject type and add the following code:
#import <Foundation/Foundation.h>
#interface PlaceDataObject : NSObject
-(id)initWithJSONData:(NSDictionary*)data;
#property (assign) NSInteger placeId;
#property (strong) NSString *placeName;
#property (strong) NSString *placeCity;
#property (strong) NSString *placeDay;
#end
and in your .m file you would add this code
#import "PlaceDataObject.h"
#implementation PlaceDataObject
#synthesize placeId;
#synthesize placeName;
#synthesize placeCity;
#synthesize placeDay;
-(id)initWithJSONData:(NSDictionary*)data{
self = [super init];
if(self){
//NSLog(#"initWithJSONData method called");
self.placeId = [[data objectForKey:#"id"] integerValue];
self.placeName = [data objectForKey:#"name"];
self.placeCity = [data objectForKey:#"city"];
self.placeDay = [data objectForKey:#"day"];
}
return self;
}
#end
What you have now is a data object class which you can use everywhere in your code where ever required and grab the appropriate details for whichever table youre showing, whether it be a city fields table or a city and name table etc. By doing this you will also avoid having json decoding code everywhere in your project. What happens when the name of your 'keys' changes? rather than scouring through your code correcting all your keys, you simply go to the PlaceDataObject class and change the appriopriate key and your application will continue working.
Apple explains this well:
"Model objects represent special knowledge and expertise. They hold an application’s data and define the logic that manipulates that data. A well-designed MVC application has all its important data encapsulated in model objects.... they represent knowledge and expertise related to a specific problem domain, they tend to be reusable."
Populating your array with custom objects for every json entry that comes in from the server
Now onto populating an array of this custom data object you've made. Now following the MVC approach, it's probably best that you have all your methods that process data in a different class, your Model class. That's what Apple recommends to put these kind of methods in a seperate model class where all the processing happens.
But for now we are just going to add the below code to the View Controller just for demonstration purposes.
Create a method in your view controller's m file that will process your JSON array.
//make sure you have a global NSMutableArray *placesArray in your view controllers.h file.
-(void)setupPlacesFromJSONArray:(NSData*)dataFromServerArray{
NSError *error;
NSMutableArray *placesArray = [[NSMutableArray alloc] init];
NSArray *arrayFromServer = [NSJSONSerialization JSONObjectWithData:dataFromServerArray options:0 error:error];
if(error){
NSLog(#"error parsing the json data from server with error description - %#", [error localizedDescription]);
}
else {
placesArray = [[NSMutableArray alloc] init];
for(NSDictionary *eachPlace in arrayFromServer)
{
PlaceDataObject *place = [PlaceDataObject alloc] initWithJSONData:eachPlace];
[placesArray addObject:place];
}
//Now you have your placesArray filled up with all your data objects
}
}
And you would call the above method like so:
//This is not what your retrievedConnection method name looks like ;)
// but you call the setupPlacesFromJSONArray method inside your connection success method
-(void)connectionWasASuccess:(NSData *)data{
[self setupPlacesFromJSONArray:data];
}
Populating your tableView with your custom Data objects
As for populating your data in your TableView you do so like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
//We check against table to make sure we are displaying the right number of cells
// for the appropriate table. This is so that things will work even if one day you
//decide that you want to have two tables instead of one.
if(tableView == myCitysTable){
return([placesArray count]);
}
return 0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if(cell)
{
//set your configuration of your cell
}
//The beauty of this is that you have all your data in one object and grab WHATEVER you like
//This way in the future you can add another field without doing much.
if([placesArray count] == 0){
cell.textLabel.text = #"no places to show";
}
else{
PlacesDataObject *currentPlace = [placesArray objectAtIndex:indexPath.row];
cell.textLabel.text = [currentPlace placeCity];
// in the future you can grab whatever data you need like this
//[currentPlace placeName], or [currentPlace placeDay];
}
return(cell);
}
Short disclaimer: the code above has not been tested, but please let me know if it all works well or if I've left out any characters.
If the raw data from you server arrives in a NSData object, you can use NSJSONSerialization class to parse it for you.
That is:
NSError *error;
NSMutableArray *cityArray = [[NSMutableArray alloc] init];
NSArray *arrayFromServer = [NSJSONSerialization JSONObjectWithData:dataFromServer options:0 error:error];
if(arrayFromServer)
{
NSLog(#"error parsing data - %#", [error localizedDescription]);
} else {
for(NSDictionary *eachEntry in arrayFromServer)
{
NSString *city = [eachEntry objectForKey:#"city"];
[cityArray addObject: city];
}
}
Once you're done populating your array of cities, this is what you can return in the table view's data source methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1; // your table only has one section, right?
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(section == 0)
{
return([cityArray count]);
}
NSLog(#"if we're at this place in the code, your numberOfSectionsInTableView is returning something other than 1");
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// are you using standard (default) cells or custom cells in your storyboard?
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if(cell)
{
cell.text = [cityArray objectAtIndex:indexPath.row];
}
return(cell);
}
what is myCitysTable, Paven? is that suppose to be the name of the TableView? i'm struggling to figure out how to name it, if so...

IOS search tag name completion bubble

I'm trying to create a search bar with a name auto complete that looks something like this in the image.
Does anyone have an idea how I may be able to achieve this?
Have a look at the TTMessageController and the TTMessageRecipientField from the open source library Three20. It's just what you want:
First you need an array with the contact's names:
//Add Address Book framework
#import <AddressBook/AddressBook.h>
--------------------
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *allPeople = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
NSMutableArray *firstNames = [NSMutableArray alloc] init];
for(NSUInteger personIndex = 0; personIndex <= [allPeople count]; personIndex++){
ABRecordRef person = (__bridge ABRecordRef)[allPeople objectAtIndex: incrementer];
firstNameString = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
[firstNames addObject: firstNameString];
}
So the firstNames array now contains an array of all the people;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"MyIdentifier"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithFrame:CGRectMake(your, values, go, here) reuseIdentifier:#"MyIdentifier"];
}
cell.text = [firstNames objectAtIndex: indexPath.row];
}
So far, you have a tableview with all the first names. Make sure you implement the other required methods in the protocols UITableViewDataSource and UITableViewDelegate. Also make sure that you declare the firstNames array a property in your header file to make sure it is accessible throughout the .m file, because if you do not do that, then you cannot access it in the cellForRowAtIndexPath: method.
To implement autocompletion, follow Ray Wenderlich's tutorial here on custom autocompletion values. Then use the array of peoples' first names as the custom values.

Resources