I'm trying to build a super-simple Cocoa app, basically one that has one function (for example, main()) with a while loop. It does some stuff, does a curl request, then waits a few seconds before starting over.
I've got my project all setup in XCode with all the necessary variables and functions, but I don't know where to put my main() function that does all the work.
Where do I define the main function?
Cocoa is very much oriented towards event-driven programming. That end, the main() function generally just starts up the main runloop and then the application delegate can kick off anything it wants to do. That said, it's certainly possible to write a non-event-based cocoa program that uses main() To do more complicated stuff. In that case, it works basically the same as in C.
Cocoa With Love just had a post about Minimalist Cocoa programming that may be of interest. It uses main() to do some work. It's not really something I would recommend emulating in your own app, but it's certainly possible.
If you design your app according to the usual Cocoa architecture, you don't really put any of your own code in main. The whole app should be event driven (where events are things like UI interactions from the user, network events, etc).
That said, there is a main function. If you've created a default Cocoa project in XCode, the main function will be in a file called "main.m". It will get run just like a main function in C. You'll see that there's a call in there to NSApplicationMain(). That's what starts a Cocoa application running (creates the application, loads the main nib file, starts running the main run loop, etc) . NSApplicationMain() doesn't return until the application quits, so if you really want to put stuff in main(), you need to put it above the call to NSApplicationMain().
Again, that's not the normal "Cocoa way" to do things, but without more info about what you want to do, it's hard to give you more advice.
As others have answered, it's possible to implement what you want to do in a way you suggested, i.e., by running a while loop inside main.
However, that is not the best way to write a Cocoa app which reloads a URL once in a few seconds. In a different environment, there's a different standard way to do things. So, you sometimes need to un-learn what you got used to. You might have thought: I want to do X. In language/environment A, I would have coded like P to do X. Now I'd like to use language/environment B. How should I implement P? That's not the way to get used to a new environment. Just ask, How should I do X in the environment B?
The most Cocoa-esque way would be this:
Open XCode, create a new project, choose a Cocoa GUI app from the template.
In the application delegate, implement applicationDidFinishLaunching:. We are going to set up an NSTimer.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSTimer*timer=[NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:#selector(timerFired:)
userInfo:nil
repeats:YES];
}
This creates a timer which fires once in five seconds, and at each time it fires it calls the method timerFired: of the app delegate itself, specified by self. For more on NSTimer, read this apple document.
Implement timerFired:.
- (void)timerFired:(NSTimer*)theTimer{
// do whatever you want. you can use plain C to invoke curl,
// or if you want you can use Cocoa methods to access a URL.
}
There's no fourth step!
The main function is provided by the template. It calls NSApplicationMain, which set up the Cocoa system. Eventually, it calls applicationDidFinishLaunching: of your delegate for you. You respond to that message. Then you set up a timer. The timer calls the method you specified for you. Then you respond to that message, again. That's basically how Cocoa works. The Cocoa system asks you to do something, so you do something. Your control over the flow of the program becomes rather passive, compared to what you would have programmed in Applescript.
To add to Andrew Madsen's answer, the best thing to do is start with an Xcode project template. It'll get a skeletal main(), a XIB, a plist, and other standard Cocoa stuff set up for you.
Related
I bought the Big Nerd Ranch Guide for Objective-C, and there is something about NSRunLoop I can't figure out.
Here's a chunk of code from the book:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:logger
selector:#selector(updateLastTime:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] run];
My question is, why do I need to put an NSRunLoop for the NSTimer object to be processed? And why does it need to be at the end, and not the beginning?
Why it is not like the other functions or object's methods where I simply have to call a function for it to be processed and logged into the console?
I'm really trying figure out every logic of every detail here.
From the early days of what would become Cocoa, when dinosaurs roamed the Earth, rocks were soft, and NeXT workstations were new, up until 10.6 came out, the most common type of multitasking was the run loop. It's cooperative multitasking. There are no threads. There is no preemptive scheduler or kernel. There are no context switches. There's just a big run loop that says "what needs doing now?" and runs it. And when that thing completes, it waits for the next thing that needs doing and runs that. It literally is a big while(true) loop. Well, technically the line of code is:
for (;;) { ... }
You can see for yourself in CFRunLoop.c. Look for __CFRunLoopRun.
NSTimer was invented in those days. All it does it make a note in the runloop telling it "when this time passes, then please do this." (It's a tiny bit more complicated than that because it uses mach ports, look for __CFRunLoopTimerSchedule in the same file for details, but basically that's the idea.)
So the point is, there's no magic. There's just a big for(;;) loop that processes this stuff. Something has to run it. And when you start it (with run), it doesn't return. It's an infinite loop. There is no "background." There are no other threads. And that's why you need to do things in the order BNR tells you to. Otherwise your next line of code wouldn't run.
Of course in iOS apps and OS X GUI apps, you don't usually have to do this yourself. The run loop gets created for you during program startup, and the whole main thread lives inside of it. It's the thing that calls you most of the time. You don't call it. But if you're on a thread other than the main thread, and you want to use run loop functionality, you're going to have to run it yourself.
Today, a lot of things are done with GCD rather than run loops. That's the "until 10.6 came out" that I mentioned. It really changed the Cocoa world. But a huge amount of Cocoa still relies on the run loop, and it's still the workhorse of most apps even if you never think about it.
In most cases today, if you're having to create a runloop in order to use NSTimer, you shouldn't be using NSTimer. Just use dispatch_after. In fact, that's what I usually recommend most of the time today even if you do have a runloop.
(And you should definitely read the link #quelish gives in the comments. It is the definitive word on run loops.)
How can I know when NSSpeechSynthesizer finishes speaking?
You read the documentation for NSSpeechSynthesizer and discover the -speechSynthesizer:didFinishSpeaking: delegate method.
Then, if you're not sure how to use delegate methods, you read more documentation about Cocoa delegates.
Then, if you still can't get it to work, you post a separate question here including as many details as you can about what you've tried (hint: code, a description of your app and how things are connected, etc.) and what isn't working (ie, the delegate method is never called, it crashes, etc.).
I know that my question perhaps sound's a bit confusing, but I wan't to stop the terminating of a Cocoa Mac Os X application. I don't know if there is an API to that. And I also don't know how to do that.
My idea was to call an NSAlert inside the applicationWillTerminate: method. But that doesn't stop the termination of the App.
Another possibility would be to use a while loop, which doesn't stop, but this isn't any good practice, because it uses a lot of CPU and doesn't add any possibility of keeping the rest of the app running.
Please give me an idea, how I could solve this problem.
Much times thanks. =D
Implement the application delegate method applicationShouldTerminate:. Return either NSTerminateCancel or NSTerminateLater. If you return NSTerminateLater then you should eventually call replyToApplicationShouldTerminate: with your final answer.
now I'm developing a GUI with pop-up windows, so actually it is a workpackage with multiple GUIs.
I have read thorough the examples given in help files (changme, and toolpalette), but I failed to animate the method to transfer data from the new one back to the old one.
Here is my problem.
I have two GUIs, A, the Main one and B that I use it to collect input data and I want to transfer the data back to B.
Question 1:
I want to define new subclasses of handles in A.
lets say,
handles.newclass
how can I define its properties, e.g. 'Strings'?
Question 2:
In A, a button has the callback
B('A', handles.A);
so we activate B.fig.
After finished the work in B,
it has collected the following data (string and double) in B(!)
title_1 itle_2 ... title_n
and
num_1 num_2 ... num_n
I want to pass the data back to A.
Following the instruction, I wrote the codes shown below.
mainHandles = guidata(A);
title = mainHandles.title_1;
set(title,'String',title_1);
However, when I go back to A, handles in A was not changed at all.
Please someon help me out here.
Thank you!
=============update================
The solution I found is adding extra variables (say handles.GUIdata) to handles structure of one GUI, and whenever the data are required, just read them from the corresponding GUI.
And It works well for me, since I have a main control panel and several sub-GUIs.
There is a short discussion of this issue here.
I have had similar issues where I wanted external batch scripts to actually control my GUI applications, but there is no reason two GUI's would not be able to do the same.
I created a Singleton object, and when the GUI application starts up it gets the reference to the Singleton controller and sets the appropriate gui handles into the object for later use. Once the Singleton has the handles it can use set and get functions to provide or exchange data to any gui control that it has the handle for. Any function/callback in the system can get the handle to the singleton and then invoke routines on that Singleton that will allow data to be exchanged or even control operations to be run. Your GUI A can, for instance, ask the controller for the value in GUI B's field X, or even modify that value directly if desired. Its very flexible.
In your case be sure to invalidate any handles if GUI A or B go away, and test if that gui component actually exists before getting or modifying any values. The Singleton object will even survive across multiple invocations of your app, as long as Matlab itself is left running, so be sure to clean up on exit if you don't want stale information laying around.
http://www.mathworks.com/matlabcentral/fileexchange/24911-design-pattern-singleton-creational
Regarding Question 2, it looks like you forgot to first specify that Figure A should be active when setting the title. Fix that and everything else looks good (at least, the small snippets you've posted).
I am developing a multi-threaded application in Cocoa. The main thread takes values from the user, and when a button is clicked I invoke a secondary thread in which a long calculation takes place. Now from this thread I have to return the output of every step of the calculation to the main thread. I want to periodically send data from one thread to the other. I can't find any simple example that does this. Any ideas?
There are a number of ways to do this, in rough order of complexity (easiest first):
use NSObject's performSelectorOnMainThread:withObject:waitUntilDone: which is pretty self explanatory.
use performSelector:onThread:withObject:waitUntilDone:, which will let you go the other way
use an NSNotification (and NSDistributedNotificationCenter), though you can easily run into a race condition if you're not careful
Use NSPorts to send data back and forth
Check out the doc that Abizer mentioned for details on all of these.
performSelectorOnMainThread:withObject:waitUntilDone: is often the easiest way to update the UI with a background thread's progress. You could also create your own storage area that's safe to access between threads using NSLock or a similar mechanism, or even use distributed objects (which also works between processes or over a network).
Then there's NSOperationQueue and NSOperation which does help a lot to simplify multi-threaded programming, although a lot of programmers have been avoiding it since it can cause a crash in certain circumstances under Leopard.
Have a look at the Apple docs for this.
You may need to create an ADC member account, but this is free
Multi-threaded Cocoa Programs