reorder and save UITableView - ios

I parse data from a server which contains passengers details.
the passengers details are saved into Passenger class.
The main viewController contains a UITableView which loads the passengers data and allows the user to rearrange the cells order.
My question is how can I save the tables new order and load it again each time the app starts, but with new passenger details parsed from the server.
I prefer not use core data.
Here is the code:
Passenger.h
#import <Foundation/Foundation.h>
#interface Passenger : NSObject
{
NSString *name;
NSString *code;
NSString *country;
NSString *date;
}
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *code;
#property (nonatomic, strong) NSString *country;
#property (nonatomic, strong) NSString *date;
mainViewController m
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
NSString *stringToMove = passengersArray[sourceIndexPath.row];
[passengersArray removeObjectAtIndex:sourceIndexPath.row];
[passengersArray insertObject:stringToMove atIndex:destinationIndexPath.row];
}
- (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];
}
Passenger *current = [passengersArray objectAtIndex:indexPath.row];
UILabel *nameLabel = (UILabel *)[cell viewWithTag:101];
nameLabel.text = current.name;
UILabel *codeLabel = (UILabel *)[cell viewWithTag:102];
codeLabel.text = current.code;
UILabel *countryLabel = (UILabel *)[cell viewWithTag:103];
countryLabel.text = current.country;
return cell;
}

You can load the passenger list from a plist in form of an Array. And when you update the information you iterate through that plist array, compare, update and add new passengers to the list. Once the user has rearranged the order you save it to the plist.
Fetch
NSPropertyListFormat format;
NSString *errorDesc;
NSString * plistPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0];
plistPath = [plistPath stringByAppendingPathComponent:#"Passengers.plist"];
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
NSArray *temp = (NSArray *)[NSPropertyListSerialization
propertyListFromData:plistXML
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&errorDesc];
Save
NSString *error;
NSString *plistPath;
NSString *rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0];
plistPath = [rootPath stringByAppendingPathComponent:#"Passengers.plist"];
NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:_passengersArray format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
if(plistData)
{
[plistData writeToFile:plistPath atomically:YES];
}
else
{
NSLog(#"Error writing passengers to file %#", error);
}

Related

myClass copyWithZone unrecognized selector sent to instance

When trying to get a object from an mutable array to et the values for that row in a tableview I get the error:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[KCNote copyWithZone:]:
unrecognized selector sent to instance 0x15589f60'
Below is my code, I had a look about this error and most places talk about issues copying data structures from the object to the new one however the objects contents is just intergers and strings as you can see below.
KCNote.h
#import <Foundation/Foundation.h>
#interface KCNote : NSObject
#property (nonatomic) NSInteger NoteID;
#property (nonatomic, strong) NSString *Note;
#property (nonatomic, strong) NSString *Author;
#property (nonatomic, strong) NSString *Date;
#end
Code in my view controller for the table.
NSMutableArray *Notes;
- (void)viewDidLoad
{
Notes = [[NSMutableArray alloc] init];
...
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"notecell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
// Configure the cell...
KCNote *note = [Notes objectAtIndex:indexPath.row];
UILabel *Author =(UILabel *) [cell viewWithTag:1];
UILabel *Date = (UILabel *) [cell viewWithTag:2];
UILabel *Note = (UILabel *) [cell viewWithTag:3];
Author.text = note.Author;
Date.text = note.Date;
Note.text = note.Note;
return cell;
}
Notes are added to the array using:
-(void)getNotes:(NSInteger)courseid{
[Notes removeAllObjects];
FMResultSet *s;
s = [db executeQuery:#"SELECT * FROM notes WHERE CourseID =?;", [NSString stringWithFormat:#"%d", courseid]];
//s = [db executeQuery:#"SELECT * FROM notes;"];
if ([db hadError]) {
NSLog(#"DB Error %d: %#", [db lastErrorCode], [db lastErrorMessage]);
}
while ([s next]) {
NSInteger NoteID = [s intForColumnIndex:0];
NSString *Note = [s stringForColumnIndex:2];
NSString *Author = [s stringForColumnIndex:3];
NSString *date = [s stringForColumnIndex:4];
KCNote *note = [KCNote new];
note.NoteID = NoteID;
note.Note = note;
note.Author = Author;
note.Date = date;
[Notes addObject:note];
}
[self.tbl_notes reloadData];
}

get crashed when deference subclassed NSObject

#interface PADiscover : NSObject
#property (nonatomic, assign) unsigned int dw3C;
#property (nonatomic, assign) BOOL isSet;
#property (nonatomic, assign) PAContactModel model;
#end
In another VC
#property (nonatomic, strong) NSMutableDictionary *shakeDict;
Then I add some objects to shakeDict
- (void)viewDidLoad {
NSNumber *num = [NSNumber numberWithUnsignedInt:message.sDeviceInfo.dw3CId];
PADiscover *discover = [[PADiscover alloc] init];
discover.dw3C = message.sDeviceInfo.dw3CId;
discover.model = message.sDeviceInfo.dwDeviceType;
discover.isSet = message.sDeviceInfo.fgPasswdFlag;
[_shakeDict setObject:discover forKey:[NSString stringWithFormat:#"%#", num]];
[_shakeTV reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
}
PADiscover *discover = [[_shakeDict allKeys] objectAtIndex:indexPath.row];
**cell.textLabel.text = [NSString stringWithFormat:#"ID %u, ISSet %d", discover.dw3C, discover.isSet];//crashed!**
cell.detailTextLabel.text = [NSString stringWithFormat:#"model %d", discover.model];
cell.detailTextLabel.font = [UIFont boldSystemFontOfSize:11];
return cell;
}
It seems cannot deference PADiscover successfully,but I'm not sure when place I get some wrong.
can anyone explain that for me?
Try this,
NSString *key = [[_shakeDict allKeys] objectAtIndex:indexPath.row];
PADiscover *discover = [_shakeDict objectForKey:key];
instead of
PADiscover *discover = (PADiscover *)[[_shakeDict allKeys] objectAtIndex:indexPath.row];
At least this line may be error:
#property (nonatomic, assign) PAContactModel model;
change to strong if a model class.
#property (nonatomic, strong) PAContactModel model;

UITableView got null items when scrolling

I have a small application, where i'm trying to load some data in UITableView from a sqlite database. Apparently everything works fine, but when I try to scroll i get Null data.
My code:
self.tblContacts.dataSource = self;
self.tblContacts.delegate = self;
self->mainManager = [[MainManager alloc] init: [NSString stringWithFormat:#"%#/contacts.db", resourcePath]];
self->contactList = [[ContactManager alloc] init];
self->contactList = [mainManager loadContacts];
-----------------------------------------------------
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self->contactList getContactsCount];
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellID = #"Cell";
CustomCell *Cell = [tableView dequeueReusableCellWithIdentifier:CellID];
if (!Cell)
Cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellID];
Cell.lblCompany.text = [[self->contactList getContact:indexPath.row] company];
Cell.lblContact.text = [NSString stringWithFormat:#"%# %#", [[self->contactList getContact:indexPath.row] name], [[self->contactList getContact:indexPath.row] surname]];
return Cell;
}
ScreenShot:
If anyone can enlighten me please. Thanks in advance.
Best regards.
I solved it. I'm noob in objective-c and i need to learn more about (strong, weak, retain, assign). I just replace weak by retain in my Contact Class:
#property (retain) NSString *name;
#property (retain) NSString *surname;
#property (retain) NSString *company;
#property (retain) NSString *cif;
#property (retain) NSString *email;
#property (retain) NSString *address;
#property (retain) NSString *city;
#property (retain) NSString *telephone;
#property (retain) NSString *provider;
strong = retain:
it says "keep this in the heap until I don't point to it anymore" in
other words " I'am the owner, you cannot dealloc this before aim fine
with that same as retain"
weak:
it says "keep this as long as someone else points to it strongly"
Source: Objective-C ARC: strong vs retain and weak vs assign
Now works perfectly!
Thanks anyway, regards.
Try this,
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellID = #"Cell";
CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:CellID];
if (cell == nil)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
for (id currentObject in topLevelObjects)
{
if ([currentObject isKindOfClass:[UITableViewCell class]])
{
cell = (CustomCell *) currentObject;
break;
}
}
}
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
Cell.lblCompany.text = [[self->contactList getContact:indexPath.row] company];
Cell.lblContact.text = [NSString stringWithFormat:#"%# %#", [[self->contactList getContact:indexPath.row] name], [[self->contactList getContact:indexPath.row] surname]];
return Cell;
}

Queue a NSMutableArray into a NString as a loop?

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.

UITableView doesn't display Address Book

I think I'm not getting the handle on address book and UITableView, or maybe I'm just making it simpler than it is.
here is my .h file:
#interface Contacts : UITableViewController <ABPeoplePickerNavigationControllerDelegate> {
NSMutableArray *menuArray;
NSString *firstName;
NSString *lastName;
UIButton *addcontact;
}
#property (nonatomic, retain) NSMutableArray *menuArray;
#property (nonatomic, strong) UIButton *addcontact;
#property (nonatomic, strong) NSString *firstName;
#property (nonatomic, strong) NSString *lastName;
-(void)showPeoplePickerController;
#end
And my .m file:
-(IBAction)addcontact:(id)sender {
ABPeoplePickerNavigationController *peoplePicker=[[ABPeoplePickerNavigationController alloc] init];
[peoplePicker setPeoplePickerDelegate:self];
[self presentModalViewController:peoplePicker animated:YES]; }
- (void)viewDidLoad
{
menuArray = [[NSMutableArray alloc] init];
[super viewDidLoad];
}
- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person {
firstName = (__bridge NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
[menuArray addObject:firstName];
lastName = (__bridge NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
[menuArray addObject:lastName];
[self dismissModalViewControllerAnimated:YES];
return NO;}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [menuArray count];
}
- (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];
}
NSString *cellValue = [menuArray objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
return cell;
}
I hope someone could help me with it, I'm fairley new to UITableViews and Addressbooks :)
For performance purposes (not to mention animation purposes), UITableView does not automatically update itself whenever the data source changes.
Try adding [myTableView reloadData]; after you add the first and last name to the arrays (or in viewWillAppear:

Resources