3

すべてのアラートに自動的に表示されるNSApplicationIconイメージを、アプリバンドルにあるものとは異なるものに調整したいと思います。

[NSApplication setApplicationIconImage:]を使用してドックアイコンを設定できることは知っていますが、これはドックにのみ影響し、他には何も影響しません。

この問題を回避できる場合があります。NSAlert*があり、setIcon:を呼び出して代替画像を表示できます。

残念ながら、NSApplicationIconを備えたNSImageViewを備えたペン先がたくさんあり、影響を与えたいので、アウトレットを作成し、アイコンを変更するためのコードを入力するのは面倒です。そして、BeginAlert ...タイプの呼び出し(NSAlertオブジェクトをいじくりまわすことはできません)で発生するアラートについては、完全に運が悪いです。

AppKitで使用されるNSApplicationIconをグローバルに(実行中のアプリケーションの存続期間中)オーバーライドして、アラートを100%置き換える(そしてコードを単純化する)ための合理的な方法を誰かが考えることができますか? ?

4

2 に答える 2

2

メソッドをスウィズルし[NSImage imageNamed:]ますか?この方法は、少なくともSnow Leopard、YMMVで機能します。

カテゴリNSImage内:

@implementation NSImage (Magic)

+ (void)load {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    // have to call imageNamed: once prior to swizzling to avoid infinite loop
    [[NSApplication sharedApplication] applicationIconImage];

    // swizzle!
    NSError *error = nil;

    if (![NSImage jr_swizzleClassMethod:@selector(imageNamed:) withClassMethod:@selector(_sensible_imageNamed:) error:&error])
        NSLog(@"couldn't swizzle imageNamed: application icons will not update: %@", error);

    [pool release];
}


+ (id)_sensible_imageNamed:(NSString *)name {
    if ([name isEqualToString:@"NSApplicationIcon"])
        return [[NSApplication sharedApplication] applicationIconImage];

    return [self _sensible_imageNamed:name];
}

@end

このハッキングされた(テストされていない、ちょうどそれを書いた)jr_swizzleClassMethod:...実装で:

+ (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_ {
#if OBJC_API_VERSION >= 2
    Method origMethod = class_getClassMethod(self, origSel_);
    if (!origMethod) {
        SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]);
        return NO;
    }

    Method altMethod = class_getClassMethod(self, altSel_);
    if (!altMethod) {
        SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]);
        return NO;
    }

    id metaClass = objc_getMetaClass(class_getName(self));

    class_addMethod(metaClass,
                    origSel_,
                    class_getMethodImplementation(metaClass, origSel_),
                    method_getTypeEncoding(origMethod));
    class_addMethod(metaClass,
                    altSel_,
                    class_getMethodImplementation(metaClass, altSel_),
                    method_getTypeEncoding(altMethod));

    method_exchangeImplementations(class_getClassMethod(self, origSel_), class_getClassMethod(self, altSel_));
    return YES;
#else
    assert(0);
    return NO;
#endif
}

次に、この方法で要点を説明します。

- (void)doMagic:(id)sender {
    static int i = 0;

    i = (i+1) % 2;

    if (i)
        [[NSApplication sharedApplication] setApplicationIconImage:[NSImage imageNamed:NSImageNameBonjour]];
    else
        [[NSApplication sharedApplication] setApplicationIconImage:[NSImage imageNamed:NSImageNameDotMac]];

    // any pre-populated image views have to be set to nil first, otherwise their icon won't change
    // [imageView setImage:nil];
    // [imageView setImage:[NSImage imageNamed:NSImageNameApplicationIcon]];

    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
    [alert setMessageText:@"Shazam!"];
    [alert runModal];
}

注意点がいくつかあります。

  1. すでに作成されている画像ビューsetImage:は、画像の変更を登録するために上記のように2回呼び出されている必要があります。理由はわかりません。
  2. 私がやった方法よりも、最初のimageNamed:呼び出しを強制するためのより良い方法があるかもしれません。@"NSApplicationIcon"
于 2009-09-09T07:03:59.853 に答える
1

試してみてください[myImage setName:@"NSApplicationIcon"](NSAppでアプリケーションアイコン画像として設定した後)。

注: 10.6 以降でNSImageNameApplicationIconは、文字列リテラルの代わりに を使用できますし、使用する必要があります@"NSApplicationIcon"

于 2009-09-09T10:48:22.513 に答える