I'm currently learning Objective C and in the process I've made the silly little program below. The program compiles fine - however I get the warning "multiple methods named '-setName:' found".
I've only interfaced and implemented the method once.
What does this warning mean, and how do I correct it?
#import <Foundation/Foundation.h>
// these are the three yoga-exercises we can perform
typedef enum {
kCobra,
kUniversal,
kDog
} ExerciseName;
// translating our variables into human
NSString *nameExercise (ExerciseName nameExercise)
{
switch (nameExercise) {
case kCobra:
return #"Cobra Pose";
break;
case kUniversal:
return #"Universal Stretch";
break;
case kDog:
return #"Dog Pose";
break;
}
return #"no clue!";
} // nameExercise
#interface Exercise : NSObject
{
ExerciseName name;
}
-(void) setName: (ExerciseName) name;
-(void) exerciseDo;
#end
#implementation Exercise
-(void) setName: (ExerciseName) n {
name = n;
} // setName
-(void) exerciseDo {
NSLog(#"Exercise: %#",
nameExercise(name));
}
#end
void executeExercises(id exercises[], int count) {
int i;
for(i=0; i<count; i++) {
id exercise = exercises[i];
[exercise exerciseDo];
}
}
int main (int argc, const char * argv[]) {
id exercises[1];
exercises[0] = [Exercise new]; // initiating an object of class Exercise
[exercises[0] setName:kDog];
executeExercises(exercises, 1);
return 0;
} //main
the meaning of the message is that there are multiple selectors with the name setName: in the translation (that is, it is declared in at least on other place among all included headers). the compiler may choose the wrong selector (which can introduce undefined behavior).
you can typically correct the problem using one (or more) of the following approaches:
1) rename the method to a unique name: e.g. setExerciseName may be ok, if not used in other translations.
2) match the signature of the other selector. e.g. setName:(NSString *)name
3) use type safety:
Exercise * ex = [Exercise new];
[ex setName:kCobra];
4) cast the variable to the type: [(Exercise*)exercise setName:kCobra];
5) restore the type with a new variable: Exercise * ex = exercise;
since you have declared the var as an id, you have erased the type, and it means that the object may respond any visible selector. in general, you should not erase the type in this manner, except when truly necessary.
the best approach i see is a combination of 1 and 3:
[ex setExerciseName:kCobra];
Related
I have a project with a lot of classes.
I want to log (e.g. to stderr) invocations of each selector in runtime.
My main requirement is not to change the existing code, so I can't just log the function's params at the start of each call.
If some method is invoked during program execution, e.g.
#implementation Class1
// ...
- (int)someFunc:(Class2*) a andClass3:(Class3*)b
{
}
// ...
#end
I want to replace it with something like:
- (int)someFuncWrapper:(Class2*) a andClass3:(Class3*)b
{
NSLog(#"- (int)someFuncWrapper:a andClass3:b <= a=%#, ab=%#", a, b);
return [someFunc: a andClass3:b];
}
Is it possible?
I've read of method swizzling, KVO, forward messaging.
My current approach with method swizzling causes infinite recursion:
- (int)funcToSwizzle:(int)a andB:(int)b
{
int r = a+b;
NSLog(#"funcToSwizzle: %d", r);
return r;
}
- (void)doSimpleSwizzling
{
NSLog(#"r1 = %d", [self funcToSwizzle:10 andB:20]);
Class curClass = NSClassFromString(#"HPTracer");
unsigned int methodCount = 0;
Method *methods = class_copyMethodList( curClass, &methodCount);
for (int i=0; i<methodCount; ++i)
{
SEL originalSelector = method_getName(methods[i]);
if ( strcmp("funcToSwizzle:andB:", sel_getName(originalSelector)) == 0 )
{
Method m1 = class_getInstanceMethod(curClass, originalSelector);
id block3 = ^(id self, int a, int b) {
NSLog(#"My block: %d", a*b);
// get current implementation of "funcToSwizzle".
// copy it. store that "IMP"/"void *" etc
return [self funcToSwizzle:a andB:b];
};
IMP imp3 = imp_implementationWithBlock(block3);
method_setImplementation(m1, imp3);
}
}
NSLog(#"r2 = %d", [self funcToSwizzle:10 andB:20]);
}
And I'm afraid it's impossible to generate a block3 or some method in runtime. There's NSSelectorFromString but no ImplementationFromString.
UPD
I looked at DTrace util, it seems very powerful, but doesn't fit my needs.
It requires disabling SIP on Mac OS, and is either impossible on iOS or possible on jailbreaked device.
What I need from methods interceptions is creating a stable custom "framework" for both Debug and production build modes.
I have created a multicast delegate in Objective-C which intercepts a message and then forwards it to multiple children by iterating through a list of children in forwardInvocation. There's quite a bit more complexity but I don't think it's relevant to the question/problem.
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
for (id child in self.children)
{
if ([child respondsToSelector:[anInvocation selector]])
{
[anInvocation invokeWithTarget:child];
}
}
}
This makes total sense for protocols which have void return type but what happens if they return a value?
I saw this problem coming and wrote the following unit test, which passes:
static NSUInteger _callCounter = 0;
#protocol TestProtocol <NSObject>
- (NSUInteger)requiredMethod;
#end
#interface TestClass : NSObject <TestProtocol>
#end
#implementation TestClass
- (NSUInteger)requiredMethod
{
return ++_callCounter;
}
#end
␠
- (void)testCallerOrder
{
_callCounter = 0;
ProtococolMulticaster *multicaster = [[ProtococolMulticaster alloc] initWithProtocol:#protocol(TestProtocol)];
//As the multicaster holds weak references, we need to retain the children
NS_VALID_UNTIL_END_OF_SCOPE NSMutableArray *childReferences = [NSMutableArray array];
for (int i = 0; i < 3; i++)
{
id child = [TestClass new];
[childReferences addObject:child];
[multicaster addChild:child];
}
XCTAssertEqual([(id<TestProtocol>)multicaster requiredMethod], 3);
}
The expectation here is that the 3 children are all called and my static is incremented 3 times and then returned to me by the last child in the array. Because this passed, my conclusion was that it is the last forwardInvocation to be called which gives the return value from [(id<TestProtocol>)multicaster requiredMethod].
Is this assumption correct? Can anyone explain exactly what is happening here? Are there any edge cases that I may have missed which might make this unpredictable?
I wonder is there any drawbacks when use alloc/free with pure C array inside Objective-C class?
For example:
#import "CVPatternGrid.h"
#implementation CVPatternGrid
#synthesize row = _row;
#synthesize column = _column;
#synthesize count = _count;
#synthesize score = _score;
- (id)initWithRow:(NSInteger)row column:(NSInteger)column {
if (self = [super init]) {
_grid = [self allocateNewGrid:row column:column];
}
return self;
}
- (NSInteger)moveCount {
return _count;
}
- (bool**)allocateNewGrid:(NSInteger)row column:(NSInteger)column {
bool **p = malloc(row * sizeof(bool*));
for (int i = 0; i < row; ++i) {
p[i] = malloc(column * sizeof(bool));
}
return p;
}
- (void)generateNewGrid:(NSInteger)row column:(NSInteger)column {
[self freeGrid];
_grid = [self allocateNewGrid:row column:column];
_count = [self.algorithmDelegate generateGrid:_grid];
_score = _count * 100;
}
- (BOOL)isMarkedAtRow:(NSInteger)row column:(NSInteger)column {
return YES;
}
- (void)freeGrid {
for (int i = 0; i < _row; ++i) {
free(_grid[i]);
}
free(_grid);
}
- (void)dealloc {
[self freeGrid];
}
#end
It's perfectly normal to use a C array in an Obj-C class. There are no low level data types in Obj-C — every class, including NSArray, NSString, etc, is using primitive C types internally.
However you are doing a few things wrong:
Do not use #synthesize unless you need to. In this case you don't need it, so delete those lines of code.
Do not use _foo to access variables unless you need it, again in this case you don't need it in any of your use cases (except, arguably, in your init and dealloc methods. But I would argue it should not even be used there. Other people disagree with me). My rule is to only use _foo when I run into performance issues when using self.foo syntax. There are also edge case issues such as KVO where you might run into problems when using an accessor inside init/dealloc. In the real world I have never run into any of those edge cases in more than 10 years of writing Obj-C — I always use accessors, unless they're too slow.
Some implementation details about how to declare an #property of a C array: Objective-C. Property for C array
This is an extension of this queston:
Is it possible to create a category of the "Block" object in Objective-C.
Basically while it seems possible to create a category on blocks, either through NSObject or NSBlock, I'm having trouble understanding how the block would be able to evaluate itself. The example given in the answer to the last question:
- (void) doFoo {
//do something awesome with self, a block
//however, you can't do "self()".
//You'll have to cast it to a block-type variable and use that
}
Implies that it is possible to somehow cast self to a block variable, but how would one execute the block itself? For example, say I did a category on NSBlock and in a method did:
NSBlock* selfAsBlock = (NSBlock*)self;
Is there any message I can send to selfAsBlock to have the block evaluate?
Implies that it is possible to somehow cast self to a block variable
Like this:
- (void)doFoo {
// Assume the block receives an int, returns an int,
// and cast self to the corresponding block type
int (^selfBlock)(int) = (int (^)(int))self;
// Call itself and print the return value
printf("in doFoo: %d\n", selfBlock(42));
}
Note that (in most cases) you need to fix the block signature so that the compiler is able to set up the call site according to the target platform ABI. In the example above, the signature is return type int, single parameter of type int.
A full example is:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#interface Foo : NSObject
- (void)doFoo;
#end
#implementation Foo
- (void)doFoo {
// Assume the block receives an int, returns an int,
// and cast self to the corresponding block type
int (^selfBlock)(int) = (int (^)(int))self;
// Call itself and print the return value
printf("in doFoo: %d\n", selfBlock(42));
}
#end
int main(void) {
[NSAutoreleasePool new];
// From Dave's answer
Method m = class_getInstanceMethod([Foo class], #selector(doFoo));
IMP doFoo = method_getImplementation(m);
const char *type = method_getTypeEncoding(m);
Class nsblock = NSClassFromString(#"NSBlock");
class_addMethod(nsblock, #selector(doFoo), doFoo, type);
// A block that receives an int, returns an int
int (^doubler)(int) = ^int(int someNumber){ return someNumber + someNumber; };
// Call the category method which in turn calls itself (the block)
[doubler doFoo];
return 0;
}
NSBlock has an invoke method that can be used to call the block.
NSBlock* b = ^() { /* do stuff */ };
[b invoke];
Note that this is a private, undocumented method.
In other dynamic languages like ruby, javascript etc. you can do simply this:
switch(someString) {
case "foo":
//do something;
break;
case "bar":
// do something else;
break;
default:
// do something by default;
}
In objective-c, because it's derived very colsely from c language, you can't do that. My best practice for this is:
#import "CaseDemo.h"
#define foo 1
#define bar 2
static NSMutableDictionary * cases;
#implementation CaseDemo
- (id)init
{
self = [super init];
if (self != nil) {
if (cases == nil) {
// this dict can be defined as a class variable
cases = [[NSMutableDictionary alloc] initWithCapacity:2];
[cases setObject:[NSNumber numberWithInt:foo] forKey:#"foo"];
[cases setObject:[NSNumber numberWithInt:bar] forKey:#"bar"];
}
}
return self;
}
- (void) switchFooBar:(NSString *) param {
switch([[cases objectForKey:param] intValue]) {
case foo:
NSLog(#"its foo");
break;
case bar:
NSLog(#"its bar");
break;
default:
NSLog(#"its default");
break;
}
}
#end
It's seems to be ok, but #define makes foo and bar like a reserved word, and I can't use in my code. If I replace define constants with class constants, this problem is fixed, because in other classes I must use MyClassName before the constant name. But how can I minimize the object allocation for this simple task? Someone have a "better practice" for this?
EDIT:
The code below is what I wanted to do, but it's a little bit unconfortable to get the values of the enum or #define. Because I created an application what have just an input where I can write the string to get that hash and go back to xcode and set the values for the enums. So my problem is I can't do that in runtime time, because of the main behavour of switch case statement... Or if I do that with that NSDictionary way -> its have a lot of overhead compared with this solution.
#import "CaseDemo.h"
typedef enum {
foo = 1033772579,
bar = -907719821
} FooBar;
unsigned int APHash(NSString* s)
{
const char* str = [s UTF8String];
unsigned int len = [s length];
unsigned int hash = 0xAAAAAAAA;
unsigned int i = 0;
for(i = 0; i < len; str++, i++)
{
hash ^= ((i & 1) == 0) ? ( (hash << 7) ^ (*str) * (hash >> 3)) :
(~((hash << 11) + ((*str) ^ (hash >> 5))));
}
return hash;
}
#implementation CaseDemo
- (void) switchFooBar:(NSString *) param {
switch(APHash(param)) {
case foo:
NSLog(#"its foo");
break;
case bar:
NSLog(#"its bar");
break;
default:
NSLog(#"its default");
break;
}
}
#end
NOTE: the hash function can defined elsewhere in common namespace to use it anywhere, typically I create a Utils.h or Common.h for this kind of stuff.
NOTE2: In "real word" we need to use some cryptographic hashing function, but now I used the algorithm by Arash Partow to keep the example simple.
So, my final question: Is there a way to evaluate these values with the preprocessor somehow? I think no, but maybe? :-)
Something like:
// !!!!!! I know this code is not working, I don't want comments about "this is wrong" !!!!
// I want a solution to invoke method with preprocessor, or something like that.
typedef enum {
foo = APHash(#"foo"),
bar = APHash(#"bar")
} FooBar;
UPDATE: I found a "maybe solution" but it seems to be work with g++ 4.6> only. generalized constant expressions may be do it for me. But I'm still testing...
typedef enum {
foo,
bar
} FooBar;
- (void) switchFooBar:(NSString *) param {
switch([[cases objectForKey:param] intValue]) {
case foo:
NSLog(#"its foo");
break;
case bar:
NSLog(#"its bar");
break;
default:
NSLog(#"its default");
break;
}
}
NSString * extension = [fileName pathExtension];
NSString * directory = nil;
NSUInteger index = [#[#"txt",#"png",#"caf",#"mp4"] indexOfObjectPassingTest:^
BOOL(id obj, NSUInteger idx, BOOL *stop)
{
return [obj isEqualToString:extension];
}];
switch (index)
{
case 0:
directory = #"texts/";
break;
case 1:
directory = #"images/";
break;
case 2:
directory = #"sounds/";
break;
case 3:
directory = #"videos/";
break;
default:
#throw [NSException exceptionWithName:#"unkonwnFileFormat"
reason:[NSString stringWithFormat:#"zip file contain nknown file format: %#",fileName]
userInfo:nil];
break;
}
The technique is extracted from production code and modified to use colors for this example. The premise is that a string comes in with the text name of a color from some external feed. This inbound color name is matched against known Crayola color names in the system. If the new color name matches any known Crayola color name strings, the numeric value for HTML hex code equivalent of that Crayola color name is returned.
First use http://www.unit-conversion.info/texttools/crc/ and put all of your known Crayola color names through it to get numerical equivalents. These will be used in the case statements. Then put those values into an enumerated for cleanliness (e.g. LivingColors below). These numbers become equivalent to the actual color name string.
Then at run time the variable text is put through the same function, but internal to your code, to generate the same kind of numeric constant. If the numeric constant from the code matches the statically generated constant, then the text strings that they represent are exactly equal.
The internal code function is crc32() found in zlib.h. This generates a unique number based upon the text put through it just like the web page converter above. The unique number from crc32() can then be used in a common C switch() statement to match against the known colors which were pre-processed into numbers into the enumerated.
To use the native system function crc32() to generate CRC32B values, include the /usr/lib/libz.1.dylib in your project for linking. Be sure to include or #import <zlib.h> in your source that references crc32()
Implement an Objective C category on NSString to make the native NSString class understand the crc32: and htmlColor: messages.
Finally, read/get the name of the color into an NSString object, then send the string the htmlColor: message, it switches to match the 'strings' and returns the HTML hex equivalent value for a Crayola color name.
#import <zlib.h>
#define typedefEnum( enumName ) typedef enum enumName enumName; enum enumName
/**
#see Crayola Web Colors https://www.w3schools.com/colors/colors_crayola.asp
#see CRC32B value generator for static case strings http://www.unit-conversion.info/texttools/crc/ or http://www.md5calc.com
*/
#define typedefEnum( enumName ) typedef enum enumName enumName; enum enumName
typedefEnum( LivingColors ) {
kRedColor = 0xc22c196f, // "Red" is 0xED0A3F in HTML
kBlueberryColor = 0xfbefa670, // "Blueberry" is 0x4F86F7 in HTML
kLightChromeGreenColor = 0x44b77242, // "Light Chrome Green" is 0xBEE64B in HTML
kPermanentGeraniumLakeColor = 0xecc4f3e4, // "Permanent Geranium Lake" is 0xE12C2C in HTML
kIlluminatingEmeraldColor = 0x4828d5f2, // "Illuminating Emerald" is 0x319177 in HTML
kWildWatermelonColor = 0x1a17c629, // "Wild Watermelon" is 0xFD5B78 in HTML
kWashTheDogColor = 0xea9fcbe6, // "Wash the Dog" is 0xFED85D in HTML
kNilColor = 0xDEADBEEF // could use '0' but what fun is that?
};
// generates the CRC32B, same used to check each ethernet packet on the network you receive so it’s fast
- (NSUInteger) crc32 {
NSUInteger theResult;
theResult = (NSUInteger)crc32( 0L,
(const unsigned char *) [self UTF8String],
(short)self.length);
return theResult;
}
/// #return the HTML hex value for a recognized color name string.
- (NSUInteger) htmlColor {
NSUInteger theResult = 0x0;
LivingColors theColorInLivingColor = kNilColor;
theColorInLivingColor = (LivingColors) [self crc32];
// return the HTML value for a known color by effectively switching on a string.
switch ( theColorInLivingColor ) {
case kRedColor : {
theResult = 0xED0A3F;
}
break;
case kBlueberryColor : {
theResult = 0x4F86F7;
}
break;
case kLightChromeGreenColor : {
theResult = 0xBEE64B;
}
break;
case kPermanentGeraniumLakeColor : {
theResult = 0xE12C2C;
}
break;
case kIlluminatingEmeraldColor : {
theResult = 0x319177;
}
break;
case kWildWatermelonColor : {
theResult = 0xFD5B78;
}
break;
case kWashTheDogColor : {
theResult = 0xFED85D;
}
break;
case kNilColor :
default : {
theResult = 0x0;
}
break;
}
return theResult;
}
For the example an Objective C Category was made to add the two methods the existing Cocoa class NSString, rather than subclass it.
The end result is that an NSString object appears to have the ability to natively get a CRC32B value of itself (very handy beyond this example) and can essentially switch() on the color’s name string that possibly came in from the user, a text file, etc. to identify a match much faster than any text string comparison can occur.
Fast, efficient, and reliable, this approach can easily be adapted to any kind of variable text matching to static known value text. Bear in mind that CRC32B checksums are generated by bitwise operations and the C switch statement use bitwise operations optimized at compile time. Remember this is speedy because CRC32B is the highly optimized function used to check each ethernet packet your Mac/iPhone/iPad receives... even when you download multi-gigabyte files like macOS Sierra.