Reputation: 4308
I have this Objective-C Code fragment, which I want to express in Swift
CFArrayRef windowList;
AXUIElementCopyAttributeValue(appRef, kAXWindowsAttribute, (CFTypeRef *)&windowList);
if ((!windowList) || CFArrayGetCount(windowList)<1)
continue;
AXUIElementRef windowRef = (AXUIElementRef) CFArrayGetValueAtIndex( windowList, 0);
CFTypeRef role;
AXUIElementCopyAttributeValue(windowRef, kAXRoleAttribute, (CFTypeRef *)&role);
The first thing I´m not sure about: Who allocates the memory behind the windowListPointer. I tried with this fragment:
var windowListPointer : UnsafeMutablePointer<Optional<AnyObject>>
AXUIElementCopyAttributeValue(appRef, kAXWindowsAttribute as CFString, windowListPointer );
But that does not even compile: It complains, the windowListPointer is not initialised. What Object I could create, to let the WindowListPointer point to?
Upvotes: 2
Views: 676
Reputation: 540105
If you pass an UnsafeMutablePointer<Optional<AnyObject>>
as the last
argument to AXUIElementCopyAttributeValue()
then you must
initialize it by allocating (and ultimately releasing) memory:
var resultPtr: UnsafeMutablePointer<Optional<AnyObject>> = UnsafeMutablePointer.allocate(capacity: 1)
resultPtr.initialize(to: nil)
let result = AXUIElementCopyAttributeValue(appRef, kAXWindowsAttribute as CFString, resultPtr)
// ...
resultPtr.deinitialize()
resultPtr.deallocate(capacity: 1)
It is easier
to pass the address of an Optional<AnyObject>
variable
with &
. Then conditionally
cast the received object to the expected type, in this case an
array of AXUIElement
:
var value: AnyObject?
let result = AXUIElementCopyAttributeValue(appRef, kAXWindowsAttribute as CFString, &value)
if result == .success, let windowList = value as? [AXUIElement] {
// use `windowList`
}
and similarly:
if let window = windowList.first {
var value: AnyObject?
let result = AXUIElementCopyAttributeValue(window, kAXRoleAttribute as CFString, &value)
if result == .success, let role = value as? String {
// use `role` ...
}
}
One could define a generic utility function which encapsulates all the casting:
func axUICopyAttributeValue<T>(of element: AXUIElement, attribute: String, as type: T.Type) -> T? {
var value: AnyObject?
let result = AXUIElementCopyAttributeValue(element, attribute as CFString, &value)
if result == .success, let typedValue = value as? T {
return typedValue
}
return nil
}
Example usage:
if let windowList = axUICopyAttributeValue(of: appRef, attribute: kAXWindowsAttribute, as:[AXUIElement].self) {
for window in windowList {
if let role = axUICopyAttributeValue(of: window, attribute: kAXRoleAttribute, as: String.self) {
// ...
}
}
}
Upvotes: 3
Reputation: 16347
CFArray is the Foundation C version of NSArray (since C doesn't understand Objective C NSObjects). Swift papers over both NSArray and CFArray for you so you don't need to use a pointer; you should just be able to cast it to a Swift array of the appropriate type with as?
Upvotes: 1