Objective c 带有WebView的Mac屏幕保护程序崩溃
大家好 我有一个用obj-c和可可制作的屏幕保护程序。在OsX 10.6.2下,除了以下各项之外,其他一切都可以正常工作。 在我的屏幕保护程序中,我有一个运行着一些应用程序的WebView。当我试图通过javascript将objective-c应用程序称为屏幕保护程序时,出现错误,屏幕保护程序和系统首选项面板崩溃 系统首选项[86666] ***由于未捕获异常“NSInvalidArgumentException”而终止应用程序 原因:'-[NSCFArray drain]:无法识别的选择器已发送到实例0x20049b1e0' ***第一次抛出时调用堆栈: 0 CoreFoundation 0x00007fff8123a444例外预处理+180 1 libobjc.A.dylib 0x00007fff81f130f3 objc_异常_抛出+45 2 CoreFoundation 0x00007fff812931c0+[NSObjectNSObject未识别选择器:+0 3 CoreFoundation 0x00007fff8120d08f转发+751 4 CoreFoundation 0x00007fff812091d8\u CF\u转发\u准备\u 0+232 5网络存储0x00007fff847adee0(u zn3JSC8绑定12对象虚拟现实环境+48 6 WebCore 0x00007fff8470d71d\u zn3JSC16运行时对象18 GetownPropertySlotePNs\u 9执行状态KNS\u 10标识符\u 12 PropertySlote+397 7 JavaScriptCore 0x00007fff80862b66 NK3JSC7JSValue3getEPNS\u 9执行状态KNS\u 10标识符\u 12 PropertySlote+486 我知道这看起来像是内存泄漏,但正如您在代码中看到的,我几乎没有分配对象 只有当我使用屏幕保护程序系统prefs中的测试按钮启动屏幕保护程序时,才会发生这种情况。 当我通过终端启动屏幕保护程序或者它自动启动时,从javascript调用obj-c的相同操作也可以正常工作 也许有人知道错误可能来自哪里。下面是实现中的一些代码:Objective c 带有WebView的Mac屏幕保护程序崩溃,objective-c,cocoa,macos,screensaver,Objective C,Cocoa,Macos,Screensaver,大家好 我有一个用obj-c和可可制作的屏幕保护程序。在OsX 10.6.2下,除了以下各项之外,其他一切都可以正常工作。 在我的屏幕保护程序中,我有一个运行着一些应用程序的WebView。当我试图通过javascript将objective-c应用程序称为屏幕保护程序时,出现错误,屏幕保护程序和系统首选项面板崩溃 系统首选项[86666] ***由于未捕获异常“NSInvalidArgumentException”而终止应用程序 原因:'-[NSCFArray drain]:无法识别的选择器已
@implementation ScreensaverView
- (id)initWithFrame:(NSRect)frame isPreview:(BOOL)isPreview {
self = [super initWithFrame:frame isPreview:isPreview];
if (self) {
[self setAnimationTimeInterval:-1];
[self setAutoresizesSubviews:YES];
// ::::::::::::::::::::::: Init stuff ::::::::::::::::::
// init
quitFlag = false;
previewMode = isPreview;
// find out the path the screensaver bundle
pMainBundle = [NSBundle bundleForClass:[self class]];
pBundlePath = [pMainBundle bundlePath];
// read Info.plist
infoDict = [pMainBundle infoDictionary];
}
return self;
}
- (void)startAnimation
{
[super startAnimation];
// combine: bundle path + filename for screensaver file
NSString *pathToScreensaver = [NSString stringWithString:pBundlePath];
NSString *valueScreensaverFile;
if(!previewMode)
{
valueScreensaverFile = [infoDict objectForKey:@"ScreensaverFile"];
}
else
{
valueScreensaverFile = [infoDict objectForKey:@"PreviewFile"];
}
// add filename to bundle path
pathToScreensaver = [pathToScreensaver stringByAppendingString:valueScreensaverFile];
// complete NSURL to the screensaver file
NSURL *screensaverUrl = [NSURL fileURLWithPath: pathToScreensaver];
webView = [WebView alloc];
[webView initWithFrame:[self frame]];
[webView setDrawsBackground:NO];
// delegation policy for interactive mode
[webView setPolicyDelegate: self];
[webView setUIDelegate:self];
// load screensaver
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:screensaverUrl]];
scriptObject = [webView windowScriptObject];
[scriptObject setValue:self forKey:@"screensaver"];
[self addSubview:webView];
}
- (void)stopAnimation
{
[[webView mainFrame] stopLoading];
[webView removeFromSuperview];
[webView release];
[super stopAnimation];
}
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector
{
if (selector == @selector(quitScreenSaver)) {
return NO;
}
if(selector == @selector(gotoUrl:) ){
return NO;
}
return YES;
}
+(NSString *)webScriptNameForSelector:(SEL)selector
{
if(selector == @selector(quitScreenSaver))
{
return @"quitNoOpen";
}
if(selector == @selector(gotoUrl:))
{
return @"openAndQuit";
}
return nil;
}
- (void) quitScreenSaver
{
quitFlag = true;
[super stopAnimation];
}
- (void) gotoUrl:(NSString *) destinationURL
{
if(destinationURL == NULL)
{
return;
}
NSString * path = destinationURL;
NSURL * fileURL = [NSURL URLWithString:path];
[[ NSWorkspace sharedWorkspace ] openURL:fileURL];
[self quitScreenSaver];
}
@end
我希望这些代码足够让您看到一些问题/解决方案。
我非常感谢您的回答。只是为了解决问题,您是否尝试过不发布WebView
另外,在首次发布WebView之前,可能会将其委托设置为零?只是为了排除故障,您是否尝试过不发布WebView
另外,在首次发布之前,可能会将WebView的委托设置为nil?需要注意的一点是,当您通过System Prefs中的测试按钮启动屏幕保护程序时,实际上有两个屏幕保护程序视图实例在不同线程的同一进程地址空间中运行。isPreview==YES的一个是SysPrefs窗口中的小预览,即使在全屏版本启动时也会继续运行,另一个是全屏版本。它们都在SysPrefs.app进程中运行。因此,您必须仔细检查所有通知/等,以查看它们是否来自您期望的视图实例 快速浏览一下您发布的代码,我没有发现任何明显的问题,但它可能在其他地方。你在任何地方都使用通知吗
我在github上放了一个类似的webview-in-a-screensaver项目,在那里我最初遇到了一些类似的问题,尽管我没有使用任何javascript内容。这不是完美的代码,但可能会有所帮助。我还做了一些技巧,将通知转发到主线程,以便在中绘制。请参阅WWScreenSaverView的线程通知支持部分。{h,m}。需要注意的一点是,当您通过System Prefs中的测试按钮启动屏幕保护程序时,实际上有两个屏幕保护程序视图实例在不同线程的同一进程地址空间中运行。isPreview==YES的一个是SysPrefs窗口中的小预览,即使在全屏版本启动时也会继续运行,另一个是全屏版本。它们都在SysPrefs.app进程中运行。因此,您必须仔细检查所有通知/等,以查看它们是否来自您期望的视图实例 快速浏览一下您发布的代码,我没有发现任何明显的问题,但它可能在其他地方。你在任何地方都使用通知吗 我在github上放了一个类似的webview-in-a-screensaver项目,在那里我最初遇到了一些类似的问题,尽管我没有使用任何javascript内容。这不是完美的代码,但可能会有所帮助。我还做了一些技巧,将通知转发到主线程,以便在中绘制。请参阅WWScreenSaverView的线程通知支持部分。{h,m}。要尝试的内容: 打开终端窗口并输入以下行以运行系统首选项: env NSZombieEnabled=YES/Applications/System Preferences.app/Contents/MacOS/System Preferences 执行导致崩溃的步骤 运行控制台应用程序,将右上角的过滤器设置为系统首选项,并查找NSZombie消息 希望这有帮助 S 尝试一下: 打开终端窗口并输入以下行以运行系统首选项: env NSZombieEnabled=YES/Applications/System Preferences.app/Contents/MacOS/System Preferences 执行导致崩溃的步骤 运行控制台应用程序,将右上角的过滤器设置为系统首选项,并查找NSZombie消息
希望这有帮助 不知何故,NSCFArray NSMutableArray正在发送一条用于NSAutoreleasePool的drain消息 通过实现NSMutableArray的drain方法,您可能可以获得关于数组是什么的更多信息,因此您可以捕获现在已识别的选择器并打印出数组对象的内容。尝试在代码中的某个位置添加以下内容:
@interface NSMutableArray (drain)
- (void) drain;
@end
@implementation NSMutableArray (drain)
- (void) drain
{
NSLog(@"drain message received by object: %@", self);
}
@end
如果控制台中没有显示任何消息,请尝试将上述代码中的NSMutableArray更改为NSObject。不知何故,NSCFArray NSMutableArray正在发送一条用于NSAutoreleasePool的drain消息 通过实现NSMutableArray的drain方法,您可能可以获得关于数组是什么的更多信息,因此您可以捕获现在已识别的选择器并打印出数组对象的内容。尝试在代码中的某个位置添加以下内容:
@interface NSMutableArray (drain)
- (void) drain;
@end
@implementation NSMutableArray (drain)
- (void) drain
{
NSLog(@"drain message received by object: %@", self);
}
@end
如果控制台中没有显示任何消息,请尝试将上述代码中的NSMutableArray更改为NSObject。是否打开GC?GC已打开。否则,屏幕保护程序将无法与OSX 10.6配合使用。您是否打开了GC?GC已打开。否则,屏幕保护程序将无法与OSX 10.6配合使用。请尝试一下。系统prefs面板仍然崩溃。我认为WebView没有委托。在您发布的示例代码中,您在WebView上设置了两个不同的委托。您是对的。我已经删除了这些,但崩溃仍然发生。只是尝试了一下。系统prefs面板仍然崩溃。我认为WebView没有委托。在您发布的示例代码中,您在WebView上设置了两个不同的委托。您是对的。我已经删除了这些,但崩溃仍然发生。我在任何地方都不使用通知。我检查了我的不同对象WebView、ScriptObject、self的实例,但是将无法识别的选择器发送到的实例是完全不同的。是否有办法查明哪些对象实例正在运行并获取名称,例如:0x200044820?scriptobject是为JavaScript正确提供的,但之后,sysPrefs崩溃了。我在任何地方都不使用通知。我检查了我的不同对象WebView、ScriptObject、self的实例,但是将无法识别的选择器发送到的实例是完全不同的。是否有办法查明哪些对象实例正在运行并获取名称,例如:0x200044820?scriptobject是为JavaScript正确提供的,但之后,sysPrefs崩溃了。我尝试了两次,但控制台中没有NSZombie消息。由于未捕获的异常“NSInvalidArgumentException”-发送到实例0x200472000的无法识别的选择器,错误消息仍在终止应用程序。我想那个实例号不是我的对象,至少不是我的mainview、webview或scriptobject。我试了两次,但我的控制台中没有NSZombie消息。由于未捕获的异常“NSInvalidArgumentException”-发送到实例0x200472000的无法识别的选择器,错误消息仍在终止应用程序。该实例编号不属于我的对象,至少不属于我的mainview、webview或scriptobject。覆盖NSObject drain后,系统prefs面板不再崩溃。漏消息来自某个奇怪的预览图像,大多数情况下是另一个。现在一切都很好。非常感谢。投赞成票,因为如果某些奇怪的对象杀死了你的应用程序,特别是当该应用程序被另一个对象执行时,我认为这是一个答案。通过覆盖NSObject drain,系统prefs面板不再崩溃。漏消息来自某个奇怪的预览图像,大多数情况下是另一个。现在一切都很好。非常感谢。投赞成票,因为这是一个答案,我认为如果一些奇怪的对象杀死了你的应用程序,特别是当应用程序被另一个执行时,你总是需要这个答案。