I want to make a call to my server fetches some data every 30 data that should be used to display annotation on a MKMapView. I have researched about it, but I'm still unsure which to use?
Some guidance please. :)
I'd recommend using an NSTimer, perform a selector and in your selector launch an NSOperation to perform the download. Use KVO to observe for isFinished or use delegates with your NSOperation :)
Related
I am wrapping AVAudioPlayer with a very simple class that allows me to specify and url and immediately play it and then call a completion block, like this:
[AudioPlayer playAudioWithURL:url
completionBlock:^{
//finished playing
}];
Reason why I wrote this is because it's very easy, simple. No need to implement delegate, etc...Problem is, this won't work. Doing this in a function will obviously allocate it on stack and it will be de-allocated soon, causing the sound to stop playing.
So, what's the best way to implement this kind of wrapper, to keep a reference around until the sound is finished playing?
Thanks
You should not have any problem. What makes you think that it "will obviously allocate it on stack and it will be de-allocated soon"? Have you tried it? You obviously don't have a good understanding of how memory management in Objective-C works.
In your implementation of playAudioWithURL:urlcompletionBlock:, you will inevitably have some kind of asynchronous dispatch. This dispatch will inevitably have to retain your audio player object, in order to have it play stuff. So no, it won't get deallocated, unless you are doing something wrong.
I'm not sure how possible this would be using ARC since you can't really manage the retain/release cycles. I've done something similar to this using a wrapper for UIAlertView, and what I have done -- not using ARC, of course -- would be to simply to call [self retain] on the wrapper class during the show method and then, when the delegate method is called on the wrapper, call the completionBlock and then [self release]. This guarantees (so long as you're following retain/release rules!) that the wrapper class will be alive at least until the callback is called and, in the usual case, the wrapper will suicide itself once it's done doing its job. Again, since you can't manage retain cycles using ARC, I'm not sure if this will work.
The alternative for you might be to look into simply subclassing AVAudioPlayer or creating a category version of it, setting the delegate to itself. That may be able to keep it alive long enough for it to persist until the full sound plays -- though I am a bit fuzzy on how ARC works.
Best of luck!
I'm creating a service class in Objective-C that communicates with a HTTP server. I'm familiar with NSURLConnection and the associated classes to make an asynchronous request to a server. So far, I've used self as the delegate, responding to the four delegate methods (didReceiveResponse, didReceiveData etc.) required for the call.
The service class I'm building must be able to handle several requests at once, and respond differently to each. I'm looking for a way to achieve this, without an endless switch or if-elseif in the connectionDidFinishLoading method.
I have the idea to create a delegate class that implements the four methods described above, and give that to the NSURLConnection object to talk to. However, I want to notify the parent class when the connection finishes loading and then fire another method within the parent class. And of course, the delegate doesn't know which method this is - it could be anything.
How to proceed? Is there a way to set a selector for the delegate class, and fire that selector (which is a method) when the request is finished? How do I do such a thing?
(Creating a delegate for my delegate, and then calling a superclass method could do the trick, but I'm really looking into wildcard methods, such as a selector.)
Any help is greatly appreciated!
Regards,
Reinder
I would pass a block (^{ ... })to the delegate that it should call when the connection has finished.
You have three options:
Using a block callback
Using notifications
Using a delegate, as you already suggested.
All three are perfectly valid, but with various advantages/disadvantages. Learn them all, then decide which to use in each scenario. :-)
Often more than one solution will be chosen. For example many of Apple's classes implement a delegate method and send a notification for the same event.
UIView has a setNeedsDisplay method that one can call several times within the same event loop, safe in the knowledge that the redrawing work will happen soon, and only the once.
Is there a generic mechanism for this sort of behaviour Cocoa? A way of of saying, "Queue a selector as many times as you like, when it's time, the selector will run once & clear the queue."
I know I could do this with some kind of state tracking in my target, or with an NSOperationQueue. I'm just wondering if there's a lightweight approach I've missed.
(Of course, the answer may be, "No".)
setNeedsDisplay is not a good example of what you're describing, since it actually does run every time you call it. It just sets a flag. But the question is good.
One solution is to use NSNotificationQueue with NSNotificationCoalescingOnName.
Another solution is to build a trampoline to do the coalescing yourself. I don't have a really good blog reference for trampolines, but here's an example of one (LSTrampoline). It's not that hard to build this if you want to coalesce the messages over a period of time. I once built a trampoline with a forwardInvocation: similar to this:
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation setTarget:self.target];
[invocation retainArguments];
[self.timer invalidate];
self.timer = [NSTimer scheduledTimerWithTimeInterval:self.timeout invocation:invocation repeats:NO];
}
This actually coalesces all messages to the object over the time period (not just matching messages). That's all I needed for the particular problem. But you could expand on this to keep track of which selectors are being coalesced, and check your invocations to see if they match "sufficiently."
To get this to run on the next event loop, just set timeout to 0.
I keep meaning to blog about trampolines. Required shilling: My upcoming book covers trampolines in Chapter 4 and Chapter 20.
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:#selector(doTheThing:)
object:someObject];
[self performSelector:#selector(doTheThing:)
withObject:someObject
afterDelay:0];
This is not exactly how UIView is doing it because setNeedsDisplay simply sets a flag and the internal UIView mechanism makes sure to call drawRect: after setting up the drawing environment, but this is a generic way and doesn't require any special state tracking in your class.
Sorry for noobness-level of the question.
I saw this answer, where it says
Add something like this to your NSURLConnection delegate
However, the method in question, sendSynchronousRequest:returningResponse:error:, is a class method. If I understand delegate methods correctly, they use a delegate which is specified when the NSURLConnection object is initiated.
So, if I have no instance of the class, a delegate can't be used. Did I understand correctly?
Yes, you are correct. In Cocoa, assigning a delegate requires an instance. In the case of NSURLConnection, its delegate is supposed to be used when making an asynchronous request that is initiated with -initWithRequest:delegate: or +connectionWithRequest:delegate:
Since classes are also objects it could be conceived that they also could have delegates. However, since there is no concept of class variables in Objective-C, a class would have nowhere to store its delegate (it could use a standard C variable in its .m file, though). Anyway, this concept is not used in Cocoa.
Yes delegates are used for handling events when you send your request asynchronously.
While sending synchronous request using +sendSynchronousRequest:returningResponse:error: method delegates are not used - you only get the resulting data and (optionally) server response and error and not aware about intermediate loading events (and remember that calling thread is also blocked while connection is in progress).
I have a Cocoa interface. When I press a button I want to process some data, but I want to keep using the interface while it's working. I guess the only solution is NSThread. Now will there be a locking mechanism preventing me from returning from an IBAction method if it spawns a thread?
No, there is no locking mechanism. The new thread will start and the current thread will continue. You may want to look at performSelectorInBackground:withObject: and possibly NSOperation in addition to NSThread.
Take a look at NSOperation. NSOperation is one of the few cocoa classes which must be subclassed for it to be useful. By adding a delegate property to your NSOperation subclass you can get notified when the operation completes. Also, you can add a userInfo property to allow the operation to pass back arbitary data to the delegate
#implementation MyNSOperationSubclass
-(void)main
{
//do operation here
//operationResult is used to report back to the delegate. operationResult could include a userInfo key so that the delegate can have some data passed back, or an error key to indicate success of the operation.
NSDictionary *operationResult;
//Some checks to ensure that the delegate implements operationHasFinished: should be added.
//waitUntilDone: YES locks the main thread
[[self delegate] performSelectorOnMainThread:#selector(operationHasFinished:) withObject:operationResult waitUntilDone: YES];
}
#end
Don't know much about cocoa, but starting a new thread for processing something in background while keeping the UI thread free for taking user inputs(and thus preventing UI from freezing) is the most widely used technique for the problem you have mentioned.Both threads will work together (concurrently) and the programmer has to take care of the synchronization issues if any.You should go ahead with the technique without doubt.
Thanks,
Sourabh