与WebView崩溃Mac屏幕保护程序
Hy everyone,与WebView崩溃Mac屏幕保护程序
我有一个用obj-c和可可做的屏幕保护程序。除了以下内容,在OsX 10.6.2下一切正常。 在我的屏幕保护程序中,我有一个运行某个应用程序的WebView。当我尝试通过javascript调用我的objective-c应用程序(屏幕保护程序)时,出现错误,屏幕保护程序和系统偏好设置面板崩溃。
系统偏好[86666] ***终止应用程序由于未捕获的异常 'NSInvalidArgumentException'
原因: ' - [NSCFArray漏极]:无法识别的选择发送到实例0x20049b1e0'
** *在第一次投掷:(
0的CoreFoundation 0x00007fff8123a444 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x00007fff81f130f3 objc_exception_throw + 45
2 CoreFound调用堆栈通货膨胀0x00007fff812931c0 + [NSObject的(NSObject的)doesNotRecognizeSelector:] + 0
3的CoreFoundation 0x00007fff8120d08f 转发 + 751
4的CoreFoundation 0x00007fff812091d8 _CF_forwarding_prep_0 + 232 5的WebCore 0x00007fff847adee0 _ZN3JSC8Bindings12ObjcInstance10virtualEndEv + 48
6的WebCore 0x00007fff8470d71d _ZN3JSC16RuntimeObjectImp18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE + 397
7 JavaScriptCore的0x00007fff80862b66 NK3JSC7JSValue3getEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE + 486
)
我知道这看起来像一些内存泄漏,但正如您将在代码中看到的,我确实几乎没有分配任何对象。
这种情况只发生在我用屏幕保护程序系统偏好设置中的“测试”按钮启动屏幕保护程序时。 当我通过终端启动屏幕保护程序或者它自动启动时,同样的操作(从javascript调用obj-c)可以正常工作。
也许有人有任何想法,错误可能来自哪里。这里是一些代码从执行:
@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
我希望这是足够的代码,让你看到一些问题/解决方案。 我真的很感谢任何答案。
不知怎的,一个NSCFArray(NSMutableArray)正在发送一个“漏”消息,这意味着一个NSAutoreleasePool。
您可以通过实现NSMutableArray的drain方法获得更多关于数组的信息,因此您可以捕获现在已识别的选择器并打印出数组对象的内容。试着在你的代码中加入这个地方:
@interface NSMutableArray (drain)
- (void) drain;
@end
@implementation NSMutableArray (drain)
- (void) drain
{
NSLog(@"drain message received by object: %@", self);
}
@end
如果你没有看到任何消息在控制台中显示出来,尝试在上面的代码为“NSObject的”改变“的NSMutableArray”。
有一点需要注意的是,当您通过System Prefs中的“测试”按钮启动屏幕保护程序时,实际上您的屏幕保护程序视图有2个实例在不同线程的相同进程地址空间中运行。其中一个(使用isPreview == YES)是SysPrefs窗口中的小预览(即使在全屏版本启动时也会继续运行),另一个是全屏版本。它们都在SysPrefs.app进程中运行。所以,你必须小心检查所有通知/等。看看他们是否来自您期望的视角。
我没有看到任何明显的问题,只需快速浏览一下您发布的代码,但它可能在其他地方。你是否在任何地方使用通知?
我在github上放了一个类似的webview-in-a-screensaver项目,在http://github.com/kelan/WikiWalker,我最初有一些类似的问题(虽然我没有使用任何JavaScript的东西)。这不是完美的代码,但可能有帮助。我也做了一些技巧,将通知转发给主线程(用于绘制)。请参阅WWScreenSaverView的“Threaded Notification Support”部分。{h,m}。
我不在任何地方使用通知。 我检查了我的不同对象(WebView,ScriptObject,self)的实例,但无法识别的选择器发送到的实例是完全不同的。有没有办法找出对象的哪些实例正在运行并获取名称(例如:0x200044820)? scriptobject是为JavaScript正确提供的,但之后,sysPrefs崩溃。 – dalind 2010-02-10 10:28:07
一些尝试:
- 打开一个终端窗口,输入以下行与NSZombieEnabled运行系统预置:
env NSZombieEnabled=YES "/Applications/System Preferences.app/Contents/MacOS/System Preferences"
执行导致的步骤到崩溃。
运行控制台应用程序,将右上角的过滤器设置为“系统偏好设置”,然后查找NSZombie消息。
希望这有助于!
我试过2次,但在我的控制台中没有NSZombie消息。该错误消息仍然是“***由于未捕获异常'终止应用程序NSInvalidArgumentException' - 无法识别的选择器发送到实例0x200472000 ***”。该实例编号不是我的对象,我认为,至少不是我的主视图,webview或scriptobject。 – dalind 2010-02-12 08:52:58
你打开GC还是不打开? – kennytm 2010-02-09 15:27:00
GC已打开。否则屏幕保护程序将无法使用OSX 10.6。 – dalind 2010-02-09 20:51:24