When using NSURLConnection in main(), why the connection can not finished? - objective-c

I'm testing the HTTPFileUploadSample now. Because I want to use it to create a type of command tool line program, so i call the method in the main() function, like this:
int main (int argc, const char * argv[])
{
#autoreleasepool {
Uploader *upl = [Uploader alloc];
[upl initWithURL:[NSURL URLWithString:#"http://localhost/uploader.php"]
filePath:#"/test.txt"
delegate:upl
doneSelector:#selector(onUploadDone)
errorSelector:#selector(onUploadError)];
//[[NSRunLoop currentRunLoop] run];
}
return 0;
}
I found it can create the connection and post request normally, but it can not finish the connection, because it do not call those delegate methods(connection:didReceiveResponse: or connection:didReceiveData: or connectionDidFinishLoading:) at all.
So I call the method [[NSRunLoop currentRunLoop] run] to run loop (as the comment in codes), then everything is ok. I do not know why. Can anybody give me some explanation? Thx!

The runloop is a big event handler infinite loop (well, infinite until it's stopped). It watches various sources and when they generate events it dispatches those events to listeners. This is a very effective way to manage asynchronous operations on a single thread.
NSURLConnection (and many other things in Cocoa) rely on the runloop for their processing. If nothing runs the runloop, then the events aren't processed.

Related

Stopping the NSApplication main event loop

I have an application consisting of the following single .m file:
#import <Cocoa/Cocoa.h>
int main(int argc, char* argv[]) {
[[[NSThread alloc] initWithBlock: ^{
sleep(2);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Stop");
[[NSApplication sharedApplication] stop:nil];
});
}] start];
[[NSApplication sharedApplication] run];
NSLog(#"Run finished");
return 0;
}
According to the developer documentation, stop should stop the main loop (run), but it doesn't (at least not on OS X 10.12 and 10.13). There's also terminate, but this exits the program too soon. I also tried setting an NSApplicationDelegate that implements applicationShouldTerminate, but this is never called.
How can I make sure the main run loop is (cleanly) exited?
Note: The shared application main loop is necessary because there is UI work being done elsewhere. More concretely, this is giving problems in the Go WDE UI library, which uses Cocoa to provide a window to a Go application.
The documentation for -stop: says:
[C]alling this method from a timer or run-loop observer routine would not stop the run loop because they do not result in the posting of an NSEvent object.
A block dispatched to the main queue is similar in that it doesn't post an event. You can try posting an NSEventTypeApplicationDefined event after calling -stop:.
After investigating this further, it seems that the UI loop stop request is only processed after a UI event (so not just after a main loop event). So, it works in response to a UI event, but not in a thread like I did in my example.
Triggering a UI event after a stop request (e.g. a programmatic resize works for me) causes the loop to end.

How to deal with concurrency issues brought by NSStream run loop scheduling using GCD?

I have the following situation where I create a GCD dispatch queue and in it I schedule an NSStream to the current NSRunLoop, as is required in its specification for it to emit delegate events, and then I make the run loop for that thread run using [[NSRunLoop currentRunLoop run].
This generates three possible scenarios:
Create a serial queue in which an initial write message is sent through the stream and other write messages are only sent when there's a delegate callback from the NSStream object, as attempting to write new messages without respecting this pattern (this would be desirable) will fail as the queue is locked by the run loop running.
Create a concurrent queue in which messages can be written to the stream freely, as blocks sent to the queue will be executed concurrently with the block that's running the run loop. However, while it is desirable to make writing messages and the run loop running concurrent, it certainly is not desirable to have to blocks in the queue running concurrently attempting to write at the same time to the stream.
Create two queues -- one responsible for keeping the run loop alive and receive read-from-stream callbacks and another one for sending asynchronous write messages to the stream. This would seem ideal, however it seems that the NSStream documentation specifically states that one should not attempt to read/write to a stream outside the thread it is scheduled in.
Given these scenarios none of which are ideal, how to solve these problems?
Late to the party, but instead of using runloops you can set the desired dispatch queue for your streams directly using
void CFReadStreamSetDispatchQueue(CFReadStreamRef stream, dispatch_queue_t q);
void CFWriteStreamSetDispatchQueue(CFWriteStreamRef stream, dispatch_queue_t q);
Where CFReadStreamRef can take a bridged NSInputStream and CFWriteStreamRef a bridged NSOutputStream. This way you don't have to schedule or unschedule runloops at all and your streams will run in the background.
Snippet from this Apple sample code:
CFReadStreamSetDispatchQueue((__bridge CFReadStreamRef) self.inputStream, self.queue);
CFWriteStreamSetDispatchQueue((__bridge CFWriteStreamRef) self.outputStream, self.queue);
In Swift, you can just directly call the functions:
CFReadStreamSetDispatchQueue(inputStream, streamQueue)
CFWriteStreamSetDispatchQueue(outputStream, streamQueue)
As you noted from the docs, when you have a run-loop-based API like NSStream, the general expectation is that all interaction with that object will occur on the thread that owns the run loop on which it's scheduled. I'm not sure there's really any benefit to mixing these two idioms (GCD and run loops) when it comes to working with NSStream.
Other than the main queue, GCD has no concept of thread-affinity, so unless the run loop you schedule the NSStream on happens to be the main thread run loop, there's no good way to use dispatch_async to schedule blocks for execution on that thread.
At the risk of stating the obvious, you should probably just use the standard methods for scheduling methods on other threads. -performSelector:onThread:withObject:waitUntilDone:modes: is the most obvious. If your confusion is that you want to work with blocks, it helps to know that heap-allocated blocks can be treated like Objective-C objects and implement the -invoke selector just like NSInvocations do. A trivial example relevant to your question might look like this:
#interface AppDelegate ()
{
NSThread* bgthread;
}
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Basic loop to get the background thread to run until you call -cancel on it
dispatch_block_t threadMain = [^{
NSThread* thread = [NSThread currentThread];
NSParameterAssert(![thread isMainThread]);
NSRunLoop* currentRunLoop = [NSRunLoop currentRunLoop];
NSPort* port = [NSPort port];
// If we dont register a mach port with the run loop, it will just exit immediately
[currentRunLoop addPort: port forMode: NSRunLoopCommonModes];
// Loop until the thread is cancelled.
while (!thread.cancelled)
{
[currentRunLoop runMode: NSDefaultRunLoopMode beforeDate: [NSDate distantFuture]];
}
[currentRunLoop removePort: port forMode: NSRunLoopCommonModes];
[port invalidate];
port = nil;
} copy];
// Start the thread
bgthread = [[NSThread alloc] initWithTarget: threadMain selector: #selector(invoke) object: nil];
[bgthread start];
// Fetch the runloop, so you can schedule an NSStream on it...
__block NSRunLoop* runloopForStream = nil;
dispatch_block_t getrunloop = [^{
runloopForStream = [NSRunLoop currentRunLoop];
} copy];
// Dispatch synchronously, so that runloopForStream is populated before we continue...
[getrunloop performSelector: #selector(invoke) onThread: bgthread withObject: nil waitUntilDone: YES];
// Schedule your stream, etc.
NSOutputStream* mystream = ...; // Your code here...
[mystream scheduleInRunLoop: runloopForStream forMode: NSDefaultRunLoopMode];
// Then later, when you want to write some data...
NSData* dataToWrite = [NSMutableData dataWithLength: 100];
dispatch_block_t doWrite = [^{
[mystream write: dataToWrite.bytes maxLength: dataToWrite.length];
} copy];
// Dispatch asynchronously to thread
[doWrite performSelector: #selector(invoke) onThread: bgthread withObject: nil waitUntilDone: NO];
}
#end
Note that the -copy of the blocks is necessary to get them copied to the heap, otherwise they'll be deallocated when the declaring method goes out of scope.

Objective C wait until an asynch task has been processed

In my code, I am running a local server (CocoaHTTPServer). When the server receives a request, it creates a thread and passes control to a certain method ( - (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path, perhaps irrelevant here).
I need to read a list of local assets and return the result. The API call ( [assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) ... ) is asynchronous.
Since the HTTPResponse needs to wait until the API call has finished, I have created a flag called _isProcessing , which I set before making the API call. After the call is finished, I am unsetting the flag and returning the HTTP request. The code to wait looks like:
// the API call is non-blocking. hence, wait in a loop until the command has finished
samCommand->isProcessing = YES;
while (samCommand->isProcessing) {
usleep(100*1000);
}
The API call calls a delegate method upon finishing its task as follows:
// to be called at the end of an asynch operation (eg: reading local asset list)
- (void) commandDidFinish {
// flag to open the lock
isProcessing = NO;
}
This works, but will perhaps require performance enhancements. How can I use anything (run-loop etc) here to improve upon the performance.
Edit following weichsel solution using dispatch_semaphore
Following weichsel's solution, I created a semaphore. The sequence of my code is:
CocoaHTTPServer receives a request and hence creates a new thread
It calls the static method of a Command class to execute the request
The Command class creates a new command Object calls another class (using reflection) which calls ALAsset APIs and passes the command Object to it
Upon returning, the ALAsset API call calls the delegate method of
the command class
I have hence embedded semaphores in appropriate locations. However, the semaphore's wait loop just doesnt end sometimes. The normal output should be:
2014-02-07 11:27:23:214 MM2Beta[7306:1103] HTTPServer: Started HTTP server on port 1978
2014-02-07 11:27:23:887 MM2Beta[7306:6303] created semaphore 0x1f890670->0x1f8950a0
2014-02-07 11:27:23:887 MM2Beta[7306:6303] calling execute with 0x1f890670
2014-02-07 11:27:23:887 MM2Beta[7306:6303] starting wait loop 0x1f890670->0x1f8950a0
2014-02-07 11:27:23:887 MM2Beta[7306:907] calling getAssetsList with delegate 0x1f890670
2014-02-07 11:27:24:108 MM2Beta[7306:907] calling delegate [0x1f890670 commandDidFinish]
2014-02-07 11:27:24:108 MM2Beta[7306:907] releasing semaphore 0x1f890670->0x1f8950a0
2014-02-07 11:27:24:109 MM2Beta[7306:6303] ending wait loop 0x1f890670->0x0
In every few runs, the last step ( ending wait loop 0x1f890670->0x0 doesnt occur). Hence, the wait loop never ends. Sometimes the code crashes too, exactly at the same point. Any clue what is wrong here.
My code is as follows:
#implementation SAMCommand {
NSData* resultData;
dispatch_semaphore_t semaphore; // a lock to establish whether the command has been processed
}
// construct the object, ensuring that the "command" field is present in the jsonString
+(NSData*) createAndExecuteCommandWithJSONParamsAs:(NSString *)jsonString {
SAMCommand* samCommand = [[SAMCommand alloc] init];
samCommand.commandParams = [jsonString dictionaryFromJSON];
if(COMPONENT==nil || COMMAND==nil){
DDLogError(#"command not found in %#",jsonString);
return nil;
}
samCommand->semaphore = dispatch_semaphore_create(0);
DDLogInfo(#"created semaphore %p->%p",samCommand,samCommand->semaphore);
// to execute a command contained in the jsonString, we use reflection.
DDLogInfo(#"calling execute with %p",samCommand);
[NSClassFromString(COMPONENT) performSelectorOnMainThread:NSSelectorFromString([NSString stringWithFormat:#"%#_%#_%#:",COMMAND,MEDIA_SOURCE,MEDIA_TYPE]) withObject:samCommand waitUntilDone:NO];
// the above calls are non-blocking. hence, wait in a loop until the command has finished
DDLogInfo(#"starting wait loop %p->%p",samCommand,samCommand->semaphore);
dispatch_semaphore_wait(samCommand->semaphore, DISPATCH_TIME_FOREVER);
DDLogInfo(#"ending wait loop %p->%p",samCommand,samCommand->semaphore);
DDLogInfo(#"");
// return the data
return samCommand->resultData;
}
// to be called at the end of an asynch operation (eg: reading local asset list)
- (void) commandDidFinish {
// flag to release the lock
DDLogInfo(#"releasing semaphore %p->%p",self,semaphore);
dispatch_semaphore_signal(semaphore);
semaphore = nil;
}
#end
I got it to work :)
Finally, what seems to work stably is creating the semaphore, and passing it to the ALAsset asynch API calls, and releasing it at the end of the call. Earlier, I was calling a delegate method of the class where I had created the semaphore, and the semaphore object was somehow getting releases. Unsure of what was happening there really.
You can use semaphore to block execution of the current queue until another one returns.
The basic pattern is:
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[assetsLibrary enumerateAssetsUsingBlock^(ALAsset *result, NSUInteger index, BOOL *stop):^{
...
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_release(semaphore);
You can find a full example of this method in Apple's MTAudioProcessingTap Xcode Project:
https://developer.apple.com/library/ios/samplecode/AudioTapProcessor
The relevant lines start at MYViewController.m:86
NSRunLoop has a method called runUntilDate: which should work for you with dates in near future like 1s ahead or so. That way you can replace your sleep call in the while loop for example with:
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeintervalSinveNow:1]

Releasing resources at end of NSRunLoop

I am trying to release resources allocated in daemon process at the end of it or if someone quits the process.
Lets say,
int main(int argc, const char * argv[])
{
Controller *controller = [[Controller alloc] init];
[controller allocateresources];
[[NSRunLoop currentRunLoop] run];
[controller release];
return 0;
}
Here Controller release will not be called. Quit [SIGTERM Signal] just terminates the runloop. How can I release resources allocated in class Controller at the end of application?
EDIT: I understand that system will claim resources back. The thing, I am trying to solve is something like cross process cooperative locks.
I don't think there is really a guarantee that you will return from the -run method. So you shouldn't rely on this to free the resources. There are other ways to do it. For example, a really low-level solution would be to implement an atexit handler
https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/atexit.3.html
and do the necessary freeing of the lock there.

How to run two multiple thread simultaneously in objective C?

I need to run two threads simultaneously, but I am not getting how to do so.
I start thread:
[NSThread detachNewThreadSelector:#selector(MyNewThread:) toTarget:[CMyClass class] withObject:nil];
-(void)MyNewThread:(id)param{
NSAutoreleasePool *Pool = [[NSAutoreleasePool alloc] init];
NSString *strSwitcher = #"myCommand";
const char * cstrSwitcher = [strSwitcher UTF8String];
system(cstrSwitcher);
[Pool release];
}
and some other system command I want to send on other thread. When I send one system command prompt changes.(e.g. myCommand> ).
Now when I start another thread then that command only works when previous thread was stopped.
Anyone can help me??
By taking into account the info in your comment on the OP, I assume you want to call system() from multiple thread simultaneously.
Unfortunately, that cannot work because when you call system(), your application waits for a signal that is sent as soon as the child process exits. Because signals don't know anything about the threads in your application, system() cannot be run from multiple threads simultaneously.
Thanks for JeremyP to point into the direction of NSTask in the comments!
The alternative is to use the NSTask.
NSTask uses fork() to create a child process and calls waitpid() in the parent and execve() (or one of its siblings) in the child process. Using the macros defined in <sys/wait.h>, the child's return value is retrieved after it finishes. This way, multiple child process can be launched without blocking other threads. You can either do all that yourself, or just use the simple NSTask class.
I would suggest not using Hungarian notation (Windows picked that up back in the Win32 days, but dropped it in .NET) as that just complicates things. rename 'Pool' to 'pool', and 'strSwitcher' to 'switcher'. Now, just call system([switcher UTF8String]); instead of that extra variable. On top of this, remove the NSAutoreleasePool, and use the new #autoreleasepool { } definition, enclosing your code in it. Here's how it looks now.
- (void)myNewThread:(id)param {
#autoreleasepool {
NSString *switcher = #"myCommand";
system([switcher UTF8String]);
}
}
And if you'd like to switch to NSTasks to be able to run multiple executables, here's how it goes: (I also changed the method a bit.)
- (void)executeTaskAtPath:(NSString *)path withArguments:(NSArray *)arguments {
#autoreleasepool {
NSTask *task = [launchedTaskWithLaunchPath:path arguments:arguments];
[task waitUntilExit]; // This blocks the thread.
}
}
To find out if the task was terminated successfully, register for a NSTaskDidTerminateNotification at [NSNotificationCenter defaultCenter].