converting my project to ARC but says it can't due to the following error 'No matching function for call to pthread_create'. Here is the code it falls in, happens specifically on the line starting with pthread create
. How can I fix this? It also says Candidate function not viable: no known conversion from 'NSString *' to 'void * _Nullable' for 4th argument
in the sidebar underneath the error.
I've cut off the rest of the function but can provide more detail if necessary.
void World::loadWorld(std::string name)
{
if(doneLoading==0)
{
doneLoading=1;
Resources::getResources->stopMenuTune();
if(LOW_MEM_DEVICE)
{
menu->deactivate();
Resources::getResources->unloadMenuTextures();
terrain->allocateMemory();
terrain->loadTerrain(name,TRUE);
doneLoading=2;
hud->fade_out=1;
}
else
{
terrain->allocateMemory();
pthread_t foo;
pthread_create(&foo,NULL,loadWorldThread, nsstring(name));
}
}
As your error message indicates the 4th argument to pthread_create
is of type void *
. Under ARC you cannot simply pass an Obj-C object reference as a void *
as ARC would is not able to track the reference once it is stored in a C(++) pointer variable, and therefore cannot manage the object's memory.
For situations where an Obj-C reference must be passed into the C(++) world a bridge cast can be used to inform ARC how the memory should be managed. However in your case there a better way, just pass the C++ pointer, name
, without creating an NSString
. If loadWorldThread
expects a std::string
that is the correct thing to do anyway. If it expects an NSString *
then either:
modify it to take a std::string
and do any required conversion to NSString *
within it; or
write a small intermediate function which takes a std::string
, produces an NSString *
from it, and then calls loadWorldThread
. Pass this new function to pthread_create
.
Doing either of the above avoids the use of a bridge cast in the pthread_create
call to move the Obj-C reference into the C(++) world and out of ARC control; and another bridge cast in loadWorldThread
(or intermediate function as above) to move it back into the Obj-C world and into ARC control.
Addendum
Expanding on the last paragraph, as the method there seems better suited to your situation. First, it is assumed that your code:
nsstring(name)
takes a value of type std::string
and returns a value of type NSString
, if it does not then look up how to do this conversion.
After the above expression you have a reference to an NSString
under ARC control. You cannot simply pass such a reference as a void *
, you must take it out of ARC's control first and take responsibility for its memory management (but not for long as you will see). You can bridge cast your NSString *
to a CFStringRef
:
CFStringRef cfName = (__bridge_retain CFStringRef)nsstring(name);
You can now pass cfName
, which is a reference to a heap-allocated CFString
, as a void *
.
Now in loadWorldThread
; which should be declared to take a void *
, something like void loadWorldThread(void *arg) { ... }
; you need to bridge cast your CFStringRef
back to NSString *
and hands responsibility for its memory management back to ARC:
NSString *nsName = (__bridge_transfer NSString *)arg;
The above is a standard pattern to pass an ARC controlled reference though an anonymous reference (void *
).
(Note: the above uses CFStringRef
to make it clear that you are passing around a reference to a manually managed CFString
, you can cast directly to void *
and back again, indeed you will notice that when casting back arg
was not first cast to a CFStringRef
to demonstrate this.)
HTH