Cocoa: int main function - objective-c

I'm curious, what role does the int main function play in a Cocoa program? Virtually all of the sample code I've been looking at has only the following code in main.m:
#import <Cocoa/Cocoa.h>
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **) argv);
}
What exactly is this doing, and where does the program actually start stepping through commands? It seems my conceptions need readjustment.

Since a Cocoa project starts like any other, the entry point for the Operating system is main. However the Cocoa Architecture is constructed to actually start the processing of your program from NSApplicationMain, which is responsible for loading the initial window from your application and starting up the Events loop used to process GUI events.
Apple has a very in depth discussion on this under the Cocoa Fundamentals Guide : The Core Application Architecture on Mac OS X

If you want to learn how control passes from "launch this" to the main() function, the execve man page has the details. You would also want to read about dyld. main() is a part of the Unix standard. Every single program that you can run effectively has a main().
As others have mentioned, NSApplicationMain passes control to Cocoa. The documentation is quite specific as to what it does.
One interesting note, NSApplicationMain doesn't actually every return. That is, if you were to separate the call to NSApplicationMain from the return in your main function and put code in between, that code would never be executed.

main() is the entry point for your program.
When you run your program that is the first function called. Your program ends when you exit that function.
Also note that this does not come from Objective-C. This is simple C.
Have a look at
Wikipedia's page on it

Value returned from main is returned by the process to operating system when the process is done.
Shell stores the value returned by last process and you can get it back with $? :
> ls
a b c
> echo $?
0
> ls x
x: No such file or directory
> echo $?
1
ls is an application like anything else.
You can use the return value to chain multiple processes together using shell script or anything else that can execute a process and check for return value.

I'm wondering where the code begins
executing (like why does an NSView
subclass execute and draw without me
explicitly calling it?) and if I'm not
supposed to stick my main loop in int
main() where does it go?
In an xcode project you have a main.m file that contains the 'int main' function. You won't actually find the code that calls the NSView draw explicitly, this code is hidden deep within an iPhone or Mac OS X framework. Just know that there is an event loop hidden deep within your 'int main' that checks for changes so that it knows when to update your view. You don't need to know where this event loop is, it's not useful information since you can override methods or create and assign delegates that can do things when this happens.
To get a better answer, you'll need to explain what you mean by a 'main loop' that you wanted to put inside the 'int main' function.
It's just weird to me coming off a
little experience in C++. It looks
unnatural that the main function would
be so empty.
You can encapsulate a billion lines of code into one function and put it into 'int main'. Don't be deceived by a main only having a few lines, that is done on purpose. Good programming teaches us to keep code in specific containers so that it is well organized. Apple chose to make the "real" launch point of their iPhone apps in this single line of code inside the main.m file:
int retVal = UIApplicationMain(argc, argv, nil, #"SillyAppDelegate");
From that one piece of code, an app's delegate is launched and won't return control to the main function until it is done.

Related

Is it OK to have Mac OS X application without an NSApplication instance?

In the Info.plist, I have one key "Application is background only" and its value is "Yes".
Most of the code is in C++.
The usual last line
return NSApplicationMain(argc, argv);
in main() is removed. Instead main starts some thread(s), blocks and waits on some condition to exit.
Yes and no.
You can have a process (colloquially an application) without it, and it will work just fine with the Unix side of things, and behave just like any other headless process.
What you cannot have is an Application in the sense of a full-fledged Cocoa Application, because an instance of NSApplication (or a subclass) isn't just a part of your application, in a very real sense the main application object is the application. Things like reading the Info.plist, hooking into the Cocoa Application System, Applescript System, and so on is all done by NSApplicationMain(), making it a requirement of a capital-A Application.
It is possible you could set some of these things up yourself, but I don't know of any ways to do so, and even if I did, I would not recommend it. If you want your program to behave like an application and interact with the Cocoa side of things, return NSApplicationMain(argc, argv); is the wait to end main() .
Yes it is OK. NSApplication is declared in AppKit so it is used only in GUI apps. An app can use Foundation, which does not require NSApplication.

Cannot inspect Self in method while debugging

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/

Objective-C: Refreshing FrontmostApplication

I wrote this little program which is supposed to print the current frontmost application twice, with a 3-second break in between.
void printFrontmostApp() {
NSRunningApplication *frontmostApplication = [NSWorkspace sharedWorkspace].frontmostApplication;
NSLog(#"%#",frontmostApplication);
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
printFrontmostApp();
sleep(3);
printFrontmostApp();
}
return 0;
}
When I ran this program, I realised that frontmostApplication is not refreshed when it is called the second time. I found the solution here. But I still have two questions:
1) I want to know why the frontmostApplication is not updated.
2) How do I force it to refresh every time I call it? I don't want to receive a notification every time the frontmost application deactivates, because it is a little inefficient for my purposes.
Edit:
Just to be crystal clear, let's suppose the time now is 10:00:00. I call printFrontmostApp, and it prints "Xcode" to the console, because Xcode is the current frontmost app. Then the program sleeps for 3 seconds. At 10:00:01, I opened another app, say TextEdit. At 10:00:03, my program calls printFrontmostApp for the second time. I expect it to print "TextEdit", which is the current frontmost application. But it prints "Xcode" instead. I can't understand this behaviour.
Can someone please explain what happens at 10:00:03? The function seems to "remember" the value of frontmostApplication at 10:00:00 and retains it when it is called the second time. I thought that any memory will be released once it goes out of scope, so why is this happening?
And how do I get my program to get the frontmost app at 10:00:03? I can get the frontmost app at 10:00:00, I should be able to do the same 3 seconds later right?
The documentation for -[NSWorkspace runningApplications] — not the method you're using, but related — says:
Similar to the NSRunningApplication class’s properties, this property will only change when the main run loop is run in a common mode. Instead of polling, use key-value observing to be notified of changes to this array property.
From the NSRunningApplication documentation:
Properties that vary over time are inherently race-prone. For example, a hidden app may unhide itself at any time. To ameliorate this, properties persist until the next turn of the main run loop in a common mode. For example, if you repeatedly poll an unhidden app for its hidden property without allowing the run loop to run, it will continue to return NO, even if the app hides, until the next turn of the run loop.
It's a near certainty that the same principle applies to -frontmostApplication even though the documentation doesn't say so explicitly. You will never get different results by polling without allowing the run loop to run.
For 1) the answer is the same described in the question you have linked: You have to observe this notification, that tells you when a new application was activated:
NSWorkspaceDidActivateApplicationNotification
About 2) You have different observers for activation and deactivation like:
NSWorkspaceDidDeactivateApplicationNotification
So your are not going to observe notifications that you are not registered, please take a look at NSWorkspace Notifications for a comprehensive list.
Otherwise, please define your question about refreshing/polling (that I think it's not a good idea anyways).

iOS9 storyboard what is unhandled action (handleNonLaunchSpecificActions)?

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")
}
}

What's the modern equivalent of GetNextEvent in Cocoa?

I'm porting an archaic C++/Carbon program to Obj-C and Cocoa. The current version uses asynchronous usb reads and GetNextEvent to read the data.
When I try to compile this in Objective C, GetNextEvent isn't found because it's in the Carbon framework.
Searching Apple support yields nothing of use.
EDIT TO ADD:
Ok, so what I'm trying to do is run a document scanner through USB. I have set up the USBDeviceInterface and the USBInterfaceInterface (who came up with THAT name???) and I call (*usbInterfaceInterface)->WritePipeTO() to ask the scanner to scan. I believe this works. AT least the flatbed light moves across the page...
Then I try to use *(usbInterfaceInterface))->ReadPipeAsyncTO() to read data. I give this function a callback function, USBDoneProc().
The general structure is:
StartScan()
WaitForScan()
StartScan() calls the WritePipeTO and the ReadPipeAsyncTO
WaitForScan() has this:
while (deviceActive) {
EventRecord event;
GetNextEvent(0,&event);
if (gDataPtr != saveDataPtr) { // more data up the timeout
timeoutTicks = TickCount() + 60 * 60;
saveDataPtr = gDataPtr;
}
if (TickCount() > timeoutTicks) {
deviceActive = false;
}
}
Meanwhile, USBDoneProc incrementing gDataPtr to be the end of the data that we've read so far. It gets called several times during the asynchronous read, called automatically by the callback, as far as I can tell.
If I cake out the GetNextEvent() call in the WORKING code the USBDoneProc doesn't get called until the asynchronous readpipe timesout.
So it looks to me that I need something to give control back to the event handler so that the USBRead interrupts can actually interrupt and make the USBDoneProcget called...
Does that make any sense?
thanks.
I suppose the nearest thing to a Cocoa equivalent would be -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]. But bear in mind that GetNextEvent is archaic even for Carbon. The preferred way of handing events is the "don't call us, we'll call you" scheme, where the app calls NSApplicationMain or RunApplicationEventLoop and events are dispatched to you.
EDIT to add: Does you app have a normal event loop? If so, maybe WaitForScan could start a Carbon timer and return to the event loop. Each time the timer fires, do what you did in the WaitForScan loop.
there is a USB hidapi that works for mac on windows.
http://www.signal11.us/oss/hidapi/
may this could be of help to you?
It works fine (I can list the connected USB devices and connect/write/read to a device);
however, if i USB device is connected/disconnected during the runtime of the application, I don't see the new connected/disconnected devices.
See: https://github.com/signal11/hidapi/issues/14
If I add the following code to hidapi, then hidapi detects the new USB devices.
#include <Carbon/Carbon.h>
void check_apple_events() {
printf("check_apple_events\n");
RgnHandle cursorRgn = NULL;
Boolean gotEvent=TRUE;
EventRecord event;
while (gotEvent) {
gotEvent = WaitNextEvent(everyEvent, &event, 0L, cursorRgn);
}
}
I need to compile this on OSX10.5 because it uses Carbon instead of Cocoa.
I am currently looking how to transform this to Cocoa.
you are also trying to move your code to cocoa, right?
let me know if you find out; I'll post it here if I get it.
regards,
David
Have you considered throwing the whole thing out and using Image Kit's new-in-10.6 scanner support instead? Even if it's custom, writing a TWAIN driver for it might be easier (and is certainly better) than trying to twist Cocoa into a GetNextEvent shape.