CFNotificationCenter 中的 NSWorkspace 通知
我们正在开发一个 Qt 项目,需要添加一些 Mac 特定的代码。我们需要注册一个事件,在一个示例程序中,我们通过使用以下方法来做到这
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(notificationHandler:)
name:NSWorkspaceDidDeactivateApplicationNotification
object:nil];
一点: 由于我们可以直接在 Qt 上的 mm 文件中使用它,因此我们采取的方法如下:
MyClass::MyClass() : {
// do other setup ...
CFNotificationCenterAddObserver
(
CFNotificationCenterGetLocalCenter(),
this,
¬ificationHandler,
CFSTR("???"),
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately
);
}
“NSWorkspaceDidDeactivateApplicationNotification”的字符串是什么?或者我们如何将自己附加到这个特定的通知?
我们尝试了 NSGod 的方法,但由于无法在 Qt 的 .h 中添加 Objective-C 代码,因此我们添加了一个私有成员,其类在 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,所以我们得到一个空指针或坏内存。怎么或者为什么会发生这种情况?
We are working on a Qt project, and there is some Mac specific code that we need to add. We need to register for an event, in a sample program we did that by using:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(notificationHandler:)
name:NSWorkspaceDidDeactivateApplicationNotification
object:nil];
Since we can use that directly in our mm file on Qt, we are taking the approach of doing something like:
MyClass::MyClass() : {
// do other setup ...
CFNotificationCenterAddObserver
(
CFNotificationCenterGetLocalCenter(),
this,
¬ificationHandler,
CFSTR("???"),
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately
);
}
whats the string for "NSWorkspaceDidDeactivateApplicationNotification"?? Or how do we attatch ourselves to this particular notification?
We tried NSGod's approach, but since no Objective-C code can be added in a .h with Qt, then we added a private member which its class is defined in the mm file, that containes the actual logic. like this:
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
{
...
}
}
It seems like someone is freeing both runApp and systemApplication, so we get a null pointer or bad memory. How or why could this be happening?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不相信你能像你希望的那样做。首先,
NSWorkspace
使用自己的NSNotificationCenter
,它与+defaultCenter
返回的默认NSNotificationCenter
不同。我不相信这些 NSWorkspace 调用有严格的 CF 等效项。可能存在基于 Carbon 的高级等效项,但它们在 64 位中不可用,因此应该避免使用。
您应该能够使用小型 Objective-C 帮助程序类来接收通知并将其转发到您的 C++ 类,如以下代码所示:
编辑:更新以从头文件中删除任何 Objective-C。只需使用通用的
void *
指针,您可以在 .mm 文件中对其进行转换。.h:
.mm:
Objective-C 部分:
C++ 部分:
请注意,
NSDictionary
与CFDictionaryRef
是免费桥接的,因此您只需转换如果您更喜欢 C 而不是 Objective,则将 appInfo
NSDictionary
转换为CFDictionaryRef
,然后调用CF
函数来获取字典的内容-C。请注意,通知中心拥有
appInfo
字典(换句话说,它将自动释放),因此您不应该像使用 < code>CFCreate*/CFCopy*
相关代码。I don't believe you can just do like you're hoping to. First of all,
NSWorkspace
uses its ownNSNotificationCenter
, which is different than the defaultNSNotificationCenter
returned with+defaultCenter
.I don't believe there's a strict CF-equivalent to those
NSWorkspace
calls. There are likely high-level Carbon-based equivalents, but they're not available in 64-bit, and should likely be avoided.You should be able to accomplish what you want using a small Objective-C helper class to receive the notifications and forward them to your C++ class like in the following code:
EDIT: updated to remove any Objective-C from header files. Just use generic
void *
pointers, which you can cast inside the .mm file..h:
.mm:
Objective-C part:
C++ part:
Note that an
NSDictionary
is toll-free-bridged withCFDictionaryRef
, so you can simply cast theappInfo
NSDictionary
to aCFDictionaryRef
and then call theCF
functions to get at the contents of the dictionary if you prefer C over Objective-C.Note that the notification center owns the
appInfo
dictionary (in other words, it will be autoreleased), so you shouldn't callCFRelease()
on it like you might withCFCreate*
/CFCopy*
-related code.