Been battling this one for a while. Basically, I am converting an image into NSData so I can send it to a server. The code I have used before, but for some reason I am getting an ARC error on this. The error lands on the line I declare the imageData variable.
NOTE: myImage is handed to the method.
- (void)uploadImage:(NSImage *)myImage {
NSData *imageData = UIImageJPEGRepresentation(myImage, 1.0);
// Do something...
}
I get an error and two warnings
Error: Implicit conversion of 'int' to 'NSData *' is disallowed with ARC
Warning: Implicit declaration of function 'UIImageJPEGRepresentation' is invalid in C99
Warning: Incompatible integer to pointer conversion intializing 'NSData * __strong' with an expression of type 'int'
Any ideas?
You might need to include the relevant header:
#import <UIKit/UIKit.h>
Prior to C99, if you call a function that the compiler hasn't seen a declaration for, it will compile the call as if the function was declared as int UIImageJPEGRepresentation(). C99 doesn't allow that, but it seems that the compiler is still applying the old interpretation (or the compiler is in pre-C99 mode; I'm not sure what the default is), hence the ARC error.
Related
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
the Code: [NSClassFromString(#"Test") gotoTest];
usage ARC with Error: No known class method for selector 'gotoTest'
but in MRC warning no error.
Way ARC from warning becomes an error ? do you have any reference? I want to know the essential reason.
You did not include the warning under MRC:
Class method '+gotoTest' not found (return type defaults to 'id')
and this contains a vital clue – the compiler is looking for the return type. Under MRC it assumes id and will let you assign the result as an object reference. If you mess up and the return type is, say, float, things will probably go wrong.
Under ARC it is the compilers job to do the memory management of any returned value, and to do this correctly it needs to the the type. So if it can't determine the return type it produce an error.
Your code fragment suggests you know the selector takes no arguments and returns no value, so declare it as such. If you've no class with the method you can use a protocol, something like:
#protocol GotoTest
+ (void) gotoTest;
#end
will do. Now the compiler knows the types and your code will compile under ARC.
HTH
I have a function declared like this:
- (void)loadWithCompletion:(MyCompletion)completion error:(NSError**)error;
The function takes a double pointer to an NSError so I can report errors to the caller. The completion (and possibly the error) will occur some time after the function is called. I need to store the NSError** as a property so I can use it when the aforementioned time passes.
#property(nonatomic, assign) NSError** error;
This property declaration gives me the error:
Pointer to non-const type NSError* with no explicit ownership.
add __autoreleasing between the **, to give NSError*__autoreleasing* error
In Xcode 5.1 the ARC warning "Implicit ownership types on out parameters" was turned on by default (it used to be off). So with 5.1 this warning started appearing when there was no specified ownership.
The compiler assumes you want autoreleased, which is usually correct, but it's better that the author think about it and specify what the really want.
Usually you want the output parameter to be autoreleasing, similar to a function result. The caller will get an autoreleased object and will need to store it in a strong variable if they want to retain ownership.
I am having a hard time finding an explanation of what it means to assign to __strong from incompatible type. I'd like to understand the message instead of how to fix a specific instance.
I understand that __strong means that I will own the object. For example:
info = [ADMCoreFactory newServiceInfoWithURI:[queue uri]];
In this case I am getting a warning that I am assigning '__strong id<ADMServiceInfo>' from incompatible type 'ADMCoreFactory *'
Does this mean that ADMCoreFactory needs to 'own' the object and my id<ADMServiceInfo> object needs to be a weak reference?
This is the method declaration from the header file:
+ (id<ADMServiceInfo>)newServiceInfoWithURI:(NSString *)anURI;
'__strong id<ADMServiceInfo>' from incompatible type 'ADMCoreFactory *'
This is telling you that ADMCoreFactory does not conform to the ADMServiceInfo protocol, and so you can't assign it to a variable of that type. __strong here is a bit of a red herring. It is technically part of the type, but it's not the important part in this case.
It is possible that you expect +newServiceInfoWithURI: to return some other type than ADMCoreFactory, in which case you have probably incorrectly declared it. Make sure there are no other warnings being issued. You should have no warnings at all in ObjC code.
I'm new to objective c & c. I'm trying to use this random generator c library in an objective c program. My understanding is that objective c is a strict superset of c so this should be possible.
My code compiles and runs but I get a lot of warnings.
warning: implicit declaration of function 'mt_seed32'
warning: implicit declaration of function 'mt_lrand'
warning: Semantic Issue: Implicit declaration of function 'mt_seed32' is invalid in C99
warning: Semantic Issue: Implicit declaration of function 'mt_lrand' is invalid in C99
warning: Semantic Issue: Incompatible integer to pointer conversion initializing uint32_t * (aka unsigned int *) with an expression of type int
I have not imported the C header file to the objective c class - it just finds it. If I import it I get duplicate method errors.
C library header file:
extern void mt_seed32(uint32_t seed);
extern uint32_t mt_lrand(void);
Code to call it: [I've tried calling it with [self method()] but that crashes
mt_seed32(3);
uint32_t *i = mt_lrand();
Can anyone tell me how too get rid of these warnings?
The last compiler error happens because mt_lrand(); returns an int, not a pointer to an int. Therefore, the last line should be
uint32_t i = mt_lrand();
All the other errors are due to the fact that you did not #include the library header. Could you please post the errors that occur when you do include the library header?
Messages such as implicit declaration of function 'mt_seed32' usually pop up, when you use a function before it was defined. See example.
void foo() {
//do stuff
bar(); //call bar that was declared later
}
void bar() {
...
}
This may happen if you forgot to include the header file, or you included it after you used functions declared in that header file. Another fix is to declare a function prototype before usage.
Also you assign your random number to a pointer to uint32_t. Is this what you really want?
If not, then you must remove * from your declaration: uint32_t i = mt_lrand();
Was able to fix my problem by changing file type from '.m' to '.mm'. This causes the compiler to use obj c++ not obj c. It removes the warnings but I'm not sure if I've fixed the underlying issues
Solution – Duplicate Symbol