I am trying to convert an ObjC stackoverflow answer to Swift and failing. It looks like I am passing a UnsafeMutablePointer<mach_msg_type_number_t>
when I should be passing an inout mach_msg_type_number_t
and I can't seem to work out my problem. From what I understand of the Swift pointer documentation (not much) these should be interchangeable..?
Further info below.
Here's the Objective C:
struct task_basic_info info;
mach_msg_type_number_t size = sizeof(info);
kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
and here's as far as I got in Swift (many lines for easier type checking)
let name: task_name_t = mach_task_self_
let flavor: task_flavor_t = task_flavor_t(MACH_TASK_BASIC_INFO)
var info: mach_task_basic_info
var size: mach_msg_type_number_t = UnsignedFixed(sizeof(mach_task_basic_info_t))
let kerr = task_info(name, flavor, info as task_info_t, &size)
The task_info
signature is:
func task_info(target_task: task_name_t, flavor: task_flavor_t, task_info_out: task_info_t, task_info_outCnt: UnsafeMutablePointer<mach_msg_type_number_t>) -> kern_return_t
and the error on the last line is:
Cannot convert the expression's type '(@!lvalue task_name_t, task_flavor_t, task_info_t, inout mach_msg_type_number_t)' to type 'kern_return_t'
When interacting with C functions, you can't rely on the compiler's error messages - break it down parameter by parameter, command-clicking until you know what you're working with. To start with, the types you're running into are:
task_name_t
:UInt32
task_flavor_t
:UInt32
task_info_t
:UnsafeMutablePointer<Int32>
UnsafeMutablePointer<mach_msg_type_number_t>
:UnsafeMutablePointer<UInt32>
kern_return_t
-Int32
There's one tricky Swift bit along with a bug in your code standing in your way here. First, the
task_info_out
parameter needs to be aUnsafeMutablePointer<UInt32>
, but needs to actually point to an instance ofmach_task_basic_info
. We can get around this by creating aUnsafeMutablePointer<mach_task_basic_info>
and wrapping it in anotherUnsafeMutablePointer
at call time - the compiler will use type inference to know we want that wrapping pointer to be sub-typed asUInt32
.Second, you're callingsizeof(mach_task_basic_info_t)
(the pointer tomach_task_basic_info
) when you should be callingsizeinfo(mach_task_basic_info)
, so your byte count ends up too low to hold the data structure.On further research, this got a little more complicated. The original code for this was incorrect, in that
size
should be initialized to the constantMACH_TASK_BASIC_INFO_COUNT
. Unfortunately, that's a macro, not a simple constant:Swift doesn't import those, so we'll need to redefine it ourselves. Here's working code for all this:
Nate’s answer is excellent but there’s a tweak you can make to simplify it.
First, rather than allocating/deallocating the
task_basic_info
pointer, you can create the struct on the stack, then usewithUnsafeMutablePointer
to get a pointer directly to it which you can pass in.Took me a bit to update Airspeed Velocity's answer to the latest swift syntax (Swift 3, beta 6), but here is what I got:
Hope that's helpful.
Airspeed Velocity's answer in Swift 3...