2

Qt プロジェクトに取り組んでおり、追加する必要がある Mac 固有のコードがいくつかあります。イベントに登録する必要があります。サンプル プログラムでは、以下を使用してそれを行いました。

[[NSNotificationCenter defaultCenter] addObserver:self
                                   selector:@selector(notificationHandler:) 
                                   name:NSWorkspaceDidDeactivateApplicationNotification
                                   object:nil];

Qt の mm ファイルで直接使用できるため、次のようなアプローチをとっています。

MyClass::MyClass() : {
    // do other setup ...

    CFNotificationCenterAddObserver
    (
        CFNotificationCenterGetLocalCenter(),
        this,
        &notificationHandler,
        CFSTR("???"),
        NULL,
        CFNotificationSuspensionBehaviorDeliverImmediately
    );
}

「NSWorkspaceDidDeactivateApplicationNotification」の文字列は何ですか?? または、この特定の通知にどのように関連付けますか?

NSGod のアプローチを試してみましたが、Qt では Objective-C コードを .h に追加できないため、実際のロジックを含む mm ファイルでクラスが定義されているプラ​​イベート メンバーを追加しました。このような:

SelectedStuffManager.h

class MacWrap;

class SelectedStuffManager
{
  public:
   ....
    doSomething();

    MacWrap* d;

  private:
   ....
};

SelectedStuffManager.mm

@class MDWorkspaceWatcher;

class MacWrap
{
    public:
        MacWrap();
        ~MacWrap();

        void  applicationDeactivated(NSNotification * notification);

        SystemEventsApplication *systemApplication;
        NSRunningApplication *runApp;

        private:
           MDWorkspaceWatcher *workspaceWatcher;
};
MacWrap::MacWrap() {
      this->workspaceWatcher = [[MDWorkspaceWatcher alloc] initWithMyClass:this];
}

MacWrap::~MacWrap() {
      [this->workspaceWatcher release];
}

void  MacWrap::applicationDeactivated(NSNotification* notification)
{
    // guardar el id del proceso para utilizarlo luego
    runApp = [[notification userInfo] valueForKey:@"NSWorkspaceApplicationKey"];
    NSString *systemEventsASppName = [runApp bundleIdentifier];
    if( [ systemEventsASppName isNotEqualTo:@"com.yo.SelectedText"])
    {
        systemApplication = [SBApplication applicationWithBundleIdentifier:systemEventsASppName];
        NSLog(@"Launched. %@",systemEventsASppName);
    }

}

@interface MDWorkspaceWatcher : NSObject {

     MacWrap  *manager;
}

- (id)initWithMyClass:(MacWrap*)obj;
- (void)didDeactivateApp:(NSNotification *)notification; @end

@implementation MDWorkspaceWatcher
- (id)initWithMyClass:(MacWrap*)obj {
    if ((self = [super init])) {
       manager = obj;

       [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
                selector:@selector(didDeactivateApp:)
                name:NSWorkspaceDidDeactivateApplicationNotification
                object:nil];
    }
    return self;
}

- (void)dealloc {
    [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
    [super dealloc];
}

- (void)didDeactivateApp:(NSNotification *)notification {
   manager->applicationDeactivated(notification);
}
@end

SelectedStuffManager::SelectedStuffManager()
{
    d = new MacWrap();
}
SelectedStuffManager::doSomething()
{
    if ([[d->runApp localizedName] isEqualTo: @"something"]) --> here it fails, bad memory access
    {
       ...
    }
}

誰かが runApp と systemApplication の両方を解放しているように見えるため、null ポインターまたは不良メモリが発生します。どのように、またはなぜこれが起こっているのでしょうか?

4

1 に答える 1

0

あなたが望んでいるようにできるとは思えません。まず、NSWorkspaceは独自のを使用します。これは、 で返さNSNotificationCenterれるデフォルトとは異なります。NSNotificationCenter+defaultCenter

NSWorkspaceこれらの呼び出しに厳密に相当する CF があるとは思いません。高レベルの Carbon ベースの同等物が存在する可能性がありますが、それらは 64 ビットでは使用できないため、避ける必要があります。

次のコードのように、小さな Objective-C ヘルパー クラスを使用して通知を受け取り、それらを C++ クラスに転送することで、目的を達成できるはずです。

編集: ヘッダー ファイルから Objective-C を削除するように更新しました。void *.mm ファイル内でキャストできる汎用ポインターを使用するだけです。

.h:

//@class MDWorkspaceWatcher;

class MyClass {
   private:
      // MDWorkspaceWatcher *workspaceWatcher;
      void *workspaceWatcher;
   public:
       MyClass();
       ~MyClass();

       // const void didActivateApp(NSNotification *notification) const;
       // const void didDeactivateApp(NSNotification *notification) const;
       const void didActivateApp(void *anNSnotification) const;
       const void didDeactivateApp(void *anNSnotification) const;

};

。んん:

Objective-C の部分:

@interface MDWorkspaceWatcher : NSObject {
    MyClass    *myClass;
}
- (id)initWithMyClass:(MyClass *)aMyClass;
@end

@implementation MDWorkspaceWatcher
- (id)initWithMyClass:(MyClass *)aMyClass {
    if ((self = [super init])) {
       myClass = aMyClass;
       [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
                selector:@selector(didActivateApp:)
                name:NSWorkspaceDidActivateApplicationNotification
                object:nil];
       [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
                selector:@selector(didDeactivateApp:)
                name:NSWorkspaceDidDeactivateApplicationNotification
                object:nil];
    }
    return self;
}
// very important:
- (void)dealloc {
    [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
    [super dealloc];
}
- (void)didActivateApp:(NSNotification *)notification {
   myClass->didActivateApp(notification);
}
- (void)didDeactivateApp:(NSNotification *)notification {
   myClass->didDeactivateApp(notification);
}
@end

C++ 部分:

MyClass::MyClass() {
      this->workspaceWatcher = [[MDWorkspaceWatcher alloc] initWithMyClass:this];
}

MyClass::~MyClass() {
      [(MDWorkspaceWatcher *)this->workspaceWatcher release];
}

MyClass::didActivateApp(void *anNSnotification) {
     NSDictionary *appInfo = [(NSNotification *)anNSnotification userInfo];          
     NSLog(@"appInfo == %@", appInfo);

}

MyClass::didDeactivateApp(void *anNSnotification) {
     NSDictionary *appInfo = [(NSNotification *)anNSnotification userInfo];          
     NSLog(@"appInfo == %@", appInfo);

}

NSDictionaryanは と無料でブリッジされていることに注意してください。したがって、Objective-C よりも C を好む場合は、単にを aにCFDictionaryRefキャストし、関数を呼び出して辞書の内容を取得できます。appInfo NSDictionaryCFDictionaryRefCF

通知センターがappInfoディクショナリを所有する (つまり、自動解放される) ため、 /関連のコードCFRelease()のように呼び出すべきではないことに注意してください。CFCreate*CFCopy*

于 2012-01-31T17:32:47.717 に答える