Replacing a call to sleep when waiting on an NSStream response - objective-c

I made an application which uses NSStream to etablish a connection to a telnet server.
When the connection is made, I send a first command. Then I use sleep(1); to make my application wait. Then the second command is sent.
The problem is that the entire GUI is stuck during the sleep(). I know that it's not the "perfect" way to make a "pause" and I'd like to learn how to this properly. I heard good things about NSTimer but I'd like to have a concrete and "easy" way of using it, to simply replace my poor use of sleep().

You should be able to register some kind of callback with whatever procedure you're using to establish the connection. Just let your code wait for that callback without doing anything at all.
In this case, using NSStream, you need to schedule the stream on the run loop:
[stream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
The run loop is the construct that processes events for your application. When you use sleep(), it is stopped, and your GUI can't do anything. By adding the stream as input to the run loop, you allow them both to continue to work.
You also must set a delegate object ([stream setDelegate:self];, e.g.) which will recieve notifications when the stream has something to report. That delegate must implement stream:handleEvent:, which will be called with a reference to the stream and a code indicating what happened.

Related

Objective-C console app that will never terminate while connected to Redis

I have a Objective-C/Swift console application that I am updating to connect to Redis (pub/sub). However, the application exits prior to even connecting to the Redis server.
How can I have the application (main thread) essentially run forever without blocking the background threads (NSOperationQueue)?
I've developed something similar in C# and used the "Console.Read()" function to essentially wait forever. I tried using the same approach for this program with "scanf(...)" but that appears to block the execution of the background threads.
I found this question, Console App Terminating Before async Call Completion for C#. Is there anything similar in Objective-c/Swift?
Any input would be greatly appreciated.
Thanks!
[[NSRunLoop currentRunLoop] run];
Do that on your main thread. It'll never return.
If you have some code you want to invoke in the context of the run loop, use dispatch_after() or performAfter:... or variant therein.

Understanding the Objective-C event loop

How can I log every message sent in a single iteration of the Objective-C event loop?
I want to further my understanding of the Objective-C runtime and thought this would be a good start.
These functions will cause all messages to be logged to a file in /tmp, based on the PID of the process. Good on simulator, but not on an iDevice.
// Start logging all messages
instrumentObjcMessageSends(YES);
// Stop logging all messages
instrumentObjcMessageSends(NO);
The CFRunLoopObserver opaque type should do exactly what you want. It is
a general means to receive callbacks at different points within a running run loop.
Use the activity argument to its creation function to specify when you want your observer serviced. For your case, this will probably be either kCFRunLoopEntry or kCFRunLoopExit.
You can get the CFRunLoopRef from the current NSRunLoop, [[NSRunLoop currentRunLoop] getCFRunLoop], or by using CFRunLoopGetCurrent().

Asynchronous NSUrlConnection not on main runloop

I am creating a set of classes which interface with a web service. At the core of this, the data is retrieved from the service using an asynchronous NSUrlConnection. In my mind, it is important that it is asynchronous, as a client of these web service interfaces has to have the ability to cancel a request that is in progress (i.e. cancel an NSUrlConnection).
The web service calls return JSON data, potentially lots of it, and this is parsed and the classes I am creating will create proper data structures out of them. Depending on which web service method is called, the request can end up being expensive - too expensive to run on the main thread, so I would like to either add the option of running the service requests asynchronously, or not giving the option, and forcing asynchronous calls.
Async calls are all well and good, but I am having problems starting an NSUrlConnection asynchronously on a runloop that isn't the main one. The problem I'm describing seems to be fairly well documented: I am led to believe the delegate of the NSUrlConnection is not called because the runloop that launches the connection has terminated, and therefore the calls back to the delegate cannot be scheduled on its runloop.
What is the best way to go about solving this issue?
I have tried using:
while (!self.isRequestComplete && !self.isRequestCancelled)
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
It seems to work ok from the basic trial I have done, except if the runloop that this is being executed on is actually the main runloop, for which I have had a few crashes...
Would an option be to offer asynchronous calls to clients, and then use the above method if the option is utilised? Is there a better way of achieving what I am trying to do?
What I am aiming to achieve is for a package of classes that allow interfacing with my specific web service, where the clients of my code do not need to worry about whether their own delegates (which my classes hold references to) will be called on different threads. I want them to be called on the exact same runloop that they called my code on - basically, exactly how NSUrlConnection operates!
Thanks in advance!
Nick
I think you may have "gone up the wrong creek" so to speak. Generally speaking you don't need to worry about run loops unless you are doing something rather odd. It sounds like you need to do some reading on multi-threading, particularly Grand Central Dispatch.

Distributed Objects, Threading, Objective-C

I have a working server/client app using Distributed Objects in objective-c. What I am struggling with right now is making the app multi-threaded. So that more users can access the server at the same time.
Here is main function for the server. This is where I create the nsconnection object.
From my understanding, the way I should approach this is when a user tries to access the server, a new thread should be allocated for that particular call. Should the [conn runInNewThread] takes care of this ?
Any thoughts is appreciated...
Here is the code for the server.
int main (void)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Transactions *trans = [Transactions new];
NSConnection *conn = [NSConnection defaultConnection];
[conn setRootObject: trans];
[conn runInNewThread];
if (![conn registerName:#"holycow"])
{
NSLog (#"Failed registering holycow.");
exit (1);
}
NSLog (#"waiting for connections...");
[[NSRunLoop currentRunLoop] run];
[pool release];
return 0;
}
In order to respond to client messages, the responding server object
must be set as the ’root object’ of an instance of the NSConnection
class, and this NSConnection must be registered with the network by
name.
So in case of Distributed object, single server object can handle multiple clients. or you can create more server object and divide your clients.
#Parag Bafna was right in his answer when I ran a test. However, I used a special kind of architecture in the server that may have aided in this. Take for instance a command that takes a long time to run on the server daemon. This can hang a server up a bit and make it much slower for connections to be processed. Here's my solution.
Have the client call an asynchronous class method using the oneway property. Let's call this runProcess.
Make runProcess do a popen() on the task and keep the PID as a global variable.
Then, make it use performSelectorInBackground to run a synchronous class method called readProcess in the background.
In readProcess, I use while(fgets(buff, sizeof(buff), ghPID)!=NULL) to read the previously established popen() output (note the global variable, ghPID) and append the latest line read into a global variable of recent lines read. This method runs as a background task, and the client has already disconnected from runProcess.
Now have the client connect to a synchronous class method called getProcessData. This should then take the global variable of recent lines read and return it back. Since that doesn't take very long to do, the client disconnects from that class method pretty quickly.
The client can then poll that data until it knows it's done. To aid with that, you can create a synchronous method called isProcessRunning that can check on a global boolean variable on the server daemon called gbRunning and return true/false. Of course, though, it will be up to you to flip that variable in the server daemon true/false in the various class methods when the server is busy running a popen() task.
By doing it this way, your server daemon can respond to concurrent requests much faster.
An additional tip would be to use a kill file or other mechanism (shared memory? SIGHUP?) so that if you're in a while loop and you want that process to stop, you can just drop a kill file somewhere in /tmp for instance and the process will use pclose to kill it and then erase the kill file. I also do this before starting a process if I want to ensure only one particular process runs at a time from that server daemon.

kqueue NOTE_EXIT doesn't work

I am trying to use Apple's example of using kqueue but the callback is never called unless I start observing the kqueue after the process starts. But the lifetime of the process is short and i need the code to work if the process starts before or after I start observing it.
What if you send the process a SIGSTOP immediately after starting it, and then SIGCONT after setting up the kqueue?
If you're using fork and exec directly, you could have the child send itself SIGSTOP (using raise(3)) and have the parent send it SIGCONT.