Why Won't Asynchronous SOAP Web Services Calls Work - cocoa

I used WSMakeStubs (in the dev tools) to generate stub code for accessing a SOAP web service. The calls I make to the object just block currently. When I try to use the async calls, nothing happens and I'm sure it has to do with my understanding of run loops. I initialize an object and try to schedule it on a run loop like this:
BeginPartnerSession *call = [[BeginPartnerSession alloc] init];
[call setParameters:kPartnerID in_Password:kPartnerPassword];
[call setCallBack:self selector:#selector(sessionIDRequestDidFinish:)];
[call scheduleOnRunLoop:[NSRunLoop currentRunLoop] mode:NSDefaultRunLoopMode];
[call release];
The stub call for scheduling on the run loop looks like this:
- (void) scheduleOnRunLoop:(NSRunLoop*) runloop mode:(NSString*) mode
{
WSMethodInvocationScheduleWithRunLoop([self getRef], [runloop getCFRunLoop], (CFStringRef) mode);
}
The call to [self getRef] returns an invocation object that has set the callback. The callback is then supposed to call out to my target and selector, but it never hits that break point after calling schedule with run loop. What needs to change in the run loop scheduling to get it to work correctly?
Synchronous calls work fine, so I'm pretty sure it's not a server issue.

I finally broke this out into a separate project where I could isolate the problem. The async call worked just fine there which made the runloop suspect to me. Turns out the issue had to do with the fact that I am running this as a plugin for iPhoto. I simply changed the runloop mode so the call looked like this:
[call scheduleOnRunLoop:[NSRunLoop currentRunLoop] mode:NSRunLoopCommonModes];
Then the callback got called. Voila!

Related

NSOperationQueue and Dispatch Queue as replacement of NSThread performing a repetitive task

I have an application in which I am repetitively calling a method in background. I implemented this by following below steps:
created a background thread,
called the appropriate method on the created thread,
called sleep method on the thread, and
again called the previously invoked method.
Below is the code which I used:
- (void) applicationDidFinishLaunching:(NSNotification *)notification
[NSApplication detachDrawingThread:#selector(refreshUserIdPassword) toTarget:self withObject:nil];
}
-(void)refreshUserIdPassword
{
[self getAllUserIdsPasswordsContinousely];
[NSThread sleepForTimeInterval:180];
[self refreshUserIdPassword];
}
I have read that NSThread is not the best way to perform background task, and there are other classes provided in cocoa, such as - NSOperationQueue and GCD, which should be preferred over NSThread to perform an asynchronous task. So I am trying to implement the above specified functionality using the alternative classes.
Problem is - though I am able to perform an asynchronous task using
these classes, I am unable to perform a repetitive task (as in my
case) using these classes.
Can someone throw some light on this and guide me towards the correct direction?
I think you'll get a stack overflow (no pun intended) using the code you've posted. -refreshUserIdPassword recurses infinitely...
How about using GCD?
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
dispatch_source_t timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_timer(timerSource, dispatch_time(DISPATCH_TIME_NOW, 0), 180*NSEC_PER_SEC, 10*NSEC_PER_SEC);
dispatch_source_set_event_handler(timerSource, ^{
[self getAllUserIdsPasswordsContinuously];
});
dispatch_resume(timerSource);
self.timer = timerSource;
}
You're looking in the wrong place. As you say, NSOperationQueue isn't suited for this type of task. NSTimer is Cocoa's solution to this problem.
As the question also has a grand-central-dispatch tag:
If you need to run something in the background based on a regular interval, you could also use a dispatch_source timer.
Apple provides a very extensive example in the Concurrency Programing Guide.
If you don't need a background thread, you could use NSTimer (as paulbailey mentioned) or even more simple:
NSObject's performSelector:withObject:afterDelay:

Cocoa: NSTimer gdb when invalidating

I'm using some timers and want the user to be able to cancel it before it's done, or remove it from a view after it has finished. Both of these things are supposed to be handled by a cancelAction method. If the timer hasn't finished, an if statement in cancelAction tells the timers to invalidate, makes them nil and removes the view displaying the time left. This works perfectly. If the timers already finished, cancelAction only removes the view, and does not try to invalidate them. But this doesn't seem to work. If I cancel before they finish, everything works, If I cancel after they finished, it throws an exception saying unrecognized selector sent to instance. Both timer were made using the scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: method
The difference between calling before or after they finished, is that if they finished, this method is run.
- (void)timerFinished:(id)sender {
[timer invalidate];
timer = nil;
[timerLabelUpdater invalidate];
timerLabelUpdater = nil;
}
This is where it gets strange. If I just remove [timerLaberUpdater invalidate] the method gets called and it gets removed. I don't want to remove that line because that timer counts down the time left and updates the view with the time left. If I don't invalidate it, it keeps counting down to the negatives, plus it takes up memory.
I sincerely have no idea why removing that line changes anything, both timers were called in the same way, and if I remove the other line, it still doesn't work, ONLY by removing that instruction does anything change.
I get EXC BAD ACCESS in gdb, which I think means the selector is sent to an instance that was released.
Thanks for the help.
if([timerLabelUpdater isValid])
[timerLabelUpdater invalidate];

How to implement custom NSApplication terminate: behavior in Cocoa?

I'm attempting to implement custom termination behavior in a Cocoa application. Normally when my application exits gracefully, it performs final-runtime database cleanup and then exits. This occurs inside AppDelegate (delegate of NSApplication) whenever [NSApp terminate:aSender] is called:
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
// database cleanup...
return NSTerminateNow;
}
If an error occurs during runtime (e.g. the database file was deleted), I present the error to the user, and give them the option to Recover (put the file back and try again), or to Quit. If Quit is selected, I want to exit the app skipping database cleanup all-together since it's no longer possible. In essence, I'd like something like this:
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
BOOL gracefulTermination = ...;
if (gracefulTermination == YES)
{
// Database cleanup....
}
return NSTerminateNow;
}
The problem, of course, is getting the value for gracefulTermination.
Is there a way to pass a custom variable to NSApp when terminate: is called, such as an infoDict, and then receive it inside applicationShouldTerminate:?
If not, is there a better way to accomplish custom termination behavior?
As far as I know, when terminate: is called by some other object, this happens:
[NSApp terminate:self]; is called by foo (a.k.a. self).
NSApp sends its delegate: [aDelegate applicationShouldTerminate:self]; (self is NSApp, not foo).
aDelegate receives the message and executes applicationShouldTerminate: if implemented.
foo appears to disappear somewhere, and by the time aDelegate gets the message, it's gone for good and only NSApp appears as sender. This prevents me from passing an infoDict inside of foo, or just a plain infoDict, to aDelegate containing custom terminate: behavior.
I am aware that it's possible to exit without using [NSApp terminate:...] with something like exit(). Though from what I've read this is frowned down upon since it's not kosher for Cocoa. Plus it would also prevent any other cleanup operations from occurring inside applicationShouldTerminate:, operations which shouldn't be skipped even during a non-graceful exit.
The ideal solution would be to structure your app in such a way that the app delegate can tell whether it's allowed to terminate.
Assuming it isn't possible for your application delegate to access this information any other way (say, which object triggered termination affects whether it can happen), this seems like the simplest solution: Subclass NSApplication, give it a terminationInfo property and override terminate: to set this property and call super.

How to create a run loop that only listens to performSelector:onThread: and GUI events?

I want to create a separate thread that runs its own window. Frankly, the documentation does not make sense to me.
So I create an NSThread with a main function. I start the thread, create an NSAutoreleasePool, and run the run loop:
// Global:
BOOL shouldKeepRunning = YES;
- (void)threadMain {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
// Load a nib file, set up its controllers etc.
while (shouldKeepRunning) {
NSAutoreleasePool *loopPool = [NSAutoreleasePool new];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
[loopPool drain];
}
[pool drain];
}
But since there is no registered port or observer, runUntilDate: exits immediately and CPU utilization goes to 100%.
All thread communication is handled by calls to performSelector:onThread:withObject:waitUntilDone:. Clearly, I am not using the API correctly. So, what am I doing wrong?
Much of AppKit is not thread-safe and will not work properly (1) when manipulated outside the main thread. You will find only pain and misery trying to ignore this fact.
What are you really trying to do that requires a different thread for this window? Are you merely trying to keep a responsive UI? If so, there're much better ways of doing it. See NSOperation / NSOperationQueue (where "units of work" and "queues" are the focus, not "this window shall run on this thread, etc.").
I'd recommend restating your question with your specific goal detailed clearly.
(1) For some classes, it takes a lot of careful work. For others, they are quite firmly off limits.

NSNotification and Multithreading

I'm trying to get the notification NSTaskDidTerminateNotification in my multithreaded app but I can't get it working. It does seem to work when I tested it on a single threaded app. In init I have [[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(taskDidEnd:) name: NSTaskDidTerminateNotification object: myTask]; and I'm quite sure that it gets called because other objects (like myTask) are being initiated there. And the taskDidEnd: method is defined as
- (void)taskDidEnd: (NSNotification *)aNotification
{
NSLog(#"Task succeeded.");
}
And in dealloc the observer gets removed.
This all happens in an object which is initiated inside a separate thread and I would like to receive that notification inside the same object.
Did you run the run loop on that thread? If not, NSTask won't notice that the task ended (or the task won't have ended yet) and won't post the notification.

Resources