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!
Related
thanks for viewing this post, it'd be great if you guys can help me out. I've been doing some objective-c and learned about the objective-c way of memory management, like making sure to call release whenever I own the object, when to call autorelease, etc. I also do not want to use ARC or the newly introduced GC because I like to manage my own memory, I plan to advance later on into iOS development, and I know it's a good practice to manage my own memory. But there's still one small detail that I seem to have hit a brick wall in. It has to do with sending objects the -retain message. I learned that sending the -retain message increments the reference count by 1. But would this be an appropriate time to send -retain? :
- (void) setName : (NSString* ) theName
{
// name is an instance variable of type NSString
[theName retain]; // Must release this
name = [theName copy]; // Must release this in dealloc
[theName release]; // decrement the reference count because of retain
}
Should I call retain here so that I own the argument temporarily and ensure it doesnt'
get released somehow before I get to use it?
Any help would be appreciated! Thanks!
No. You the object supplied as an argument to the method will generally be around until your method returns. You don't need the retain messages there. You copy the string here to keep it around after the method returns.
This is documented in Apple's Documentation on this page in the "Avoid Causing Deallocation of Objects You’re Using" Section. Specifically:
Cocoa’s ownership policy specifies that received objects should
typically remain valid throughout the scope of the calling method. It
should also be possible to return a received object from the current
scope without fear of it being released. It should not matter to your
application that the getter method of an object returns a cached
instance variable or a computed value. What matters is that the object
remains valid for the time you need it.
As an aside you really should consider using ARC. Its not good practise to manage your own memory. No matter how good one can be at managing their own memory the LLVM compiler is still better. Managing your own memory will lead to hard to troubleshoot issues caused only by yourself. It is an extra level of cognitive load that you really don't have to deal with and, when you finally let manual memory management go, you will breathe a sigh of relief at all the mental overhead you didn't even know was there.
I'm looking to use FSPathCopyObjectAsync and I'm failing. In order to get my head around the problem I've been looking for examples of it elsewhere and although I was experimenting with the slightly dated source code from Matt Long's tutorial over on Cocoa is my Girlfriend, I then found a bit more elaborate example in a project on github, as a category on NSFileManager. Since my project is running under ARC, I tried porting it, and succeeded only at the half of it.
In its current form, the actual copying works, yet the callback method MZCopyFSPathFileOperationStatusProc is never called. That callback method happens to be the sole reason for using asynchronous copying, otherwise one might as well run a synchronous one in the background. I'm assuming the reason for the callback not being called is that some object is incorrectly released by ARC, but there could be something else going on. I am holding on to the return object of the copyItemAsyncAtPath:toPath:destName:options:statusChangeInterval:error: method, so that can't be it, right?
Who can spot the error and explain why this category isn't generating any callbacks? Is it ARC? Is it something else?
Much obliged. EP.
P.S. For redundancy reasons, here is the gist: https://gist.github.com/6f3715753896ccf6fd35
Your delegate needs to be strongly referenced by something. NSFileManager will only hold a weak reference to it (as it should do), so if you don’t have a strong reference to it, your delegate will get released and the callbacks won’t be seen.
Have you considered using blocks for the callbacks? That would probably be preferable.
I'm so very sorry for the unclear title, but I can't explain it shortly.
I am basically wondering what happens if you use ARC and you have a method like this:
- (void)fooMethod:(NSURLRequest *)fooReq
{
NSURLConnection *fooConn = [NSURLConnection connectionWithRequest:fooReq delegate:self];
[fooConn start];
}
So fooConn goes out of scope at the end of the fooMethod, but will I still receive callbacks? In other words: because there aren't any more references, will it get dealloc'd (or something like that) immediately, or will it stay in memory and handle the request because the delegate is still set?
That totally depends on what NSURLConnection does behind the scenes. If the retain count drops to zero, then fooConn will be dealloc'ed still and one would assume no more callbacks would be made then.
Now, I think that NSURLConnection behind the scenes does get retained somewhere in the hierarchy of things so you would in fact receive callbacks. However with NSURLConnection I usually keep a strong reference to it lying around to be on the safe side. After all, you as the caller of it want to own it and you want to ensure that you will keep getting the delegate callbacks and not be at the mercy of whatever happens to it under the hood.
So, in short, if I were you I'd keep a strong reference to it to ensure you won't have to worry.
From the Apple docs:
- (id)initWithRequest:(NSURLRequest *)request delegate:(id < NSURLConnectionDelegate >)delegate startImmediately:(BOOL)startImmediately
The connection retains delegate. It releases delegate when the connection finishes loading, fails
fooConn is a local variable without any ownership qualifier so ARC will infer it as strong. Therefore ARC will retain the value returned by connectionWithRequest:delegate: when storing it into foxConn; and when exiting fooMethod: ARC will clean up by releasing fooConn.
That the delegate references the current instance will have no effect on this.
If you wish the NSURLConnection to exist after fooMethod: returns one way is to store it into an instance variable (which ARC also infers as strong, so no ownership qualifier required there either). If you do this when the class instance itself is no longer reference ARC will release the NSURLConnection.
I am wondering if I am using blocks as shown in the code below
__block Loader *loader = [[Loader alloc]initWithResourcePath:self.resourcePath];
[loader setCompletionHandler:^(NSArray *anArray){
self.answerArray=anArray;
[self reloadData];
}];
[loader getObjects];
My question is with regards to memory management. The analyzer tells me that there is a potential leak (since I did an alloc/init for my loader). How can I stop the leak here? I tried to release the loader at the end but that causes my app to stop functioning. Any advise is appreciated here
Several issues:
there is no reason for loader to be declared __block; you aren't re-assigning in the block and, thus, the __block is pointless.
the leak is because you alloc/init the loader, but never release it
do not name methods getSomething; the get prefix is reserved for methods that return stuff by reference. Just call it objects. If it is supposed to trigger the load, then call it load or performLoad.
If it is asynchronous, then getObjects is pointless. If synchronous, then the completion block is pointless.
If loader is to be used synchronously, release it at the end of the method. If it is asynchronous, then the completion block could release it. Note that the use of __block in this case is still pointless; while referring to loader in the completion block will create a retain cycle, it will be broken when you explicitly Block_release() the block in your loader (because you must have done a Block_copy() when setting the completion handler if it is to be used asynchronously in the first place).
If you plan to use loader outside of the function calling your block, it is highly possible that you need to store it in a ivar of your controller (I guess, it is a controller, but I don't know what kind of class owns the code you shows). Once you do that, you can release it in your dealloc.
The reasoning is that loader should live across several methods and runloop cycles, so a local variable will not do.
Otherwise, just release it at the end of the block, once you have done with it.
If this does not seem right to you, then possibly more code is needed.
I'm going to make some assumptions: 1) The completion handler (block) is used by method getObjects. 2) getObjects is asynchronous (it returns to the caller right away though it continues to process).
With these assumptions you can't send release after sending getObjects because getObjects is still using the completion handler.
Try sending a release or autorelease at the end of the completion handler. That should free loader provided reloadData is not also asynchronous.
I inherited an iPhone app at work and I'm new to Objective-C so I don't have my bearings just yet. I encountered code similar to this:
- (void) dealloc {
[[StaticObject sharedObject] showSomeDialog];
[super dealloc];
}
I know this is frowned upon in other languages. My spider sense is going crazy looking at that code.
Is this a common Objective-C idiom? Or do I have a crappy codebase to fix?
You should not put UI code in a -dealloc. General rule of thumb, only use -dealloc to clean up what you've done: release objects, remove observers, etc.
Consider what would happen if this object lived on a thread other than the main thread... now you'd have UI code running on the non-main thread, which is a bad thing.
You can do such thing for some debugging reasons. But I don't think you should ever do anything like this!
This means a dialog is prompted when an object is being deallocated. So if you need any mechanism to show a dialog at a certain time don't make it depended on an object being deallocated.
In the dealloc method you should really just release all objects retained by the deallocated object. And not doing some fancy application features.