EKEventViewDelegate didCompleteWithAction not getting called - iphone

I don't get a call to my eventViewController:didCompleteWithAction: when the EKEventViewController finishes edting an event.
Here's how I set it up:
- (void)showCalendar:(id)sender {
EKEventViewController *eventViewController = [[EKEventViewController alloc] init];
eventViewController.delegate = self;
eventViewController.event = self.event;
// Allow event editing.
eventViewController.allowsEditing = YES;
[self.navigationController pushViewController:eventViewController animated:YES];
[eventViewController release];
}
I do have the protocol on my class and the method was implements by copy and pasting the definition from the docs. It just doesn't get called.
If I use the EKEventEditViewController and its corresponding delegate, then that does get called when the event is saved.
I was able to reproduce the problem in the SimpleEKDemo code same as well. Does anyone know what might be wrong?
I could just drop the view functionality and go straight to the EKEventEditViewController, but I'd rather not.

Might be a bit late to be helpful, but I had this problem as well.
To get around it I subclassed EKEventViewController, then in the subclass' viewDidLoad I replaced the standard edit button with one of my own:
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *editItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self.delegate action:#selector(editCalEvent)];
self.navigationItem.rightBarButtonItem = editItem;
}
That way when you want to edit an event, you can set up your own EKEventEditViewController and specify its delegate in order to respond to changes:
- (void)editCalEvent {
EKEventEditViewController *editController = [[EKEventEditViewController alloc] init];
editController.event = editingEvent;
editController.eventStore = self.eventStore;
editController.editViewDelegate = self;
[self presentModalViewController:editController animated:YES];
[editController release];
}
Hope that helps.

I had the similar problem when I use "pushViewController", the result is that it will go to
- (void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{}
But after I changed to presentModalViewController, it will go to eventViewController:didCompleteWithAction: when Done/Cancel/Delete are pressed.

in this .m file you need to import the EventKit/EventKit.h and EventKitUI/EventKitUI.h
and in the .h file you need to implement the 'EKEventViewDelegate' delegates.
hope it helps you

This does seem to be a fairly obvious omission in the library. My workaround: I'm presenting the EKEventViewController in a UINavigationController. I detect completion in the viewWillAppear method of the controller than pushed the EKEventViewController onto the view stack. Use a boolean variable in this view controller to track and differentiate between initial appearance and re-appearance due to the EKEventViewController being popped. There is a risk that your code will get called at other times, but if you are just refreshing tableviews, etc, then this should be sufficient.

Related

InitWithName Execution Before ViewDidLoad Possible?

I'm trying to move an NSString between two View Controllers and after searching around all convoluted ways, the easiest and most straight-forward way I want to get used to was to write an initWithName function in the Receiving VC and calling it in the Sending VC. It does move it successfully but I want it to get executed before ViewDidLoad loads the textViewer so that it shows right after the tab button is pressed. Here's the code from the sending VC:
- (void)textViewDidEndEditing:(UITextView *)textView
{
if ([textView.text isEqualToString: #""]) {
textView.text = #"*Paste the machine code in question here*";
}
SecondViewController *theVCMover = [[SecondViewController alloc] initWithName: textView.text];
[self.navigationController pushViewController:theVCMover animated:YES]; //Is this really necessary if I'm not going to segue it directly, I'm just waiting for the user to press the next tab
gotItLabel.text = #"Got it! Ready for action...";
}
And here's the code on the receiving VC:
- (id)initWithName:(NSString *)theVCMovee {
self = [super initWithNibName:#"SecondViewController" bundle:nil];
if (self) {
rawUserInput = theVCMovee;
CleanerText.text = rawUserInput;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
CleanerText.text = rawUserInput;
NSLog(#"Got the other tab's text and it's %# ", rawUserInput);
}
Your code is mostly fine, but you'll find that as you have more complex view controllers that you won't necessarily want to write custom initializers to do every bit of property setting. Note that if CleanerText is a UI element that you're loading from your nib, it doesn't help to set CleanerText.text in your init method—it's not loaded until -viewDidLoad is called.
You don't have to do everything in init, though, if you declare properties for rawUserInput or other variables you want to set. You can then just go:
SecondViewController *theVCMover = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
theVCMover.rawUserInput = textView.text;
theVCMover.otherProperty = otherValue;
....
And the rest of your code works the same.
You can't (reliably) call methods on an instance until init has finished executing, so this pattern is "safe" and is how it's supposed to work.

When to call selectRow: on a UIPickerView that has just loaded?

I am trying to learn iPhone/iOS programming. I have an UIPickerView that should dispay its selected row as soon as it becomes visible (it is contained on a flippSideView).
Unfortunately, the flipSideViewController's awakeFromNib is not called. It is somewhat too late to do it in viewDidLoad.
So, how can I make the pickerView display the selected row as soon it becomes visible?
Update:
Here is how I show the flipside view
- (IBAction)showInfo:(id)sender {
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"FlipsideView" bundle:nil];
controller.delegate = self;
controller.uData = userData;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];
controller.pickerView.delegate = userData;
controller.pickerView.dataSource = userData;
[controller release];
}// showInfo
In the flipside controller there is a method mySelect (to help me trace trace the calls)
-(void) mySelect:(NSString*) strMethod{
int row = [uData getCurrentUserRow];
[pickerView selectRow:row inComponent:0 animated:NO];
NSLog(#"selectRow %d called from %# (pickerView=%d uData=%d)", row, strMethod, (int)pickerView, (int)uData); }
and when the program runs it generates the log
selectRow 3 called from viewDidLoad (pickerView=87412720 uData=89267696)
selectRow 3 called from viewWillAppear (pickerView=87412720 uData=89267696)
selectRow 3 called from viewDidAppear (pickerView=87412720 uData=89267696)
It seems you're having the problem i had a couple days ago, i really don't think it's a bug I think the problem is when everything is called (could be wrong). Correct me if I'm wrong but you want your PickerView to display a certain value when it's first shown onscreen correct? Are you creating the PickerView in code or from a nib?
In my app, the below code snippet is right at the bottom of my viewDidLoad method
[pickerView selectRow: 100 inComponent:0 animated:YES];
This works as intended. Please post a snippet of your code so we can better understand your problem.
PS: When developing for iOS i would stay away from awakeFromNib and just use ViewDidLoad:
There apparently is a bug in some versions of iOS that means your view is not loaded until you call [super viewWillAppear:animated] or force it to load by calling [self view].

compilation error for navigation controller

I am new in objective C. I don't know much more things about this. I am practicing on navigation controller. The problem is that whatever methods I am putting in action:#selector in shows SIGABRT error.
could you clarify me which types of methods i can put in action:#selector section.
Though I know it's a silly question but I think these will clear my concept over navigationViewController.
thank you.
- (void)viewDidLoad
{
UISearchBar *search=[[UISearchBar alloc] init];
self.navigationItem.rightBarButtonItem=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:self action:#selector(searchBarShouldBeginEditing:)];
[super viewDidLoad];
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar{
UISearchBar *search=[[UISearchBar alloc] init];
[search resignFirstResponder];
return YES;
}
Try moving your '[super viewDidLoad]' to the beginning of the viewDidLoad method, not the end. YOu need to make sure the controls exist before you add the right bar button item.

ipad - dismissing a UIPopoverController

I have a button inside the content of a UIPopoverController. This button runs a method called myAction.
MyAction has the form
- (void) myAction:(id)sender
so, myAction receives the id of the caller button.
Now, inside this method I would like to dismiss the UIPopoverController, but the only thing I have is the ID of the caller button. Remember that the button is inside the UIPopoverController.
Is there a way to discover the ID of the UIPopoverController, given the button ID I already have?
thanks.
Unfortunately no. At least, not within the standard practices. You might be able to travel up the responder stack to find it, but it's a hack, it's buggy, and it's really, really messy.
If you want to dismiss a popover by pushing a button, some place relevant should keep a reference to the popover. Usually that would be the owner of the popover (not the controller showed within the popover). When the button is pressed, it can send a message to the owner controller, which can then dismiss the popover.
You might be tempted to have the controller displayed inside of the popover be the owner of its own popover, but coding this way is brittle, can get messy (again), and may result in retain loops so that neither ever gets released.
You can access the presenting popoverController by accessing "popoverController" with KVC.
[[self valueForKey:#"popoverController"] dismissPopoverAnimated:YES]
I have this working, and I do not think it is a hack. I have a standard split view iPad app. I then added a method on my detail controller (the owner of the pop over) to handle the dismissal.
On the standard split view architechture, both the root and detail view controllers are available via the app delegate. So I bound a button click inside the pop over to call a method which gets the app delegate. From there I call the method on the detail controller to dismiss the pop over.
This is the code for the method on the View Controller that is displayed inside the popover:
- (void) exitView: (id)sender {
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.detailViewController exitDrill];
}
Then the simple method to dismiss on the Detail View Controller:
- (void) exitDrill {
if(dtController != nil){
[dtController dismissPopoverAnimated: YES];
[dtController release];
}
}
I like the ability to do this because it give me a way to show a user how they can exit a pop over. This may not be necessary in future versions of the app; for right now, while this paradigm is still new to the platform, I prefer to let the users gexit a display in a couple fo different ways to make sure I minimize frustration.
As Ed Marty already wrote
If you want to dismiss a popover by pushing a button, some place relevant should keep a reference to the popover
This is very true; however, when showing a UIPopoverController, the class opening the popovercontroller keeps this resource already. So, what you could do is to use this class as the delegate class for your Popover Controller.
To do so, you could do the following, which I use in my code.
In the class opening the popover, this is my code:
- (void)showInformationForView:(Booking*)booking frame:(CGRect)rect
{
BookingDetailsViewController *bookingView = [[BookingDetailsViewController alloc] initWithStyle:UITableViewStyleGrouped booking:booking];
[bookingView setDelegate:self];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:bookingView];
self.popController = [[UIPopoverController alloc] initWithContentViewController:navController];
[self.popController setDelegate:self];
[self.popController setPopoverContentSize:CGSizeMake(320, 320)];
rect.size.width = 0;
[self.popController presentPopoverFromRect:rect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
}
- (void)dismissPopoverAnimated:(BOOL)animated
{
[self.popController dismissPopoverAnimated:animated];
}
So what I am doing here is creating a UINavigationController and setting a BookingDetailsViewController as its rootViewController. Then I am also adding the current class as delegate to this BookingDetailsViewController.
The second thing I added is a dismissal method called dismissPopoverAnimated:animated.
In my BookingDetailsViewController.h I added the following code:
[...]
#property (nonatomic, strong) id delegate;
[...]
And in my BookingDetailsViewController.m I added this code:
[...]
#synthesize delegate = _delegate;
- (void)viewDidLoad
{
UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] initWithTitle:#"Close" style:UIBarButtonItemStylePlain target:self action:#selector(closeView)];
[self.navigationItem setRightBarButtonItem:closeButton];
[super viewDidLoad];
}
- (void)closeView
{
if ([self.delegate respondsToSelector:#selector(dismissPopoverAnimated:)]) {
[self.delegate dismissPopoverAnimated:YES];
}
else {
NSLog(#"Cannot close the view, nu such dismiss method");
}
}
[...]
What happens is that when the "Close" button in the UINavigationController is pressed, the method closeView is called. This method check if the delegate responds to dismissPopoverAnimated:animated and if so, it calls it. If it does not respond to this method it will show a log message and do nothing more (so it wont crash).
I have written my code using ARC, hence there is no memory management.
I hope this helped you.

Can presentModalViewController work at startup?

I'd like to use a modal UITableView at startup to ask users for password, etc. if they are not already configured. However, the command to call the uitableview doesn't seem to work inside viewDidLoad.
startup code:
- (void)viewDidLoad {
rootViewController = [[SettingsController alloc]
initWithStyle:UITableViewStyleGrouped];
navigationController = [[UINavigationController alloc]
initWithRootViewController:rootViewController];
// place where code doesn't work
//[self presentModalViewController:navigationController animated:YES];
}
However, the same code works fine when called later by a button:
- (IBAction)settingsPressed:(id)sender{
[self presentModalViewController:navigationController animated:YES];
}
Related question: how do I sense (at the upper level) when the UITableView has used the command to quit?
[self.parentViewController dismissModalViewControllerAnimated:YES];
You can place the presentModalViewController:animated: call elsewhere in code - it should work in the viewWillAppear method of the view controller, or in the applicationDidFinishLaunching method in the app delegate (this is where I place my on-launch modal controllers).
As for knowing when the view controller disappears, you can define a method on the parent view controller and override the implementation of dismissModalViewControllerAnimated on the child controller to call the method. Something like this:
// Parent view controller, of class ParentController
- (void)modalViewControllerWasDismissed {
NSLog(#"dismissed!");
}
// Modal (child) view controller
- (void)dismissModalViewControllerAnimated:(BOOL)animated {
ParentController *parent = (ParentController *)(self.parentViewController);
[parent modalViewControllerWasDismissed];
[super dismissModalViewControllerAnimated:animated];
}
I had quite the same problem. I know the topic is old but maybe my solution could help someone else...
You just have to move your modal definition in a method:
// ModalViewController initialization
- (void) presentStartUpModal
{
ModalStartupViewController *startUpModal = [[ModalStartupViewController alloc] initWithNibName:#"StartUpModalView" bundle:nil];
startUpModal.delegate = self;
[self presentModalViewController:startUpModal animated:YES];
[startUpModal release];
}
Next, in viewDidLoad, call your modal definition method in a performSelector:withObject:afterDelay: with 0 as delay value. Like this:
- (void)viewDidLoad
{
[super viewDidLoad];
//[self presentStartUpModal]; // <== This line don't seems to work but the next one is fine.
[self performSelector:#selector(presentStartUpModal) withObject:nil afterDelay:0.0];
}
I still don't understand why the 'standard' way doesn't work.
If you are going to do it like that then you are going to have to declare your own protocol to be able to tell when the UITableView dismissed the parentViewController, so you declare a protocol that has a method like
-(void)MyTableViewDidDismiss
then in your parent class you can implement this protocol and after you dismissModalView in tableView you can call MyTableViewDidDismiss on the delegate (whihc is the parent view controller).