如何在AXObserverCallback回调中保留AXUIElementRef以便外部复用?
问题描述
我尝试存储AXObserverCallback回调提供的AXUIElementRef,但当回调作用域结束后,该结构体似乎被释放,导致无法在其他地方使用。请问是否有办法将该引用保留或复制到自定义数据结构中?
相关代码如下:
AXObserverCreate(..., &observer_callback, ...); AXObserverAddNotification(..., ..., kAXWindowCreatedNotification, this); ... void observer_callback(AXObserverRef observer, AXUIElementRef windowRef, CFStringRef notificationName, void* inUserData) { applications* apps = (applications*)inUserData; if (CFEqual(notificationName, kAXWindowCreatedNotification)) { // memory error when trying to use windowRef outside of callback apps->add_window_ref(windowRef); } else if (CFEqual(notificationName, kAXUIElementDestroyedNotification)) { apps->remove_window_ref(windowRef); } }
已知在Swift中可实现该需求,例如某开源项目已采用相关做法。
解决方案
AXUIElementRef属于*Core Foundation(CF)*对象,遵循CF的手动内存管理规则。回调中拿到的windowRef是临时引用,回调结束后系统会自动释放它,直接存储会触发野指针错误。要保留这个引用,必须手动管理它的引用计数:
1. 存储时保留引用
在add_window_ref方法中调用CFRetain(windowRef)增加引用计数,确保对象不会被系统提前释放:
void applications::add_window_ref(AXUIElementRef windowRef) { // 保留引用,维持对象生命周期 CFRetain(windowRef); // 将引用存入自定义数据结构(示例用vector) window_refs.push_back(windowRef); }
2. 不再使用时释放引用
当你确定不再需要该AXUIElementRef(比如收到销毁通知或清理数据结构时),调用CFRelease(windowRef)减少引用计数,避免内存泄漏:
void applications::remove_window_ref(AXUIElementRef windowRef) { // 从数据结构中移除目标引用 auto it = std::find(window_refs.begin(), window_refs.end(), windowRef); if (it != window_refs.end()) { window_refs.erase(it); // 释放引用,平衡计数 CFRelease(windowRef); } }
关键注意事项
- 严格遵循CF内存管理原则:谁调用
CFRetain,谁就要负责调用CFRelease,保证引用计数始终平衡。 - 收到
kAXUIElementDestroyedNotification时,对应的AXUIElementRef已经失效,释放后绝对不能再访问该对象。 - Swift中能自动处理,是因为Swift的ARC会自动为桥接的CF对象管理引用计数,本质和手动调用
CFRetain/CFRelease逻辑一致。
内容的提问来源于stack exchange,提问作者Jason1923
相关产品推荐
相关产品推荐

