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
Related
I have a method on one of my ViewController's that is called by one of its view's and delivered some value. It then sends out a message to a manager object with some information about the VC's state.
- (void)elementXChangedWithValue:(float)value {
ParameterManager * pMan = [ParameterManager sharedInstance];
[pMan updateParameter:self.elementX.parameter value:value];
}
In debugging, it was important for me to inspect what the .SomeElement.parameter state was so I could know what was getting lost in translation by the time I get to my ParameterManager.
Unfortunately, although Self is definitely non-nil and accessible the debugger shows scant information about the class making quick and practical glancing of the value difficult. (i will sometimes invoke "po" command in the debugger command line, however).
Not sure if it helps but this project is running heavy with the Objective-C/Swift interoperability although the ViewController is a fully Objective-C class.
Here is an image of what I am getting in the debugger. The drop-down arrow shows nothing but empty.
The debugger isn't perfect and sometimes you just cant see what is in certain areas, such as self. What does always work is NSLog's placed in code though, so if all else fails, add one of those in at the right place to print out the object you wish to know about.
The debugger may show more info after you make it execute these commands:
expr #import UIKit;
expr #import Foundation;
This loads the whole UIKit and Foundation symbols in the debugger at runtime, you only need to execute it once per debug session.
You can automate this with a user-defined breakpoint that'll be triggered every time your application starts in the debugger.
Source : http://furbo.org/2015/05/11/an-import-ant-change-in-xcode/
I've noticed the following error popping up in the console when running my app on iOS 9 when using a storyboard. I'm using xCode7. Is this something I need to be concerned about?
-[UIApplication _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion:] ** unhandled action -> <FBSSceneSnapshotAction: 0x176bfb20> {
handler = remote;
info = <BSSettings: 0x176a5d90> {
(1) = 5;
};
}
There is nothing wrong with your code. This is a logging message internal to Apple, and you should file a radar about it.
There are two hints that show that this is probably Apple's code:
The underscore leading the method name _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion is a convention indicating that the method is private/internal to the class that it's declared in. (See this comment.)
It's reasonable to guess that the two letter prefix in FBSSceneSnapshotAction is shorthand for FrontBoard, which according to Rene Ritchie in "iOS 9 wish-list: Guest Mode" is part of the whole family of software related to launching apps:
With iOS 8, Apple refactored its system manager, SpringBoard, into several smaller, more focused components. In addition to BackBoard, which was already spun off to handle background tasks, they added Frontboard for foreground tasks. They also added PreBoard to handle the Lock screen under secure, encrypted conditions. [...]
I have no idea what the BS prefix in BSSettings is for, but
BS is shorthand for BackBoard Settings, and an analysis of this log message would indicate that it's not anything you did, and you should file a radar with steps to reproduce the logging message.
If you want to try and grab a stack trace, you can implement the category linked to here. Some would argue that overriding private API is a bad idea, but in this case a temporary injection to grab a stack trace can't be too harmful.
EDIT:
But, we still want to know what this action is. So I put a breakpoint on -[UIApplication _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion] and started printing out register values and found a class called FBSceneImpl which had a whole bunch of information about my application:
We are able to find out which private method is called next (stored in the program counter, instruction pointer, register 15.)
I tried finding the un-handled FBSceneSnapshotAction referenced in the log, but no dice. Then, I subclassed UIApplication, and overrode _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion. Now I was able to get at the action directly, but still, we don't know what it is.
Then, I looked at the FBSceneSnapshotAction again. Turns out it has a superclass called BSAction.
Then I wrote a tool similar to RuntimeBrowser and looked up all of the subclasses of BSAction. It turns out that there's quite a list of them:
The two method names we have (one from the log and one from the program counter on the devices) indicate that these actions are used under the hood for passing actions around the system.
Some actions are probably sent up to the app delegate's callbacks, while others are handled internally.
What's happening here is that there is an action that wasn't handled correctly and the system is noting it. We weren't supposed to see it, apparently.
AFAIK, the info above is related to iOS during snapshot the screen (i suppose for double click home multitask related behaviour).I deeply investigated my application and seems that it does not get any side behaviours. You can safely ignore it, for now.
You can use the following gist simple category to test yourself against the calls to the above function:
I have figured it out, it will happen when you have IBAction method declared in .h or .m file but you have not bind it to any control.
.m example:
- (IBAction)click:(id)sender{
}
but not assigned this method to any control in storyboard.
haven't find out why it happens in my app, but at least you can catch the exception, if you want to keep this from popping up in your log pane. It's not a solution, but it might give you more insight why it is happing by inspecting any of the arguments that are passed in the catch.
swift 2 version:
import UIKit
extension UIApplication {
func _handleNonLaunchSpecificActions(arg1: AnyObject, forScene arg2: AnyObject, withTransitionContext arg3: AnyObject, completion completionHandler: () -> Void) {
//whatever you want to do in this catch
print("handleNonLaunchSpecificActions catched")
}
}
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.
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.
From what I have learned so far: In Objective-C you can send any message to any object. If the object does implement the right method it will be executed otherwise nothing will happen. This is because before the message is sent Objective-C will perform respondsToSelector.
I hope I am right so far.
I did a little program for testing where an action is invoked every time a slider is moved. Also for testing I set the sender to NSButton but in fact it is an NSSlider. Now I asked the object if it will respond to setAlternateTitle. While a NSButton will do and NSSlider will not. If I run the code and do respondsToSelector myself it will tell me the object will not respond to that selector. If I test something else like intValue, it will respond. So my code is fine so far.
- (IBAction)sliderDidMove:(id)sender
{
NSButton *slider = sender;
BOOL responds =
[slider respondsToSelector:#selector(setAlternateTitle)];
if(responds == YES)
{
NSLog(#"YES");
}
else
{
NSLog(#"NO");
}
[slider setAlternateTitle:#"Hello World"];
}
But when I actually send the setAlternateTitle message the program will crash and I am not exactly sure why. Shouldn't it do a respondsToSelector before sending the message?
First of all, the name of a method (its selector) includes all subparts and colon characters, as mvds said.
Second of all, the method -respondsToSelector: is not called by the runtime, it's usually called by the user (yourself or APIs that want to know if a delegate, for example, responds to an optional method of the protocol).
When you send a message to an object, the runtime will look for the implementation of the method in the class of the object (through the object's isa pointer). It's equivalent to sending -respondsToSelector: although the message itself is not dispatched. If the implementation of the method is found in the class or in its superclasses, it's called with all the arguments you passed in.
If not, then the runtime gives the message a second chance to be executed. It will start by sending the message + (BOOL)resolveInstanceMethod:(SEL)name to the class of the object: this method allows you to add the method at runtime to the class: if this message returns YES, it means it can redispatch the message.
If not it gives the message a third chance to be executed, it sends - (id)forwardingTargetForSelector:(SEL)aSelector with the selector, this method can return another object that may be able to respond to the selector on behalf of the actual receiver, if the returned object can respond, the method is executed and the value is returned as if it was returned by the original message. (Note: This is available beginning with OS X 10.6 or iOS 4.)
If the returned object is nil or self (to avoid infinite loops), the runtime gives the message a fourth chance to execute the method… It sends the message - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector to get a method signature in order to build an invocation. If one is provided then an invocation is sent through the message - (void)forwardInvocation:(NSInvocation *)anInvocation. In this method you can parse the invocation and build other messages to send to other targets in any ways you want, and then you can set the return value of the invocation… That value will act as the return value of the original message.
Finally, if no method signature is returned by the object, then the runtime sends the message - (void)doesNotRecognizeSelector:(SEL)aSelector to your object, the implementation of this method in NSObject class throws an exception.
For one thing, the selector is not only the "name" of the message, but also what follows, i.e. the arguments, and their names.
So the correct selector for some -(void)setAlternateTitle:(NSString*)str would be
#selector(setAlternateTitle:)
with the :
As for your problem: If a class respondsToSelector() and you perform that selector, you shouldn't get a crash on sending an unknown selector. What kind of crash log do you see in the debugging window?
(ps. why not include the [slider setAlternateTitle:...] in the if ( responds ) { ... } conditional block?)
"This is because before the message is
sent Objective-C will perform
respondsToSelector."
I guess this is not correct. If the object does not respond to selector, it will crash at runtime. There is no automatic checking by the system. If there was a check by the run time system then we should never get "unrecognized selector sent to instance" exception.
Please make me correct if I am wrong.
EDIT: This is not a straight forward crash, but the default result is the process will be terminated. The whole sequence is already explained in comment and other answer, so I am not going to write that again.
There is an +instancesRespondToSelector: method. As the name suggests, it tells you whether the instances of the class implement that method.