Can I call a method without triggering its event listeners? - objective-c

Is there any sort of flag or way to call a method without triggering any event handlers?
FOR EXAMPLE
I'm handling a controlTextDidChange method and checking to see if the character returned by a keystroke is valid. If it's not, I remove it; if it is, I append a word. The problem is that when I change the text while in controlTextDidChange, controlTextDidChange is called again and the program will loop indefinitely. I know I can use an instance variable to get around this, but is there any sort of flag or way to call a method without triggering any event handlers?

To expand the comment into a quick answer.
You have a method that issues a notification by design. You want it to not issue that notification. You don't have an alternative available that does the same thing w/o the notification. If you want it to never issue that notification, and you have access to the code for the method, you could swizzle the method to a version where you've just commented out the notification. Of course, if you had the code, you could just add another method, and call that one. So you don't have the code, and all that's moot.
Can't you just bracket that invocation in code that removes the listener and then restores the listener? In other words, psuedocode like this:
[self.controlThingy removeObserver:self]
[self.controlThingy myMethod]
[self.controlThingy addObserver:self]
You've then made self deaf to notifications for that one invocation of myMethod. I've done similar things with bindings and KVO.

Related

wxWidgets: is it possible to nest two different wxTimers?

I am writing an application that stays in the traybar and do some checks every some minutes.
When it performs this checks, I would like the traybar icon to be animated.
That is why I have a first wxTimer triggering checks. In its OnTimer call I tried to manage the second wxTimer to handle the animation.
The issue is that timers work in the mainloop, so the icon is not updated when the second timer updates the icon index.
Is there a way to overcome this problem?
Thank you!
Your description of the problem is unfortunately not clear at all but if you mean that you don't get timer events until you reenter the event loop, this is indeed true and, moreover, almost tautological -- you need to return to the event loop to get any events.
This is the reason why your event handlers should always execute quickly and return control to the main loop. And if they take too long, the usual solution is to use a background thread for the real work and just schedule it in your event handler, but not wait until it is done.
Basing on Ryan G's comment
It is possible to incorporate wx.Yield() into the main loop. This is usually used to temporarily release the global lock to allow the widgets to update.
It is also possible to create a separate thread to update the animation independently from the main thread.
Using wx.Yield() should be easier to implement.

Is NSApp terminate:id deprecated?

I have been searching for how to terminate my application programmatically. I found in many topics people using NSApp terminate:id.
In Xcode terminate:id is crossed. Is this method deprecated ? Should I use it to terminate my application ? If no which is the right way to do it ?
Update:
Picture of what i mean when I say that it's crossed:
I don't see that terminate is deprecated. A possible cause for the compiler warning might be that in
[NSApp terminate:sender]
NSApp returns a general id, so that the compiler does not know which terminate message is actually meant. An indeed, if I use "Jump to Definition", Xcode jumps to
#protocol NSInputServiceProvider
...
- (void) terminate:(id)sender NS_DEPRECATED_MAC(10_0, 10_6);
But if you use the equivalent code
[[NSApplication sharedApplication] terminate:sender];
then the compiler warning goes away.
Nope, not deprecated:
terminate:
Terminates the receiver.
- (void)terminate:(id)sender
Parameters
sender
Typically, this parameter contains the object that initiated the termination request.
Discussion
This method is typically invoked when the user chooses Quit or Exit from the application’s menu.
When invoked, this method performs several steps to process the termination request. First, it asks the application’s document controller (if one exists) to save any unsaved changes in its documents. During this process, the document controller can cancel termination in response to input from the user. If the document controller does not cancel the operation, this method then calls the delegate’s applicationShouldTerminate: method. If applicationShouldTerminate: returns NSTerminateCancel, the termination process is aborted and control is handed back to the main event loop. If the method returns NSTerminateLater, the application runs its run loop in the NSModalPanelRunLoopMode mode until the replyToApplicationShouldTerminate: method is called with the value YES or NO. If the applicationShouldTerminate: method returns NSTerminateNow, this method posts a NSApplicationWillTerminateNotification notification to the default notification center.
Do not bother to put final cleanup code in your application’s main() function—it will never be executed. If cleanup is necessary, perform that cleanup in the delegate’s applicationWillTerminate: method.
Availability
Available in OS X v10.0 and later.
See Also
– run
– stop:
– applicationShouldTerminate: (NSApplicationDelegate)
– applicationWillTerminate: (NSApplicationDelegate)
– replyToApplicationShouldTerminate:
NSApplicationWillTerminateNotification
Related Sample Code
BlastApp
PreLoginAgents
Declared In
NSApplication.h

Get notified when NSDocument is saved

How can I get notified when NSDocument is saved, the first time and subsequent times?
I first thought that overriding writeToURL:ofType:error: would do it, but it appears that this method is also called for temporary autosaves before the document is saved for the first time, and maybe on copy/duplicate operations.
On the other hand, setFileURL: appears to be called the first time that the document is saved but not on subsequent times.
Is there some kind of Save notification? Or do I have to work around the various border cases of the above methods?
NSDocument has writeSafelyToURL::::, which in addition to the target location URL also gets a NSSaveOperationType passed in.
This would allow you to filter out autosave operations.
Don't forget to call the super implementation when overriding writeSafelyToURL.

how to continue after calling objc_msgSend

I am doing meta-programming with objective-C and try to automate some of an application functions. Thus, I am not changing the source code files and the view controllers of the application but from another file I am managing to get the UI navigation stack and I am using Objective-C Runtime Reference to find the tappable UI elements and the actions. for example for a button I found the target and action and call objc_msgSend to programatically fire the event.
step = (NSObject *)objc_msgSend(element.target, NSSelectorFromString(element.action));
However I need to be notified when the action was done, or in other word, I need to wait until the action was done and then continue my automation. I was thinking of using NSNotificationCenter
//To raise an event
[[NSNotificationCenter defaultCenter] postNotificationName:FIRE_EVENT_NOTIFICATION object:self];
but doesn't look like working.
I am even thinking of using Categories or
So I am not sure if there is anyway to wait for objc_msgSend and where should I continue.
It isn't entirely clear what you are trying to do and the exact problem that you are having but I'll have a go at answering your question.
If I understand correctly you are trying to fire the action associated with a UI element, presumably something like a button press. You have a reference to the element in element and you want to call the associated action on the elements target. The following assumes the action is an IBAction.
The simplest way to do this would presumably be:
[element.target performSelector:element.action];
Note: element.action almost certainly returns a SEL (a selector) not an NSString so there is no need to run it through NSSelectorFromString().
Normally, an IBAction event would receive the clicked on element as a parameter so I think you might want to do:
[element.target performSelector:element.action withObject:element];
IBAction's have no return value so there is nothing to store when the method returns.
performSelector: and performSelector:withObject: will only return once the called method has run to completion. You shouldn't need to organise some sort of notification of the action completing.
However, if the action you are calling is launching code on another thread then it is possible that the called action will return before the result of pressing the button has completed. This will be difficult to monitor without knowledge of the code that is being run.
If, for some reason, you have to use objc_msgSend then you would use the following:
objc_msgSend(element.target, element.action, element);
Like performSelector:, objc_msgSend will only return when the called method has run to completion.
Hopefully I have understood your question and my answer makes sense, it is entirely possible I'm barking up the wrong tree though.

Globally monitoring NSMouseMoved returns NSMouseUp

I'm trying to register the NSMouseMoved event globally using this line of code:
[NSEvent addGlobalMonitorForEventsMatchingMask:NSMouseMoved handler:mouseMovedBlock];
However, my mouseMovedBlock only gets called when the mouse gets clicked and not when the mouse is moved. I tried detecting the type of the NSEvent and it returns NSMouseUp, which doesn't really make any sense.
Why is my program acting so strange / what did I miss?
Turns out it was a simple mistake. I just changed "NSMouseMoved" to "NSMouseMovedMask". I simply forgot that it needed to be an event mask instead of a normal event type.