Why is my window:willPositionSheet:usingRect: delegate method not called? - macos

I need to reposition a NSAlert window. I found out already, that to do that I need to implement the (NSRect)window:(NSWindow *)window willPositionSheet:(NSWindow *)sheet usingRect:(NSRect)rect method in the delegate.
My code where I trigger the Alert Window is in the following method:
- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
NSAlert* jsAlert = [[NSAlert alloc] init];
[jsAlert addButtonWithTitle:#"OK"];
[jsAlert setMessageText:#""];
[jsAlert setInformativeText:message];
[jsAlert setAlertStyle:NSWarningAlertStyle];
// [jsAlert setDelegate:self];
[jsAlert beginSheetModalForWindow:sender.window modalDelegate:self didEndSelector:#selector(alertDidEnd:returnCode:contextInfo:) contextInfo:NULL];
}
There I set the modalDelegate so self, where self is the AppDelegate. I implemented the following method in the AppDelegate:
- (NSRect)window:(NSWindow *)window willPositionSheet:(NSWindow *)sheet usingRect:(NSRect)rect {
NSLog(#"we are here: %s", __func__);
return NSMakeRect(0, 0, 100, 100); // just fake
}
This method won't be called. From what I've found in the documentation this should work though and I cannot comprehend why it doesn't.
I also tried the following, i.e. making the AppDelegate comply to the NSWindowDelegate-protocol (and the NSAlertDelegate protocol, when commenting in the uncommented line in the first code snippet).
#interface AppDelegate : NSObject <NSApplicationDelegate, NSAlertDelegate, NSWindowDelegate>
I read everywhere that this should just work. What am I doing wrong here?

The only thing left to do was to actually register the AppDelegate as NSWindowDelegate like this:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// [...]
[self.window setDelegate:self];
// [...]
}
This sounds very trivial, but then I needed a hell lot of time to find that out, as all examples I saw didn't do it. They just set modalDelegate to self which in my case should be the AppDelegate.
I hope this helps someone out there...

Related

Calling method from another class doesn't execute the whole method

In an OSX-application I have a main class A and a second class B. Both run a window each, at the same time.
In class A there is a button that plays a movie in an AVPlayerView (called playerView) [The movie is loaded into the PlayerView earlier!]:
- (IBAction)runMovieN:(id)sender {
[playerView.player play];
}
This works perfectly fine. The movie is played immediately after clicking the button.
On the other hand, in class B there is a button that calls a method in class A...
- (IBAction)runMovie:(id)sender {
ViewController *runMovieButton = [[ViewController alloc] init];
[runMovieButton runMovie];
}
...which will run this method in class A:
- (void)playPause {
NSLog(#"A");
[playerView.player play];
}
The problem is, that the Log will be printed out perfectly fine, but anything else that is in this method will be ignored, no matter what is in there. The content of the bracket is being ignored completely, except for the Log.
The solution is probably very easy, but I just cannot come up with any that could possibly work.
In your MainViewController.h
#interface MainViewController : UIViewController
-(void)playMedia:(NSURL*)url;
#end
In your MainViewController.m
#interface MainViewController ()
#property(nonatomic, retain) AVPlayerLayer *layer;
#property(nonatomic, retain) AVPlayer *player;
#end
#implementation MainViewController
-(void)playMedia:(NSURL*)url{
self.player = [AVPlayer playerWithURL:url];
self.layer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
self.layer.frame = CGRectMake(0, 0, 200, 200);
[self.view.layer addSublayer: self.layer];
[self.player play];
}
-(IBAction)playButton:(id)sender
{
[self playMedia:[NSURL URLWithString:#"http://content.jwplatform.com/manifests/vM7nH0Kl.m3u8"]];
}
-(IBAction)moveToChild:(id)sender
{
[self.layer.player pause];
[self.layer removeFromSuperlayer];
self.player=nil;
ChildViewController* childView = [[ChildViewController alloc] initWithNibName:#"ChildViewController" bundle:nil];
[self presentViewController:childView animated:YES completion:nil];
}
#end
In you ChildViewController.h
#interface ChildViewController : MainViewController
#end
In your ChildViewController.m
-(IBAction)playButton:(id)sender{
[self playMedia:[NSURL URLWithString:#"http://srv6.zoeweb.tv:1935/z330-live/stream/playlist.m3u8"]];
}
Please not if their is no Parent child relation in two classes you can also use delegates to interact between Viewcontrollers

Adding a UIViewController before UIImagePickerController

I have the following code to load a UIImagePickerController which works fine.
UIImagePickerController *mediaUI = [[UIImagePickerController alloc] init];
mediaUI.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
mediaUI.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil];
mediaUI.delegate = self;
[controller presentModalViewController: mediaUI animated: YES];
return YES;
I would like to load a modal view with some help information on how to use the UIImagePickerController:
UIStoryboard *storyboard = self.storyboard;
HelpViewController *svc = [storyboard instantiateViewControllerWithIdentifier:#"HelpViewController"];
[self presentViewController:svc animated:YES completion:nil];
How can I display the UIImagePickerController after the user dismisses the HelpViewController view?
Don't be tempted to move directly from HelpViewController to UIImagePickerController, you need to get there via your mainViewController.
Let's put your code into a method...
- (void) presentImagePicker {
UIImagePickerController *mediaUI = [[UIImagePickerController alloc] init];
mediaUI.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
mediaUI.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil];
mediaUI.delegate = self;
[controller presentModalViewController: mediaUI animated: YES];
return YES;
}
(Note that presentModalViewController:animated is depracated since ~iOS5, and you should really replace it with
[controller presentViewController:mediaUI animated:YES completion:nil];)
Let's call your viewControllers mainVC, helpVC and imageVC. There are two ways you can implement this.
method 1 - performSelector
The quick-and-slightly-dirty solution is to do this in your helpVC's dismiss button method:
- (IBAction)dismissHelpAndPresentImagePicker:(id)sender
{
UIViewController* mainVC = self.presentingViewController;
[mainVC dismissViewControllerAnimated:NO completion:
^{
if ([mainVC respondsToSelector:#selector(presentImagePicker)])
[mainVC performSelector:#selector(presentImagePicker)];
}];
}
It's slightly dirty because you need to ensure that presentImagePicker is implemented in mainVC - the compiler will give you no warnings if it is not. Also you are running a completion block after it's object has been dismissed, so there's no certainty it's going to work (in practice, it does, but still...)
Note that you have to assign the pointer self.presentingViewController's to a local variable (mainVC). That's because when helpVC is dismissed, it's presentingViewController property is reset to nil, so by the time you get to run the completion block you cannot use it. But the local variable mainVC is still valid.
method 2 - protocol/delegate
The clean way to do this is to use a protocol in helpVC to declare a delegate method, and make mainVC the delegate. This way the compiler will keep track of everything and warn you if it is not correctly implemented.
Here are the steps to do that:
In helpVC.h add this protocol above the #interface section:
#protocol helpVCDelegate
- (void) dismissHelpAndPresentImagePicker;
#end
In helpVC.h interface section declare a property for its delegate:
#property (nonatomic, weak) id <helpVCDelegate> delegate;
(the <helpVCDelegate> tells the compiler that the delegate is expected to conform to the protocol, so it will have to implement dismissHelpAndPresentImagePicker)
In helpVC.m your method can now look like this:
- (IBAction)dismissHelpAndPresentImagePicker:(id)sender
{
[self.delegate dismissHelpAndPresentImagePicker];
}
In MainVC, when you create HelpVC (=svc in your code), set MainVC as it's delegate:
HelpViewController *svc = [storyboard instantiateViewControllerWithIdentifier:#"HelpViewController"];
svc.delegate = self;
[self presentViewController:svc animated:YES completion:nil];
And be sure to implement the delegate method dismissHelpAndPresentImagePicker
- (void) dismissHelpAndPresentImagePicker
{
[self dismissViewControllerAnimated:NO completion:^{
[self presentImagePicker];
}];
}
Personally I would always use method 2. But I offered up a that solution earlier today to a similar question, and the questioner seemed to think protocol/delegate was overcomplicated. Maybe my answer just made it seem so, I have tried to simplify it here.

Using a calendar in Xcode 4.2 iPhone

I have been learning Xcode 4.2 for a bit now and still can't get my head round on how the create a calendar so i really hope you guys can help me sort out my errors and maybe tell me what the next step in the code is to get this working i really appreciate your time thanks.
This is the storyboard
.h there are no errors here
#import <UIKit/UIKit.h>
#import <EventKitUI/EventKitUI.h>
#interface FirstViewController : UIViewController <EKEventEditViewDelegate> {
}
-(IBAction) createEvent;
#end
.m this is where the errors are
#import "FirstViewController.h"
#import <EventKitUI/EventKitUI.h>
#implementation FirstViewController
-(IBAction) createEvent {
//Get the event store object
EKEventStore *eventStore = [[EKEventEditViewController alloc] INIT];
//Cretae the EditViewController
EKEventEditViewController* controller = [[EKEventEditViewController alloc] INIT];
controller.eventStore = eventStore;
controller.editViewDelegate = self;
[self presentModalViewController:controler animated:YES];
[controller release];
}
//delegate method for EKEventEditViewDelegate
-(void)eventEditViewController:(EKEventEditViewController *)controller
didCompleteWithAction:(EKEventEditViewAction)action {
[self dismissModalViewControllerAnimated:YES];
}
Errors:
EKEventStore *eventStore = [[EKEventEditViewController alloc] INIT];
Receiver type 'EKEventEditViewController' for instance message does not declare a method with selector 'init'
EKEventEditViewController* controller = [[EKEventEditViewController alloc] INIT];
Receiver type 'EKEventEditViewController' for instance message does not declare a method with selector 'init'
[controller release];
'release' is unavailable: not available in automatic reference counting mode 2
That's all the errors hope you guys can tall me whats wrong i really appreciate it :)
It's init, not INIT.
You need to get rid of the [controller release]; if you're using ARC.
So, change to this:
-(IBAction) createEvent {
//Get the event store object
EKEventStore *eventStore = [[EKEventStore alloc] init];
//Cretae the EditViewController
EKEventEditViewController* controller = [[EKEventEditViewController alloc] init];
controller.eventStore = eventStore;
controller.editViewDelegate = self;
[self presentModalViewController:controler animated:YES];
}

How I tell my UITextField (code) to resign first responder?

I have created my UITextField by code, without InterfaceBuilder. I want the keyboard to disappear when the button "Done" is pushed. How does the code know that I am referending to an UITextField and no to other one
First, thanks a lot.
My code is like this:
-(void)viewDidLoad {
[super viewDidLoad];
field = [[UITextField alloc] initWithFrame:CGRectMake(30, 100, 185, 30)];
field.adjustsFontSizeToFitWidth = YES;
field.textColor = [UIColor blackColor];
field.placeholder = #"Text";
field.keyboardType = UIKeyboardTypeDefault;
field.returnKeyType = UIReturnKeyDone;
field.backgroundColor = [UIColor blueColor];
field.delegate = self;
[self.view addSubview:field];
}
......
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
}
With this code I push the button Done and nothing happen. Is like that how you say?
Edit:
I've created two UITextField how I did with the previous one. But now, for each row I do this:
if ([indexPath row] == 0) {
[cell.contentView addSubview:pTextField];
}
else {
[cell.contentView addSubview:pTextField];
}
So with this code, the program received signal "EXC_BAD_ACCESS". Any idea why happen this?
How does the code know that I am referending to an UITextField and no to other one
Your textFieldShouldReturn: method's textField parameter will always be the text field that is currently active.
The method has to return a BOOL, you should be getting compiler warnings with it as it stands. Try
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
Note that you are also currently leaking memory in the way you add the text field. You should set it as a property as per WrightCS's answer so that you can refer to it later on. So at the end of your viewDidLoad:
self.myTextField = field;
[field release];
Define your textField in your header, then you can use the following:
.h
#interface MyeViewController : UIViewController <UITextFieldDelegate>
{
UITextField * myTextField;
}
#end
.m
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[myTextField resignFirstResponder];
/* textField here is referenced from
textFieldShouldReturn:(UITextField *)textField
*/
}
Make sure you set the delegate of your programatically created UITextField to self (the view controller that created the object) and implement the appropriate UITextFieldDelegate method (I think its textFieldShouldReturn:) and call in that method resignFirstResponder on the textField argument passed to the delegate method (which will be your UITextField).

NSOperation will not cancel NSXMLParser. Which continues to call methods on delegate causing crash

I am trying to download some XML on another thread, and parse it.
I release the 'controller' then call cancelAllOperations on the NSOperationQueue.
And implement method 'cancel' on NSoperation which attempts to set nSXMLParser's delegate to nil.
But a second or so later the NSXMLParser is still alive and kicking and calls methods on it's delegate (which now no longer exists) causing a crash.
I just dont get it, what am I doing wrong?
#import "LoadXMLTheadedController.h"
#import "LoadXMLThreaded.h"
#implementation LoadXMLTheadedController
- (id)initWithURLString:(NSString *)newString
{self = [super init];
queue = [[NSOperationQueue alloc] init];
loadXMLThreaded = [[LoadXMLThreaded alloc] initWithDelegate:self andXMLURLString:newString];
[queue addOperation:loadXMLThreaded];
return self;
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
NSLog(#" do some parsing.. ");
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[queue cancelAllOperations];
[loadXMLThreaded release];
[queue release];
[super dealloc];
}
#end
//----------------------------------------------------------------//
#import "LoadXMLThreaded.h"
#implementation LoadXMLThreaded
- (id)initWithDelegate:(id)newDelegate andXMLURLString:(NSString *)newString
{
[super init];
delegate = newDelegate;
url = [[NSURL URLWithString:newString]retain];
return self;
}
- (void)cancel{
nSXMLParser.delegate = nil;
[nSXMLParser abortParsing];
}
- (void)main {
nSXMLParser = [[NSXMLParser alloc]initWithContentsOfURL:url];
nSXMLParser.delegate = delegate;
[nSXMLParser parse];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
nSXMLParser.delegate = nil;
[nSXMLParser abortParsing];
[nSXMLParser release];
[url release];
[super dealloc];
}
#end
The NSOperation's cancel method simply sets a flag. It does not forcibly halt the NSOperation itself. The user is responsible for implementing the necessary code to stop whatever's running at the moment.
You would need to check periodically to see if the cancel flag is set, then call abort on NSXMLParser yourself.
I know I'm late to the party with this one, but thought I'd put in my 2 cents. Going off of #futureelite7, you should never override the cancel method.
Instead, throughout your NSOperation's subclass, you should periodically verify if the operation is cancelled by using isCancelled and act accordingly. In this case, we want to abort the parsing.
For example, after your NSXMLParser delegate methods, make this the first line in the method:
// make your parser an ivar
if ([self isCancelled]) [operationParser abortParsing];
In addition, I recommend making your NSOperation the NSXMLParser delegate, so all parsing is encapsulated within your NSOperation subclass.
And lastly, just an fyi, aborting parsing will cause an error with code NSXMLParserDelegateAbortedParseError. Just be aware of it during error handling.
Apple's documentation:
abortParsing
Stops the parser object.
- (void)abortParsing
Discussion
If you invoke this method,
the delegate, if it implements
parser:parseErrorOccurred:, is
informed of the cancelled parsing
operation.
I'm just guessing. Normally sending a method to nil isn't a problem in Objective-C. But maybe NSXMLParser does something fancy internally.
General remarks about your code
Learn how to write the init method correctly.
You don't have to set the delegate of an object to nil that is going to be deallocated anyway.

Resources