对象在初始化后立即释放(Object deallocates immediately after it has been initialized)

我正在尝试制作一个播放YouTube视频的课程,但我遇到了一些问题。

以下是我处理YouTube视频的课程:

// 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

以下是调用此类的代码(此代码位于appDelegate中):

NSLog(@"about to load youtube"); ytObj=[[MyYouTube alloc] initIntoView:mainView withContent:cn]; NSLog(@"loaded youtube"); [mainView addSubview:[ytObj view]];

仅供参考的mainView和ytObj声明如下:

@property (nonatomic,strong) UIView * mainView; @property (nonatomic,strong) MyYouTube * ytObj;

运行此代码时,应用程序崩溃,我在控制台中获取此代码:

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

如果我将UIWebView委托设置为nil那么应用程序不会崩溃,但正如预期的那样,YouTube视频不会自动播放。

任何人都可以向我解释:

为什么对象在初始化后立即解除分配?

为什么respondsToSelector:消息被发送到除MyYouTube之外的实例?

如何在不崩溃的情况下让YouTube视频自动播放?

非常感谢。


编辑

完全是我的坏 - ytObj是一个强大的财产 - 我忘了提到这一点。 我添加了代码以反映这一点。


编辑2

我在dealloc方法上添加了一个断点,这是调用堆栈:

0 -[MyYouTube dealloc] 1 objc-object::sidetable_release(bool) 2 -[MyAppDelegate playYouTube:]

这里的最后一个条目( playYouTube:是包含我的app委托中代码的方法,该代码位于上面的原始帖子中。 那么,还有一个问题:

什么是objc-object::sidetable_release(bool) ,它做了什么,为什么它发布我的YouTube对象?

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?

最满意答案

为什么对象在初始化后立即解除分配?

因为没有东西拥有它。

您将其设置为视图的委托,但UIWebView的委托属性是assign属性。 该视图不接受其委托的所有权。 这意味着当ytObj超出范围时(可能之前,取决于优化)没有任何拥有它,所以它消失了。

编辑

您还需要确保在取消分配ytObj时,将其仍为委托的任何视图的委托属性设置为nil。 否则视图将继续尝试将消息发送到解除分配的对象。

如何在不崩溃的情况下让YouTube视频自动播放?

您需要确保ytObj持续的时间与它是委托的视图一样长,并且当它被解除分配时,它的视图的委托被设置为nil。


另一个小问题。 你的-init函数应该在调用self = [super init]后测试self不是nil。 如果self为nil,它不应该运行任何其余的初始化代码。

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.

更多推荐