I want to edit record from address book in my iphone app. But I can not edit any record. Here is my code
// In my First View Controller
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController *detailViewController=[[DetailViewController alloc] initWithRecordObject:record];
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
//------------------------------------
#import <UIKit/UIKit.h>
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
#import "User.h"
#interface DetailViewController : UIViewController <UITableViewDelegate,UITableViewDataSource,UIActionSheetDelegate,ABPersonViewControllerDelegate> {
ABRecordRef record;
// Some other ivars
}
- (id)initWithRecordObject:(ABRecordRef)myrecord;
//------------------------------------
#implementation DetailViewController
- (id)initWithRecordObject:(ABRecordRef)myrecord
{
self = [super initWithNibName:#"DetailViewController" bundle:nil];
if (self) {
record = myrecord;
}
return self;
}
#pragma mark - Edit Record Method
-(void)btnEditContactTapped:(id)sender {
// Fetch the address book
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordID recID = ABRecordGetRecordID(record);
ABRecordRef record1 = ABAddressBookGetPersonWithRecordID(addressBook,recID);
ABPersonViewController *personViewController = [[ABPersonViewController alloc]init];
// set delegate
personViewController.personViewDelegate = self;
// Allow editing info
personViewController.allowsEditing = YES;
// Display contact info of selected person
personViewController.displayedPerson = record1;
personViewController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:self action:#selector(returnFromPersonView)] ;
APP_DELGATE.isContactEdited = YES;
[self.navigationController pushViewController:personViewController animated:YES];
[personViewController release];
}
-(void)returnFromPersonView {
NSLog(#"In %s",__PRETTY_FUNCTION__);
[self.navigationController popViewControllerAnimated:YES];
}
#pragma mark - ABPersonViewControllerDelegate Method
- (BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue {
//[self dismissModalViewControllerAnimated:YES];
return NO;
}
When I push personViewController , I can't see anything regarding record. Here is a screenshot
Any kind of help is highly appreciated.Thanks
Take a look at Apple's Adress Book Programming Guide. A page that would be useful to you is the Direct Interaction: Programmatically Accessing the Database page. I advise you to just look around at those pages, they are quite self explanatory.
Changing return to YES may help in last method
- (BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue {
//[self dismissModalViewControllerAnimated:YES];
return NO; //try changing it to YES
}
You are not passing the "Correct Contact ID" as ABRecordRef ;)
Related
I seek to create a "Utility Email sender class" that I can use in several iPhone projects.
I created MailSender header and implementation for that purpose.
MailSender.h:
#interface MailSender : NSObject<MFMailComposeViewControllerDelegate>
- (id) initWithParent:(UIViewController*) mainController;
- (void) invokeMailSender:(NSString*) to:(NSString*) subject:(NSString*) failureTitle:(NSString*) failureMessage:(NSString*) failureCancel;
#end
MailSender.m:
#import "MailSender.h"
#implementation MailSender
MFMailComposeViewController* mailer;
UIViewController* mailParentController;
- (id) initWithParent:(UIViewController*) mainController
{
if( self = [super init])
{
mailParentController = mainController;
}
return self;
}
- (void) invokeMailSender:(NSString*) to:(NSString*) subject:(NSString*) failureTitle:(NSString*) failureMessage:(NSString*) failureCancel;
{
if([MFMailComposeViewController canSendMail])
{
mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
[mailer setSubject:subject];
NSArray *toRecipients = [NSArray arrayWithObjects:to, nil];
[mailer setToRecipients:toRecipients];
[mailParentController presentModalViewController:mailer animated:YES];
}
else
{
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:failureTitle message:failureMessage
delegate:nil cancelButtonTitle:failureCancel otherButtonTitles: nil];
[alert show];
}
}
-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
// Do nothing
[mailParentController dismissModalViewControllerAnimated:YES];
mailer = nil;
}
#end
I called the class from a View Controller (in a button touch down action) using the following instructions:
#implementation InfoViewController
MailSender *sender;
- (IBAction)openMail:(id)sender
{
sender = [[MailSender alloc] initWithParent:self];
[sender invokeMailSender:#"test#test.com" :#"123" :#"123" :#"123" :#"123"];
}
....
#end
When I run the code, I am able to show the email views correctly. However, this is then followed by a crash.
Note that I do not have a crash when using MFMailComposeViewController directly from my UIViewController (And assigning the View Controller as the delegate),
Any ideas?
Sorry I am still a new to Objective C :)
You need to retain your sender MailSender instance. It is being released after you call the invoke message.
You could do this by declaring a property named sender. E.g.
#property (strong, nonatomic) MailSender *sender;
...
#synthesize sender = _sender;
...
self.sender = [[MailSender alloc] initWithParent:self];
[self.sender invokeMailSender:#"noor#dimachk.com" :#"123" :#"123" :#"123" :#"123"];
By the way, your method declaration is a bit funny. You should name the arguments. E.g.
- (void)invokeMailSender:(NSString *)sender
to:(NSString *)to
subject:(NSString *)subject
failureTitle:(NSString *)failureTitle
failureMessage:(NSString *)failureMessage
failureCancelButtonTitle:(NSString *)failureCancelButtonTitle
How can I dismiss the ABPersonViewController? Here is my code
#pragma mark - Edit Record Method
-(void)btnEditContactTapped:(id)sender {
// Fetch the address book
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordID recID = ABRecordGetRecordID(record);
ABRecordRef record1 = ABAddressBookGetPersonWithRecordID(addressBook,recID);
ABPersonViewController *personViewController = [[ABPersonViewController alloc]init];
// set delegate
personViewController.personViewDelegate = self;
// Allow editing info
personViewController.allowsEditing = YES;
// Display contact info of selected person
personViewController.displayedPerson = record1;
// Person view controllers must be used with a navigation controller in order to function properly.
UINavigationController *nc = [[UINavigationController alloc]
initWithRootViewController:personViewController];
[self presentModalViewController:nc animated:YES];
[personViewController release];
}
#pragma mark - ABPersonViewControllerDelegate Method
- (BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue {
[self dismissModalViewControllerAnimated:YES];
return NO;
}
record in my ivar declared as ABRecordRef record in .h file.
ABPersonViewControllerDelegate method never gets called? What's going wrong? Any kind of help is appreciated. Thanks
Have you implemented thesse protocols in .h of your project.. ?
< ABPeoplePickerNavigationControllerDelegate,
ABPersonViewControllerDelegate,
ABNewPersonViewControllerDelegate,
ABUnknownPersonViewControllerDelegate>
I am adding contact info from my iPhone application on Addcontact click. I just want to open edit contact window on same Addcontact click so user can edit or delete the contact which just now have added. I have done smthing like below..
- (IBAction)AddContact
{
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef Showroom = ABPersonCreate();
//adding contact name as showroom name
ABRecordSetValue(Showroom, kABPersonFirstNameProperty, ShowroomName.text , nil);
ABAddressBookAddRecord(addressBook, Showroom, nil);
ABAddressBookSave(addressBook, nil);
// Fetch the address book
//ABAddressBookRef addressBook = ABAddressBookCreate();
// Search for the person named "Appleseed" in the address book
//ABRecordRef Showroom = (ABRecordRef)[Showroom objectAtIndex:0];
ABPersonViewController *picker = [[[ABPersonViewController alloc] init] autorelease];
picker.personViewDelegate = self;
picker.displayedPerson = Showroom;
// Allow users to edit the person’s information
picker.allowsEditing = YES;
[self.navigationController pushViewController:picker animated:YES];
}
this is my Map application. On launching I get showroom results with there contacts. This I can add in to the iPHone contact with edit contact window opening. But when I open other controller to pass user selected string address in to Map controller to search showroom location. The same above code is not working. I mean it only add the contacts but I didnt get the edit contact window.
Edit:
May be this problem is regarding navigation controller bar so check the below code also
- (void)viewWillAppear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
- (void)viewDidLoad {
[self.navigationController setNavigationBarHidden:NO ];
self.navigationController.navigationBar.tintColor = [UIColor colorWithRed:25.0/255.0f green:25.0/255.0f blue:25.0/255.0f alpha:1.0f];
}
- (void)viewWillDisappear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
I hope this code is works for you i implements that code and in my application works fine thank you
contecviewcontroller.h
#interface DetailsViewController : UIViewController
DocumentNavController *coffeeObj;
editViewController *evController;
int currentindex;
}
#property (nonatomic, retain) DocumentNavController *coffeeObj;
#property (readwrite, assign) int currentindex;
#end
contecviewcontroller.m
- (void)viewDidLoad {
[super viewDidLoad];
//self.navigationController.toolbar.tintColor = [UIColor darkGrayColor];
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemEdit
target:self action:#selector(goToEdit)]autorelease];
}
-(void)goToEdit{
if(evController == nil)
evController = [[editViewController alloc]initWithNibName:#"editViewController" bundle:nil];
evernoteAppDelegate *appdelegete = (evernoteAppDelegate *)[[UIApplication sharedApplication]delegate];
coffeeObj = [appdelegete.noteArray objectAtIndex:currentindex];
evController.Editcurrentindex = currentindex;
evController.docedObj = coffeeObj;
[self.navigationController pushViewController:evController animated:YES];
}
I have a custom UIButton class in my IPhone navigation application. When the user clicks the button I present a modal view which displays a tableview list of records that the user can select from.
On click of the button I create my viewController and show it using the following code:
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
dropDownPickerViewController = [[DropDownListingViewController alloc] initWithNibName:#"DropDownListingView" bundle:[NSBundle mainBundle]];
.....
.....
[[(AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate] navigationController] presentModalViewController:dropDownPickerViewController animated:NO];
[dropDownPickerViewController release];
[super touchesEnded:touches withEvent:event];
}
As you can see the button could be on any viewController so I grab the navigationController from the app delegate. Than in my DropDownPickerViewController code i have the following when a user selects a record:
[[(AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate] navigationController] dismissModalViewControllerAnimated:NO];
But nothing occurs. It seems to freeze and hang and not allow any interaction with the form. Any ideas on why my ModalViewController wouldnt be dismissing? Im thinking it is the way I use the app delegate to present the viewController. Is there a way to go self.ParentViewController in a UIButton class so I can get the ViewController of the view that the button is in (if this is the problem)?
Any ideas would be greatly appreciated.
Thanks
I did recall that I did have to do something similar once, and by looking at this post:
Get to UIViewController from UIView?
I was able to create some categories:
//
// UIKitCategories.h
//
#import <Foundation/Foundation.h>
#interface UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController;
- (id) traverseResponderChainForUIViewController;
#end
#interface UIView (FindUINavigationController)
- (UINavigationController *) firstAvailableUINavigationController;
- (id) traverseResponderChainForUINavigationController;
#end
//
// UIKitCategories.m
//
#import "UIKitCategories.h"
#implementation UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController {
// convenience function for casting and to "mask" the recursive function
return (UIViewController *)[self traverseResponderChainForUIViewController];
}
- (id) traverseResponderChainForUIViewController {
id nextResponder = [self nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]]) {
return nextResponder;
} else if ([nextResponder isKindOfClass:[UIView class]]) {
return [nextResponder traverseResponderChainForUIViewController];
} else {
return nil;
}
}
#end
#implementation UIView (FindUINavigationController)
- (UINavigationController *) firstAvailableUINavigationController {
// convenience function for casting and to "mask" the recursive function
return (UINavigationController *)[self traverseResponderChainForUINavigationController];
}
- (id) traverseResponderChainForUINavigationController {
id nextResponder = [self nextResponder];
if ([nextResponder isKindOfClass:[UINavigationController class]]) {
return nextResponder;
} else {
if ([nextResponder isKindOfClass:[UIViewController class]]) {
//NSLog(#" this is a UIViewController ");
return [nextResponder traverseResponderChainForUINavigationController];
} else {
if ([nextResponder isKindOfClass:[UIView class]]) {
return [nextResponder traverseResponderChainForUINavigationController];
} else {
return nil;
}
}
}
}
#end
you can then call them like so:
UINavigationController *myNavController = [self firstAvailableUINavigationController];
UIViewController *myViewController = [self firstAvailableUIViewController];
maybe they will help you, I hope so.
In your DropDownPickerViewController, Instead of this:
[[(AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate] navigationController] dismissModalViewControllerAnimated:NO];
Try
[self dismissModalViewControllerAnimated:NO];
I would call a method on the button's "parent" viewController and do it from there.
Update 9/2/10: This code no longer works as of the iOS 4 update--it fails with an internal assertion. There is now a great Address Book API example available in the iPhone SDK Reference Library called "QuickContacts."
The example code is available here; it will help you solve this problem:
http://developer.apple.com/iphone/library/samplecode/QuickContacts/Introduction/Intro.html
I'm attempting to add a feature to my app that allows the user to select a contact from an ABPeoplePickerNavigationController, which then displays an ABPersonViewController corresponding to the contact they picked. At that point, I want the user to be able to click on a contact's phone number and have my app respond with custom behavior.
I've got the ABPeoplePickerNavigationController working fine, but I'm running into a problem displaying the ABPersonViewController. I can get the ABPersonViewController to animate onto the screen just fine, but it only displays the contact's photo, name, and company name. None of the contact's other fields are displayed.
I'm using the 'displayedProperties' element in the ABPersonViewController to tell the program to display phone numbers. This creates some strange behavior; when I select a contact that has no phone numbers assigned, the contact shows up with "No Phone Numbers" written in the background (as you'd expect), but when selecting a contact that does have a phone number, all I get is a blank contact page (without the "No Phone Numbers" text).
Here's the method in my ABPeoplePickerNavigationController delegate class that I'm using to create my PersonViewController class, which implements the ABPersonViewController interface:
- (BOOL) peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {
BOOL returnState = NO;
PersonViewController *personView = [[PersonViewController alloc] init];
[personView displayContactInfo:person];
[peoplePicker pushViewController:personView animated:YES];
[personView release];
return returnState;
}
Here's my PersonViewController.h header file:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <AddressBookUI/AddressBookUI.h>
#interface PersonViewController : UIViewController <ABPersonViewControllerDelegate>
{
}
- (void) displayContactInfo: (ABRecordRef)person;
#end
Finally, here's my PersonViewController.m that's creating the ABPersonViewController to view the selected contact:
#import "PersonViewController.h"
#implementation PersonViewController
- (void) displayContactInfo: (ABRecordRef)person
{
ABPersonViewController *personController = [[ABPersonViewController alloc] init];
personController.personViewDelegate = self;
personController.allowsEditing = NO;
personController.displayedPerson = person;
personController.addressBook = ABAddressBookCreate();
personController.displayedProperties = [NSArray arrayWithObjects:
[NSNumber numberWithInt:kABPersonPhoneProperty],
nil];
[self setView:personController.view];
[[self navigationController] pushViewController:personController animated:YES];
[personController release];
}
- (BOOL) personViewController:(ABPersonViewController*)personView shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue
{
return YES;
}
#end
Does anyone have any idea as to why I'm seeing this blank Contact screen instead of one with clickable phone number fields?
Alright, I think I'm getting closer to finding the problem. I'm fairly sure it's with this part of the displayContactInfo call above:
[self setView:personController.view];
When I omit this line, all I see is a blank screen when I click a contact. The ABPeoplePickerNavigationController is pushing the PersonViewController onto the NavigationController stack. The PersonViewController then instantiates an ABPersonViewController object, but for whatever reason the ABPersonViewController never gets properly added to the NavigationController stack.
Does anyone know how to add the ABPersonViewController to the stack, rather than just the PersonViewController?
Just a heads-up to anyone who runs into this problem themselves: I was able to product the correct behavior by instantiating the ABPersonViewController in its delegate's viewDidLoad() method as below:
As before, here's my ABPeoplePickerNavigationController delegate's method:
- (BOOL) peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
BOOL returnState = NO;
PersonViewController *personView = [[PersonViewController alloc] init];
[peoplePicker pushViewController:personView animated:YES];
[personView displayContactInfo:person];
[personView release];
return returnState;
}
Here's my PersonViewController.h (ABPersonViewController delegate) header file:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <AddressBookUI/AddressBookUI.h>
#interface PersonViewController : UIViewController <ABPersonViewControllerDelegate>
{
ABPersonViewController *personController;
}
- (void) displayContactInfo: (ABRecordRef)person;
#end
Finally, here's the delegate's implementation (PersonViewController.m):
#import "PersonViewController.h"
#implementation PersonViewController
- (void) viewDidLoad
{
}
- (void) viewDidUnload
{
[personController release];
}
- (void) displayContactInfo: (ABRecordRef)person
{
personController = [[ABPersonViewController alloc] init];
[personController setDisplayedPerson:person];
[personController setPersonViewDelegate:self];
[personController setAllowsEditing:NO];
personController.addressBook = ABAddressBookCreate();
personController.displayedProperties = [NSArray arrayWithObjects:
[NSNumber numberWithInt:kABPersonPhoneProperty],
nil];
[self setView:personController.view];
}
- (BOOL) personViewController:(ABPersonViewController*)personView shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue
{
// This is where you pass the selected contact property elsewhere in your program
[[self navigationController] dismissModalViewControllerAnimated:YES];
return NO;
}
#end
Hopefully this ends up being helpful for someone. The AddressBook UI framework was a bit tricky for me to wrap my head around (although I'm new to iPhone development so I'm still learning a lot of the nuances of iPhone program organization).