EXC_BAD_ACCESS crash when stopping MPMoviePlayerController - ios

I am having some EXC_BAD_ACCESS problems whilst trying to stop a video that is being played through MPMoviePlayerController. Here is some code:
Video Class:
#interface MyVideo()
#property (nonatomic, strong) MPMoviePlayerController * videoController
#end
#implementation MyVideo
#synthesize videoController;
- (MyVideo*) initIntoView: (UIView*) view withContent (NSDictionary*) contentDict {
self=[super init];
NSString * rawUrl=[[NSString alloc] initWithFormat:#"http://.../%#.mp4", [contentDict objectForKey:#"filename"]];
NSURL * videoUrl=[[NSURL alloc] initWithString:rawUrl];
videoController = [[MPMoviePlayerController alloc] initWithContentURL:videoUrl];
videoController.movieSourceType=MPMovieSourceTypeFile;
videoController.view.frame = viewRef.bounds;
[videoController.view setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
videoController.controlStyle=MPMovieControlStyleNone;
[view addSubview:videoController.view];
return self;
}
/* other code */
- (void) stop {
NSLog(#"video stop");
[videoController stop];
}
#end
This MyVideo class is a property within my AppDelegate class, like so:
#property (nonatomic, strong) MyVideo video;
A line in my AppDelegate class fires off the public method stop of this MyVideo class, like so:
[video stop];
This usually works fine. But occasionally I get an EXC_BAD_ACCESS error on the line with [videoController stop]. The line before it, the one with NSLog on it, outputs to the console as expected.
This crash happens while the video that has been loaded into the videoController is still playing. But it does not happen every time.
Can anyone suggest why this crash is happening? I suspect its because videoController is no longer in memory, despite it being strong and still in use.
Am I right in thinking there is absolutely no way of testing the videoController to see if it is still in memory?
Am I right in thinking there is absolutely no way of forcing videoController to stay in memory while it is being used to play a video?
So instead of trying to stop the video and shut down the MyVideo class properly when I dont want to play the video anymore, I am now thinking of just setting the MyVideo class to nil, and let ARC deal with stopping the video and clearing it from memory. Is this the right way of doing this? Would there be any disadvantages to this?
Are there any other solutions to this problem that I am missing?

With EXC_BAD_ACCESS my first port of call is to enable Zombie Objects in my Debug Scheme.
This should give you an idea of what object is causing the EXC_BAD_ACCESS. Just to double check it is your videoController.
When does your stop function get called on MyVideo
Is the crash on specific devices, iPad iPod, does it occur on specific os's iOS 6,7
Is it the same video file?
It cant randomly break there must be some pattern that is causing the EXC_BAD_ACCESS

I may be wrong but I have a feeling that its a threading issue. I suspect the thread calling the [myVideo stop] function is not aware of the videoController(probably initialised on the main thread). Try calling the [videoController stop] within the main thread by using the following:
dispatch_async(dispatch_get_main_queue(), ^{
[videoController stop];
});
Do let me know if this works!

Related

How to access MPVolumeView in my app delegate applicationWillTerminate?

EDIT: It is appearing that there may not be ANY possible way to, on app termination only, set the device volume back to the level it was when an app started. To me this is a possible oversight on the part of Apple. Why wouldn't Apple want my app to be a good camper that leaves their campsite the way they found it, there must be a way, please help... I tried to get an answer to this broader question with another topic but it was closed as a duplicate, please go there and vote to re-open it :)
When my app terminates, I want to set the system volume back to the same volume it was when my app started (Edit: and not change the volume when the app enters the background).
I am attempting to do that with MPVolumeView as the mechanism to set the devices volume. From what I have researched, that seems to be the only way to set the devices volume programmatically. If there is another way, please suggest it.
So, when I launch my app I save the system volume as an external variable 'appStartVol' in my AppDelegate.m.
I let the user change the volume during app usage with MPVolumeView.
Then I try to set the system volume back to the appStartVol in the AppDelegate.m files' applicationWillTerminate. EDIT: applicationWillTerminate is called when a user dismisses apps from their recents list. I do this all the time and leave regularly used apps in recents so I don't have to scroll through 9 pages of icons to find them. So, there is a reason to do what I am asking, in that function.
I use this approach for screen brightness but can not seem to do it for volume.
I am having trouble because I do not seem to be able to get access to my storyboard MPVolumeView in AppDelegate.m applicationWillTerminate and I can not seem to make a local MPVolumeView work in AppDelegate.m applicationWillTerminate.
If I use a UIApplicationWillTerminateNotification notification in my view controller, I still run into the same problems in the notification event since the storyboard MPVolumeView also seems not accessible from that event.
EDIT: This is the reason that using code in applicationDidEnterBackground does not meet my needs: I want my users to be able to use my music player at the volume they have manually chosen in my app even when they decide to bring another app into focus. I believe that this is what the users would naturally assume would happen. For instance, why would the volume change if I want to use the calculator? I also want to believe that the natural assumption for a user would be that the volume should pop back to pre-app volume if the app is dismissed. Using applicationDidEnterBackground would make the app go to pre-app volume both when the app goes into background AND when it terminates, this is not acceptable.
ATTEMPT 1: Here is my code in my AppDelegate.m applicationWillTerminate:
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
NSLog(#"=== App is terminating ===");
UIScreen.mainScreen.brightness = brightnessORG;
NSLog(#"=== Screen brightness back to pre-app level of %f ===", brightnessORG);
UISlider *volumeViewSlider;
for (UIView *view in [_mpVolumeViewParentView subviews]){
if ([view.class.description isEqualToString:#"MPVolumeSlider"]){
volumeViewSlider = (UISlider*)view;
volumeViewSlider.value = appStartVol;
break;
}
}
}
ATTEMPT 1: Here is my AppDelegate.h:
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
extern CGFloat brightnessORG;
extern float appStartVol;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
MPVolumeView *_mpVolumeViewParentView;
}
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, retain) IBOutlet MPVolumeView *mpVolumeViewParentView;
#end
Re. ATTEMPT 1: Although this code runs without error, it does not set the volume back to appStartVol since there are no views in the app delegates [_mpVolumeViewParentView subviews]. I am obviously not accessing the mpVolumeViewParentView that is in my storyboard.
ATTEMPT 2: Lets see if I can just add a local MPVolumeView in AppDelegate.m applicationWillTerminate:
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
NSLog(#"=== App is terminating ===");
UIScreen.mainScreen.brightness = brightnessORG;
NSLog(#"=== Screen brightness back to pre-app level of %f ===", brightnessORG);
MPVolumeView *volumeView = [ [MPVolumeView alloc] init];
UISlider *volumeViewSlider;
volumeViewSlider = (UISlider*)volumeView;
volumeViewSlider.value = appStartVol;
}
Re. ATTEMPT 2: Runs with error = 'Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MPVolumeView setValue:]: unrecognized selector sent to instance'
But I have tried :), as you can see I am an objective-c newbie...
Any help would be appreciated :)
ATTEMPT 3: Try subviews in local MPVolumeView in applicationWillTerminate:
MPVolumeView *_mpVolumeViewParentView = [ [MPVolumeView alloc] init];
MPVolumeView *volumeView = [ [MPVolumeView alloc] init];
[_mpVolumeViewParentView addSubview:volumeView];
UISlider *volumeViewSlider;
for (UIView *view in [_mpVolumeViewParentView subviews]){
if ([view.class.description isEqualToString:#"MPVolumeSlider"]){
volumeViewSlider = (UISlider*)volumeView;
volumeViewSlider.value = appStartVol;
break;
}
}
Re. ATTEMPT 3: Runs with error at for loop initiation: 'Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MPVolumeView setValue:]: unrecognized selector sent to instance'
ATTEMPT 4: After adding AVfoundation framework to the project, I added this to my AppDelegate.m:
#import <AVFoundation/AVFoundation.h>
And I put these two lines to AppDelegate.m applicationWillTerminate:
AVAudioPlayer* wavplayer = [[AVAudioPlayer alloc] init];
wavplayer.volume = appStartVol;
Re. ATTEMPT 4: Runs with error at 'wavplayer.volume= appStartVol;': 'Thread 1: EXC_BAD_ACCESS (code=1, address=0x48)' , darn......
First, you are trying something that probably can't work - you are casting MPVolumeView to UISlider and then try to use UISlider's setValue: method. But your object is still MPVolumeView and support that method. So this can't work not because you are using it in wrong place, but in never works.
Also - appWillTerminate is not sufficient, as it's called only in one specific case. If app goes to background first, and then killed - the willTerminate is never called.
I assume you were trying to de something like described here iOS 9: How to change volume programmatically without showing system sound bar popup? - but you should just do the same - so find the UISlider within subviews, instead of casting the whole thing to it.
Edit:
#implementation AppDelegate
{
MPVolumeView* mv;
UISlider* slider;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
slider.value = 1;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
mv = [MPVolumeView new];
for (UIView *view in [mv subviews]){
if ([view.class.description isEqualToString:#"MPVolumeSlider"]){
slider = ((UISlider*)view);
break;
}
}
}
#end
that's the sample code I used. Using in terminate unfortunately didn't work, so that's the most that I see that can be done (I also think it's the more correct way than using terminate, as it's not always called).
Remember this can stop working at any time, or even be rejected when submitted to the AppStore.

Error 849 in livestreaming application on iOS

I am working on the livestream feature for an iOS application. I have used an AVPlayerViewController contained within a ContainerView to display the video.
And here is the associated code for the ViewController
#interface ViewController ()
#property MPMoviePlayerController* streamPlayer;
#property BOOL isPlaying;
#end
AVPlayerViewController *streamPlayer;
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.isPlaying = NO;
NSURL *streamURL = [NSURL URLWithString:#"http://vevoplaylist-live.hls.adaptive.level3.net/vevo/ch1/appleman.m3u8"];
streamPlayer = [[ UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"StreamPlayer" ];
streamPlayer.player = [ AVPlayer playerWithURL:streamURL ];
}
- (IBAction)playVideo:(id)sender{
if ( !self.isPlaying ){
[ streamPlayer.player play ];
[self.button setTitle:#"Stop" forState:UIControlStateNormal ];
self.isPlaying = YES;
} else {
[ streamPlayer.player pause ];
[self.button setTitle:#"Play" forState:UIControlStateNormal ];
self.isPlaying = NO;
}
}
(You can ignore the isPlaying variable. It's just to see what I can control)
The stream starts and works fine for a few minutes before it stops/buffers(i think) for a few seconds and an error show up:
ERROR: 849: AudioQueue: request to trim 4291961269 + 0 = 4291961269 frames from buffer containing 21504 frames
The stream continues after this but there is no audio.
Occasionally there is a second or two of audio but immediately the error showing up again and the stream continues in silence. (Something I'm glad of when a Pitbull video is being broadcast. )
If I pause the stream and then play it, the audio returns for a few minutes and then goes off again.
I have searched for this error but have not found anything to help me fix this. Being relatively new to iOS and HLS, I don't have any ideas as to what the issue could be but if I had to guess I'd say that it's an issue with synchronization of audio and video.
Any and all help is appreciated.
There are two issues in your code that stand out right away.
You have TWO streamPlayer variables.
The AVPlayerViewController variable should be a Global Variable
By putting your AVPlayerViewController property declaration inside your Interface Extension as a global variable the error should be resolved.
The code would look something like this:
#interface ViewController ()
#property (nonatomic) MPMoviePlayerController *mpStreamPlayer;
#property (nonatomic) AVPlayerViewController *avStreamPlayer;
#property (nonatomic) BOOL isPlaying;
#end
#implementation ViewController
- (void)viewDidLoad ... // continue as expected
The reason I am assuming it will be resolved is because of this similar problem a member of the community is experiencing with the Error 849 (their codebase is SWIFT) and the answer working answer.
this is possibly related to the iOS 9 bugs, paste your m3u8 into the Safari, you could experience the same problem down the road (intermediate audio interrupt, audio/video out of sync), there is nothing you can do with your code.
see some report here, and Apple engineer ask to file a bug report.

How to release the private property in iOS 7 using ARC

I am developing a project on iOS 7 using ARC, I want to release a private property when the viewController is released
Here is the TestViewController that is presented as a modal view controller, setting a value to the private property testAVPlayer in viewDidLoad:
//TestViewController.m
#import "TestAVPlayer.h"
#interface TestViewController () {
TestAVPlayer *testAVPlayer;
}
#end
- (void)viewDidLoad
{
[self setupPlayer];
}
- (void)setupPlayer {
AVPlayerItem *item = [AVPlayerItem playerItemWithURL:[[NSBundle mainBundle] URLForResource:#"music" withExtension:#"mp3"]];
testAVPlayer = [TestAVPlayer playerWithPlayerItem:item];
[testAVPlayer setActionAtItemEnd:AVPlayerActionAtItemEndNone];
[testAVPlayer play];
}
- (void)dealloc {
NSLog(#"dealloc TestViewController: %#", self);
}
TestAVPlayer is a subclass of AVPlayer, I put a NSLog into the dealloc
// TestAVPlayer.h
#import <AVFoundation/AVFoundation.h>
#interface TestAVPlayer : AVPlayer
#end
// TestAVPlayer.m
#import "TestAVPlayer.h"
#implementation TestAVPlayer
- (void)dealloc {
NSLog(#"dealloc testAVPlayer: %#", self);
}
#end
When TestViewController is dismissed, the testAVPlayer seems never be released, I see the "dealloc TestViewController", but there is no "dealloc testAVPlayer" in console log
I tried your code, the problem is that even if you call [TestAVPlayer playerWithPlayerItem:item] the TestAVPlayer class doesn't have such method, so it will call playerWithPlayerItem: function from the AVPlayer base class, which will return an instance of the AVPlayer class instead of the TestAVPlayer class. The compiler won't give you any warning because the playerWithPlayerItem: method returns a type of id. If you check this with the debugger you'll see that the private variable's type is not TestAVPlayer:
The dealloc of the TestAVPlayer will never be called as no such object was created.
The AVPlayer instance gets deallocated when the TestViewController is deallocated. You can check this by using Instruments or simply adding a Symbolic Breakpoint to [AVPlayer dealloc].
Select the Breakpoint Navigator and click on the + button and add a Symbolic Breakpoint.
Write [AVPLayer dealloc] to the Symbol field and press Enter. When you run the application and the TestViewController gets deallocated then you will see that the breakpoint will be hit, hence the AVPlayer really gets deallocated.
You are using a class factory method to initialize your object, which means that you do not own the testAVPlayer object and thus are not responsible for releasing it.
See Class Factory Methods from the Concepts in Objective-C Programming guide for more details.
If you indeed want to own and control the lifetime of this object, use the following initializer:
testAVPlayer = [[TestAVPlayer alloc] initWithPlayerItem:item];
and your dealloc method will be called.
testAVPlayer = [AVPlayer playerWithPlayerItem:playerItem];
You are using AVPlayer, not your TestAVPlayer.
Try implementing - viewDidUnload then nil the testAVPlayer:
- (void) viewDidUnload
{
[super viewDidUnload];
testAVPlayer = nil;
}
Although you are calling it as [TestAVPlayer playerWithPlayerItem:item], you are really getting back an instance of AVPlayer, not TestAVPlayer. In fact, the AVPlayer instance you created really IS getting deallocated. You won't be able to see your log in dealloc because an instance of that class is never created.
As suggested by another, replace [TestAVPlayer playerWithPlayerItem:item] with [[TestAVPlayer alloc] initWithPlayerItem:item]; and you should start seeing your logs.

Object deallocates immediately after it has been initialized

I am trying to make a class that plays YouTube videos, but I am having several problems with it.
Here is my class that handles YouTube videos:
// this is the only property declared in the .h file:
#property (strong, nonatomic) UIView * view
// the rest of this is the .m file:
#import "MyYouTube.h"
#interface MyYouTube()
#property (strong, nonatomic) NSDictionary * contentData;
#property (strong, nonatomic) UIWebView * webView;
#property (nonatomic) int videoOffset;
#end
#implementation MyYouTube
#synthesize view,contentData,webView,videoOffset;
- (MyYouTube*) initIntoView: (UIView*) passedView withContent: (NSDictionary*) contentDict {
NSLog(#"YOUTUBE: begin init");
self=[super init];
videoOffset=0;
view=[[UIView alloc] initWithFrame:passedView.bounds];
[view setBackgroundColor:[UIColor blackColor]];
[view setAutoresizesSubviews:YES];
[view setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
contentData=contentDict;
NSString * compiledUrl=[[NSString alloc] initWithFormat:#"http://_xxx_.com/app/youtube.php?yt=%#",[contentData objectForKey:#"cnloc"]];
NSURL * url=[[NSURL alloc] initWithString:compiledUrl];
NSURLRequest * request=[[NSURLRequest alloc] initWithURL:url];
webView=[[UIWebView alloc] initWithFrame:passedView.bounds];
[webView loadRequest:request];
[webView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[[webView scrollView] setScrollEnabled:NO];
[[webView scrollView] setBounces:NO];
[webView setMediaPlaybackRequiresUserAction:NO];
[webView setDelegate:self];
NSLog(#"YOUTUBE: self: %#",self);
NSLog(#"YOUTUBE: delegate: %#",webView.delegate);
[view addSubview:webView];
NSLog(#"YOUTUBE: end init");
return self;
}
-(void)webViewDidFinishLoad:(UIWebView*)myWebView {
NSLog(#"YOUTUBE: send play command");
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:#"playVideo(%d)", videoOffset]];
}
- (void) dealloc {
NSLog(#"YOUTUBE: dealloc");
}
#end
Here is the code that calls this class (this code is located in the appDelegate):
NSLog(#"about to load youtube");
ytObj=[[MyYouTube alloc] initIntoView:mainView withContent:cn];
NSLog(#"loaded youtube");
[mainView addSubview:[ytObj view]];
FYI mainView and ytObj are declared as this:
#property (nonatomic,strong) UIView * mainView;
#property (nonatomic,strong) MyYouTube * ytObj;
When this code is run, the app crashes and I get this in the console:
about to load youtube
YOUTUBE: begin init
YOUTUBE: self: <MyYouTube: 0x16503d40>
YOUTUBE: delegate: <MyYouTube: 0x16503d40>
YOUTUBE: end init
YOUTUBE: dealloc
loaded youtube
*** -[MyYouTube respondsToSelector:]: message sent to deallocated instance 0x166f19f0
If I set the UIWebView delegate to nil then the app doesn't crash, but, as expected, the YouTube video doesn't autoplay.
Can anyone explain to me:
Why does the object deallocates immediately after it has been
initialized?
Why the respondsToSelector: message is sent to an
instance other than the MyYouTube one?
How can I get the YouTube video to autoplay without the app crashing?
Many thanks.
EDIT
Totally my bad - ytObj is a strong property - I forgot to mention this. Ive added the code to reflect this.
EDIT 2
Ive added a breakpoint on the dealloc method, and this is the call stack:
0 -[MyYouTube dealloc]
1 objc-object::sidetable_release(bool)
2 -[MyAppDelegate playYouTube:]
The last entry here (playYouTube:) is the method that contains the code in my app delegate that is in the original post above. So, one more question:
What is objc-object::sidetable_release(bool), what does it do, and why is it releasing my YouTube object?
Why does the object deallocates immediately after it has been initialised?
Because nothing owns it.
You set it as the delegate to a view, but the delegate property of UIWebView is an assign property. The view doesn't take ownership of its delegate. This means that when ytObj goes out of scope (possibly before, depending on optimisation) nothing owns it, so it goes away.
EDIT
You also need to make sure that when a ytObj is deallocated, you set the delegate property of any views it is still a delegate of to nil. Otherwise the views will continue to try to send messages to the deallocated object.
How can I get the YouTube video to autoplay without the app crashing?
You need to make sure that ytObj lasts as long as the view of which it is the delegate and when it is deallocated, it's view's delegate is set to nil.
Another minor issue. Your -init function should test that self is not nil after invoking self = [super init]. It shouldn't run any of the rest of the initialisation code if self is nil.
1) (my first answer to your first question, before your edit)
This is happening because you're using ARC (automated reference counting) and you are not keeping your local "ytObj" variable ((which is NOT the "self.ytObj" property) around in the object that you created it in. As soon as the function that created the local "ytObj" variable finishes up and returns, the object is automagically dealloc'd.
Change this:
ytObj=[[MyYouTube alloc] initIntoView:mainView withContent:cn];
to this:
self.ytObj=[[MyYouTube alloc] initIntoView:mainView withContent:cn];
And for "best practices", I'd also suggest not doing so much work and/or code in your application delegate. App delegates are meant to receive application specific messages (like "application is suspending", "application is becoming active again", etc.), and you should do stuff like this in a subclassed view controller.
2)
The "respondsToSelector:" error you're seeing is because your YouTube object has been automagically dealloc'd. If it were still living, you wouldn't see that message.
3)
If you search here on Stackoverflow, you'll find other questions and answers that explain how to do autoplaying... like how about this one?
The object ytObj since is not strong referenced anywhere, it exists only inside the scope where is defined. Delegates most of time are declared as weak properties. None is keeping a strong reference to this object, thus ARC releases it.
Create a strong properties to ytObj and you will see everything working fine.

UIImagePickerController: [PLImageScrollView release]: message sent to deallocated instance

I am writing an iOS6 app using Cocos2D with ARC turned on (Cocos is linked as a static library, not under ARC). I am able to present the camera using the following code:
cameraController = [[UIImagePickerController alloc] init];
// set other properties of camera
cameraController.delegate = psImageLayer;
psImageLayer.imagePicker = cameraController;
[[CCDirector sharedDirector] presentViewController:cameraController animated:YES completion:nil];
and I dismiss the camera in psImageLayer with this code:
- (void) imagePickerController: (UIImagePickerController *) picker
didFinishPickingMediaWithInfo: (NSDictionary *) info {
// do something with image
[[CCDirector sharedDirector] dismissViewControllerAnimated:YES completion:nil];
}
When I dismiss the camera, the app crashes with the following error: *** -[PLImageScrollView release]: message sent to deallocated instance 0x2494f4f0 I am pretty sure that PLImageScrollView is an iOS class, because I did not write it.
My issue appears to be very similar to the issue posted here, but his solution involves modifying the class that owns the delegate. In this case, UIImagePickerController is the class, which cannot be modified.
The relevant parts of the PhotoShareImageLayer header file are posted below:
// PhotoShareImageLayer.h (this is what psImageLayer is)
#interface PhotoShareImageLayer : CCLayer <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
#property(nonatomic, retain) UIImagePickerController *imagePicker;
#property(nonatomic, retain) UIImage *currentImage;
#end
Any ideas on how to stop this error from happening? Thanks.
EDIT: List of things I have already tried.
Subclassing UIImagePickerController and adding - (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self setDelegate:nil];
}
EDIT 2: The crash does not happen in imagePickerController:didCancel. Only when a picture is taken, OR when "Retake" is pressed in the camera. There is no UIImagePickerDelegate method for "Retake" (only "Cancel" and "Use").
EDIT 3: After continuing and writing more of the app, it appears this issue is not unique to the camera. The same (or very similar) errors occur when dismissing modal views for Twitter, Facebook, Contacts, and more.
I believe this is a problem with Apple's internal implementation of PLImageScrollView. I'm swizzling the UIScrollView`s setDelegate method and this causes a crash when a UIImagePicker is used (although, it only seems to be if you select a photo, not if you cancel). The problem I end up seeing is that the scrollViewDidScroll: method is sent to the real delegate (through my interceptor), but it's already been released.
This suggests to me that the PLImageScrollView's delegate is being dealloced without being nilled out. I half-solved the problem by creating my own strong reference to the real delegate. This could cause a memory leak in other implementations, but that's better than a crash at least.

Resources