casting a block to a void* for dynamic class method resolution - objective-c

+(BOOL)resolveClassMethod:(SEL)aSel {
NSString *lString = NSStringFromSelector(aSel);
if ([self validateLetterAndAccidental:lString]) {
id (^noteFactoryBLOCK)(id) = ^(id aSelf) {
return [self noteWithString:lString];
};
IMP lIMP = imp_implementationWithBlock(noteFactoryBLOCK);
...
I get an error at the last line because noteFactoryBLOCK is cast to a void* and ARC disallows that. Is there currently a way to accomplish what I want? I would like an IMP that I can pass to class_addMethod at runtime.
EDIT
IMP myIMP = imp_implementationWithBlock(objc_unretainedPointer(noteFactoryBLOCK));
This line give me a warning instead of an error - Semantic Issue: Passing 'objc_objectptr_t' (aka 'const void *') to parameter of type 'void *' discards qualifiers

I hate to say it but you might just have to cast away the const in this case.
IMP myIMP = imp_implementationWithBlock((void*)objc_unretainedPointer(noteFactoryBLOCK));
That is pretty ugly though.

Related

How to do objective c style assignments after renaming file to .mm

This code compiles in a .m file, but not in an .mm file:
CFDataRef nativeSocket = CFWriteStreamCopyProperty((CFWriteStreamRef)outputStream, kCFStreamPropertySocketNativeHandle);
CFSocketNativeHandle *sock = (CFSocketNativeHandle *)CFDataGetBytePtr(nativeSocket);
The error message is:
Cannot initialize a variable of type 'CFDataRef' (aka 'const __CFData *') with an rvalue of type 'CFTypeRef' (aka 'const void *')
If I change the type of nativeSocket to CFTypeRef the error message becomes:
Candidate function not viable: cannot convert argument of incomplete type 'CFTypeRef' (aka 'const void *') to 'CFDataRef' (aka 'const __CFData *')
Please tell me how to fix this. I can't seem to guess what to google.
Thanks!
You just need to cast the result from CFWriteStreamCopyProperty() to the proper type:
CFDataRef nativeSocket = (CFDataRef)CFWriteStreamCopyProperty((CFWriteStreamRef)outputStream, kCFStreamPropertySocketNativeHandle);
CFSocketNativeHandle *sock = (CFSocketNativeHandle *)CFDataGetBytePtr(nativeSocket);
It's probably safer to extract the native handle this way, though:
CFSocketNativeHandle sock;
CFDataGetBytes(nativeSocket, CFRangeMake(0, sizeof(sock)), (UInt8*)&sock);
That avoids any issue with the data object's byte pointer being misaligned. Also, it ensures that you don't try to deference the byte pointer implicitly (by doing *sock) after the data object has been released.

Incompatible types casting 'NSString *' to 'CTStringRef *'

I'm just trying to cast NSString* to CTStringRef*
NSString *foobar = #"foobar";
CFStringRef *tmp = (__bridge_retained CFStringRef*)foobar;
Can someone help with this error?
"Incompatible types casting 'NSString *' to 'CTStringRef *' (aka const struct __CFString **)with a __bridge_retained cast"
I've tried with simply __bridge and it don't work either. From the documentation, I think the _retained is the right type I need.
Thanks.
If you look closely at the error message you will see what your problem is. The hint is in this part -
__CFString **
Notice the two * - This means that you are trying to cast to a pointer to a pointer, or in other words a reference to a reference. CTStringRef is already a reference, as implied by the 'Ref' part of the name, so you don't need the * in (__bridge_retained CFStringRef*)
Your code should read
NSString *foobar = #"foobar";
CFStringRef tmp = (__bridge_retained CFStringRef)foobar;

Bad receiver type 'NSUInteger *' (aka 'unsigned int *')

Here is my method createNewRectangleWithHeight and the parameter is heightParam and widthParam. My problem is i can't use the parameter in the method.
I am getting an error something like this
Bad receiver type 'NSUInteger *' (aka 'unsigned int *')
-(BOOL)createNewRectangleWithHeight:(NSUInteger *)heightParam width:(NSUInteger *)widthParam{
if ([[heightParam length] == 0] || [widthParam length]==0]) {
NSLog(#"The height and width must no be 0");
}
}
Error is in if condition
You can only call methods on objects. A pointer to an unsigned int is not an object; it's just the address of a number.
You don't need to pass addresses unless you're changing the value inside your method and you can just check the value rather than treating the number as an object.
-(BOOL)createNewRectangleWithHeight:(NSUInteger)heightParam width:(NSUInteger)widthParam {
if (heightParam == 0 || widthParam == 0) {
NSLog(#"The height and width must not be 0");
}
}
Learn to look at the error messages you get. In this case the error message is telling you exactly what's wrong. The syntax [object message] is sending a message to an object. NSInteger is a scalar type, not an object type.
BTW, your method does not return a result, and is badly named. It should be called something like heightAndWidthAreNotZero.
Others have already pointed out that you should be using (NSUInteger), not (NSUInteger *), as your parameter types. Actually, if you're getting ready to create a CGRect, you should probably be using CGFloat, not NSUInteger, since the different values of a CGRect are CGFloat type.
Finally, there is a built-in system function CGRectIsEmpty() that takes a CGRect as input and returns TRUE if the rectangle is empty, and FALSE if it's not empty.

Casting an (NSString *) to (int *)?

I have an NSString.
NSString *str;
And I need to store it in a struct.
struct {
int *s;
} st;
And set it.
st.s = str;
So, how should I go about retrieving it?
return (__bridge_retained NSString *)st.s;
I've tried the above, and it gives the error: Incompatible types casting 'int *' to 'NSString *' with a __bridge_retained cast.
Answered the question. Simply define the NSString in the struct like this.
struct {
__unsafe_unretained NSString *s;
} st;
Thanks, Carl Veazey!
To store an Objective-C object in an struct you have a couple of options, the one I see most is to store it in the struct as __unsafe_unretained and then maintain a strong reference to it elsewhere.
From the "Common Issues While Converting a Project" section of the ARC Transition Notes:
If using Objective-C objects is sub-optimal, (maybe you want a dense
array of these structs) then consider using a void* instead. This
requires the use of the explicit casts...
They seem to imply __bridge is the way to cast void * to id but are not 100% clear on this.
The other option, which makes more sense to me personally and I've seen more often I think:
Mark the object reference as __unsafe_unretained. ... You declare the
structure as: struct x { NSString * __unsafe_unretained S; int X; }
Hope this helps!

adding methods dynamically

I am trying this method found in Obj-c runtime reference
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
I want to add a new method like:
- [AClass drawWithFrame:(NSRect)rect inView:(id)view]
So far I have written a C function:
void drawWithFrameInView(id this, SEL this_cmd, NSRect frame, id view){
...
}
now I am ready to do:
BOOL success = class_addMethod(NSClassFromString(#"AClass"),
#selector(drawWithFrame:inView:),
(IMP)drawWithFrameInView,
"v#:#:#:");
but success is never YES, I have tried the same approach with methods with simpler signatures and it worked. So I think the problem is last parameter: "v#:#:#:"
What should I pass in this case to get my new method working ?
This will work:
char *types = [[NSString stringWithFormat:#"v#:%s#", #encode(NSRect)] UTF8String];
BOOL success = class_addMethod(NSClassFromString(#"MyClass"),
#selector(drawWithFrame:inView:),
(IMP)drawWithFrameInView,
types);
The reason why your code doesn't work is because NSRect is not an object, it is a typedef to a struct.
Learn more about type encodings here.