Show vcard data in a uitableview - ios

Good evening.
I'm developing a QRcode reader and I have one question.
When I read a vcard, I want to show the contact data in a UItableview like the contact's default uitablview in iPhone.
I want to show the contact data as above:
And I want to add the option to save to.
I want to know how can I do it. I have to manually program the view or is there some easier way to do it?
Thanks so much.

CFDataRef vCardData = (CFDataRef)[vCard dataUsingEncoding:NSUTF8StringEncoding];
ABAddressBookRef addressBook = [AddressBook Instance].addressBook;
ABRecordRef defaultSource = ABAddressBookCopyDefaultSource(addressBook);
NSArray *contacts = (NSArray *)ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource,vCardData);
CFRelease(defaultSource);
if (contacts.count) {
ABRecordRef person = [contacts objectAtIndex:0];
ABUnknownPersonViewController *unknownPersonVC = [[ABUnknownPersonViewController alloc] init];
unknownPersonVC.unknownPersonViewDelegate = self;
unknownPersonVC.allowsAddingToAddressBook = YES;
unknownPersonVC.displayedPerson = person;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:unknownPersonVC];
[unknownPersonVC release];
[self.navigationController pushViewController:unknownPersonVC animated:YES];
[navController release];
}
instead of creating custome Contact person View using table View use above code to first get all contact person record Ref and then display them one by one using
ABUnknownPersonViewController or ABPersonViewController..
may be help you..

You need to create the UITableView and implement all of its dataSource and delegate methods to draw the sections and cells. There's no free way to do this automatically, unfortunately.

You should probably check out a table view framework such as the free Sensible TableView. These frameworks automate a lot of these common tasks and will save you a lot of time.

Related

Variables and Transferring Data between View Controllers

I know that there are tutorials everywhere, but I can't figure this out for some reason. I have a tab bar controller. Each tab links to a navigation controller, which is segued to a view controller. So, 2 main view controllers (StatusVC and TransactionsVC).
In StatusVC, I have a text field. In TransVC, I have a table view. A person adds a cell to the table. Math is done behind the scenes. The cell values are added together (numbers). This information is sent back to StatVC for calculations and displaying of the data. I've already got the math part down. My question: how do I transfer the data between view controllers, and better yet, how do I store this data so that it doesn't get deleted on quit (NSUserDefaults probably)?
This can be broken down I suppose, the transferring of data, the saving of data, and the displaying of data when the tab is pressed and view is shown.
I'm hoping this is making sense. Anyway, here's the code I've got. You're looking at TranVC. User enters data into the table with an alert view. You are looking at part of the Alert View delegate methods. This is when the user enters data into a cell (presses done). Look for key areas with the ******* comments.
StatusViewController *statVC = [[StatusViewController alloc]init]; //*******init
// Set the amount left in the budget
NSString *amountToSpend = statVC.amountLeftInBudget.text;
double budgetLabel = [amountToSpend doubleValue];
NSString *lastItem = [transactions objectAtIndex:0];
double lastLabel = [lastItem doubleValue];
double totalValue = budgetLabel - lastLabel;
NSString *amountToSpendTotal = [NSString stringWithFormat: #"%.2f", totalValue];
statVC.amountLeftInBudget.text = amountToSpendTotal; //*******set text (but not save), either way, this doesn't work
// Set the amount spent
NSString *sum = [transactions valueForKeyPath:#"#sum.self"];
double sumLabel = [sum doubleValue];
NSString *finalSum = [NSString stringWithFormat:#"%.2f", sumLabel];
//Set the amountSpent label
statVC.amountSpent.text = finalSum; //*******set text (but not save), either way, this doesn't work
// The maxed out budget section
if ([statVC.amountLeftInBudget.text isEqualToString: #"0.00"]) //*******set color (but not save), either way, this doesn't work
{
statVC.amountLeftInBudget.textColor = statVC.currencyLabel.textColor = [UIColor redColor];
} else if ([statVC.amountLeftInBudget.text compare:#"0.00"] == NSOrderedAscending)
{
statVC.amountLeftInBudget.textColor = statVC.currencyLabel.textColor = [UIColor redColor];
} else if ([statVC.amountLeftInBudget.text compare:#"0.00"] == NSOrderedDescending)
{
statVC.amountLeftInBudget.textColor = statVC.currencyLabel.textColor = [UIColor colorWithRed:23.0/255.0 green:143.0/255.0 blue:9.0/255.0 alpha:1.0];
}
if ([statVC.amountLeftInBudget.text compare:#"0.00"] == NSOrderedAscending)
{
// Create our Installation query
UIAlertView *exceed;
exceed = [[UIAlertView alloc]
initWithTitle: #"Budget Exceeded"
message: #"You have exceeded your budget amount"
delegate: self
cancelButtonTitle: #"Okay"
otherButtonTitles: nil];
[exceed show];
}
Any help with this would be amazing.
This is indeed a common question.
There are various solutions. The one I recommend is to use a data container singleton. Do a google search on the singleton design pattern in Objective C. You'll even find examples of it here on SO.
Create a singleton with properties for the values that you want to share. Then teach your singleton to save it's data. You can use user defaults, you can use NSCoding, you can extract the data to a dictionary and save it to a plist file in your documents directory, or various other schemes as well.
Like Duncan suggested, a Singleton pattern might be the best route to go. If you place the shared data into a model class, you can create a class method that can be used to acquire a singleton object.
MyModel.m
#implementation MyObject
- (id) init
{
return nil; // We force the use of a singleton. Probably bad practice?
}
// Private initializer used by the singleton; not included in the header file.
- (id)initAsSingleton {
self = [super init];
if (self) {
// Initialize your singleton instance here.
}
return self;
}
+ (MyModel *)sharedMyModel {
static MyModel *myModel = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
myModel = [[MyModel alloc] initAsSingleton];
});
return myModel;
}
MyModel.h
#interface MyModel : NSObject
+ (MyModel *)sharedMyModel; // Singleton instance.
#end
This does not protect against you using [[MyModel alloc] init];. It returns a nil object which is probably poor programming on my end, but it does force you to use the singleton object instead. To use in each one of your view controllers, you just use the following line to grab the singleton instance.
MyModel *model = [MyModel sharedMyModel];
Store the data into it, and return to your other view controller and grab the singleton again. You'll have all of your data.
After thinking about it, you could also force the default initializer to just return your singleton instance like:
- (id)init {
return [MyModel sharedMyModel];
}

Object creation of views and share data between view in iOS

I am new to iOS.I am recently stuck with a problem.
I have a view A and View B. View A has a navigation controller. view A has a button to switch to B.When i am clicking this button every time B creates a new object. how can i track this object to share data between this two view.
Thanks
There are several ways to do this.
You could have a property of B, that A sets before you push. (NSDictionary, Array, String etc)
This not the best way however it would work.
UIViewController *viewB = [[UIViewController alloc]init];
[viewB setMyProperty:#"some data!"];
[self.navigationController pushViewController:viewB animated:YES];
You could also use NSNotificationCenter to pass the object to the next view.
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:
[NSNumber numberWithInt:index]
forKey:#"index"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"myNotification"
object:self
userInfo:dictionary];
The way I usually handle this is to setup and object that holds my data with an associated protocol initialized in my AppDelegate. Then any view that needs to read/write something just grabs a Pointer to that object and runs with it.
#class AppData;
#protocol AppDataProtocol
- (AppData*)theAppData;
#end
in the View you can grab the pointer with this.
-(AppData*)theAppData {
id<AppDataProtocol> theDelegate = (id<AppDataProtocol>)[UIApplication sharedApplication].delegate;
AppData* theData = (AppData*)theDelegate.theAppData;
return theData;
}
and this.
appData = [self theAppData];
You are then able to easily access any property of appData.
-(void)fnButtonA{
ViewB *vcB = [[ViewB alloc] initWithData:DataToB];
[[self navigationController] pushViewController:vcB animated:Yes];
}
In ViewB.m edit the init function to
-(UIViewController *)initWithData:(NSMutableDictionary*)data

IOS AddressBook update contact or merge records

In my iOS app, I created my own contact form that appends to note an unique identifier for my app. I want to update the contact from address book as sql "update" statement.
In iOS i only see ABAddressBookAddRecord and ABAddressBookRemoveRecord methods. How can i do UpdateContact?
In our app, we let the user decide, whether to add a new contact or merge the new data into an existing one. We did it like that: (assuming you use a navigationViewController)
ABUnknownPersonViewController *view = [[ABUnknownPersonViewController alloc] init];
view.unknownPersonViewDelegate = self;
view.displayedPerson = <YOUR-ABRecordRef-HERE>;
view.allowsAddingToAddressBook = YES;
view.allowsActions = YES;
[self.navigationController pushViewController:view animated:YES];
The user then sees the record in single view (just your "new" data) and has buttons to import or merge to existing contact.

io looking for insert and cancel pattern

I've been looking around for a good pattern to implement a insert then cancel pattern when working with a UINavigationBar and UITableView.
I have I have a "insert"button in my TeamsViewController navigation bar (screenshot)
Which when I run it runs this code:
-(void)insertTeam
{
if( !detailViewController ) {
detailViewController = [[TeamDetailViewController alloc] init];
}
if( !teams ) {
teams = [NSMutableArray array];
}
Team *team = [[Team alloc] init];
[teams addObject:team];
int lastIndex = [teams count];
[detailViewController setEditingTeam:[teams objectAtIndex:lastIndex - 1]];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:detailViewController];
[self presentModalViewController:navigationController animated:YES];
}
Which is great if the user fills out all the info, but if they hit cancel on the next view, there's an empty object in my arrary.
I'm sure there's a great pattern to achieve this but I've looked at all the TableView sample codes, two different ios books, and tried googling it, but haven't found a pattern for this.
My thought is something like the following:
When user cancels, set a canceled ivar in my Team object to YES
Back in my TeamsViewController, when the view appears check the last object in my teams array and see if it's property canceled is YES, if so remove that last object.
But this doesn't seem so slick and I was figuring there was some better way to achieve this. TIA.
I would be tempted to make the TeamsViewController a delegate of the TeamDetailViewController. The delegate would implement a method such as - (void)teamCreated:(Team *)team; and it would update the array. Since there seems to be no point to having a Team in the array that's incomplete, I would have the TeamDetailViewController create the Team and pass it back in the delegate call. On a cancel, there would be no need to do anything except pop the controller.

Odd memory leak with iOS address book

I have the below in one of my functions to copy the contacts on the phone:
ABAddressBookRef addressbook = ABAddressBookCreate();
if(self.contacts != nil)
[contacts release];
self.contacts = (NSArray *)ABAddressBookCopyArrayOfAllPeople(address book);
contacts is an NSArray declared in the class, retained, synthesized et al.
The array is then used in another view controller:
if (!self.contactsViewController) {
self.contactsViewController = [[[contactsViewController alloc] initWithNibName:#"ContactsViewController" bundle:nil] autorelease];
}
self.contactsViewController.contacts = self.contacts;
[self.navigationController pushViewController:self.contactsViewController animated:YES];
I know you are supposed to release the addressbook, but when I do, the contacts that are copied to the viewController only have their names left; all phone numbers and emails disappear when I call them up with ABPersonViewController. It, on the other hand, works fine when I don't release address book, but leaks memory all over the floor. What is going on and how do I fix it?
You are not supposed to release the address book returned by ABAddressBookCreate. Following the conventions, methods that create and return and object should make it autorelease.
However, the line
self.contacts = (NSArray *)ABAddressBookCopyArrayOfAllPeople(address book);
is certainly leaking. Why?, well because ABAddressBookCopyArrayOfAllPeople is creating a new object, that you are retaining again: self.contacts =. So you should either change it for
contacts = (NSArray *)ABAddressBookCopyArrayOfAllPeople(address book);
or use another method that doesn't create a new array of contacts.

Resources