How can I know whether an instance implements a method in Objective-C? - objective-c

I would like to know if an instance implements a specific method. I could use respondsToSelector: but it returns YES if the instance inherits the method...
I could loop through the methods of class_copyMethodList(), but since I might want to check a lot of instances, I wanted to know if there was a simpler solution (like repondsToSelector:, but restricted to the class itself...)
edit: since I really think there is no function or method doing that, I wrote mine. Thanks for your answers, here is the method if it can be of any use :
+ (BOOL)class:(Class)aClass implementsSelector:(SEL)aSelector
{
Method *methods;
unsigned int count;
unsigned int i;
methods = class_copyMethodList(aClass, &count);
BOOL implementsSelector = NO;
for (i = 0; i < count; i++) {
if (sel_isEqual(method_getName(methods[i]), aSelector)) {
implementsSelector = YES;
break;
}
}
free(methods);
return implementsSelector;
}

It's probably easier to check whether the method your own class returns is the same or different than the method your superclass returns.
if ([[obj class] instanceMethodForSelector:sel] != [[obj superclass] instanceMethodForSelector:sel]) {
NSLog(#"%# directly implements %#", [obj class], NSStringFromSelector(sel));
}

instance responds and super does not:
-(BOOL) declaresSelector:(SEL)inSelector {
return [self respondsToSelector:inSelector] && ![super respondsToSelector:inSelector];
}
instance responds and is different than super:
-(BOOL) implementsSelector:(SEL)inSelector {
return [self respondsToSelector:inSelector] && !( [super respondsToSelector:inSelector] && [self methodForSelector:inSelector] == [super methodForSelector:inSelector] );
}
According to Apple documents you should call respondsToSelector before methodForSelector.

You can use reflection to do that.

Related

Call original class method when called from child

I have a class A. B inherits A. Both classes implement method1 and method2.
method1 in A calls method2. It look like...
- (void)method1{
// some code
[self method2];
// some code
}
- (void)method2{
// some work
}
method1 in B calls super class method 1, and B also overrides method2.
- (void)method1{
[super method1];
}
- (void)method2{
// some work
}
Now, when B's instance is created and called method1 A's method1 calls method2 in B. What I want to do is calling A's method2 from A's method1 even when it is called from child(B).
In other words, in A's method1, I want to "forcefully" call the method in the same owner(class).
Is there any easy way to do it? I think I can do it with calling objective-c runtime functions but I want to know if there is easier way.
I know that this is not the design we should make in usual case, but from a little complex reason I have to do it. So please don't propose me to change the design or ask me what is the original goal of the program.
As a simplest solution I can come up with, use BOOL flag to decide how method2 should behave:
#interface B ()
#property (nonatomic) BOOL shouldCallSuperMethod2;
#end
#implementation B
- (void)method1{
self.shouldCallSuperMethod2 = YES;
[super method1];
self.shouldCallSuperMethod2 = NO;
}
- (void)method2{
if (self.shouldCallSuperMethod2) {
[super method2];
}
else {
// some work
}
}
#end
Note that this solution is not thread safe.
UPD Another interesting way, using runtime magic:
#import ObjectiveC.runtime;
#implementation B
- (void)method2 {
NSUInteger returnAddress = (NSUInteger)__builtin_return_address(0);
NSUInteger callerIMPAddress = 0;
SEL interestingSelector = #selector(method1);
// Iterate over the class and all superclasses
Class currentClass = object_getClass(self);
while (currentClass)
{
// Iterate over all instance methods for this class
unsigned int methodCount;
Method *methodList = class_copyMethodList(currentClass, &methodCount);
unsigned int i;
for (i = 0; i < methodCount; i++)
{
// Ignore methods with different selectors
if (method_getName(methodList[i]) != interestingSelector)
{
continue;
}
// If this address is closer, use it instead
NSUInteger address = (NSUInteger)method_getImplementation(methodList[i]);
if (address < returnAddress && address > callerIMPAddress)
{
callerIMPAddress = address;
}
}
free(methodList);
currentClass = class_getSuperclass(currentClass);
}
if (callerIMPAddress == (NSUInteger)[self methodForSelector:interestingSelector]) {
// method2 is called from method1, call super instead
[super method2];
}
else {
// some work
}
}
#end
Other interesting ways to identify caller may be found in answers to this question

Why does my superclass object call its subclass method?

I have seen so many helpful threads here, but this is my first time posting!
I was working on the infamous Stanford OpenCourse project: Matchismo. While I got everything going just fine, but I don't understand one part of the sample codes.
Basically the code below is used to get a Card object to compare with another card.
- (void) flipCardAtIndex: (NSUInteger)index
{
Card *card = [self cardAtIndex:index];
if (card && !card.isUnplayable)
{
if (!card.isFaceUp)
{
for (Card* otherCard in self.cards)//for-in loop
{
if (otherCard.isFaceUp && !otherCard.isUnplayable)
{
int matchScore = [card match:#[otherCard]];
......
And this is how cardAtIndex works:
-(Card *) cardAtIndex:(NSUInteger)index
{
if (index < [self.cards count])
//dot notation is used for property
//[] is used for method
{
return self.cards[index];
}
return nil;
}
Here are the methods for Match(card*) and Match(playingCard)
Match(card*)
-(int) match:(NSArray *)otherCards
{
NSLog(#"here");
int score = 0;
for (Card *card in otherCards)
{
if ([card.content isEqualToString:self.content])
score = 1;
{
NSLog(#"Card Match");
}
}
return score;
}
Match(PlayingCard*)
-(int) match: (NSArray *)otherCards;
{
int score = 0;
if ([otherCards count] == 1)
{
PlayingCard *otherCard = [otherCards lastObject];//the last object in the array
if ([otherCard.suit isEqualToString:self.suit])
score = 1;
else if (otherCard.rank == self.rank)
score = 4;
NSLog(#"PlayingCard Match");
}
return score;
}
It worked just fine, but I don't get why when a Card* object calls a method, its subclass's PlayingCard's method is invoked.
Thanks so much for help me!
This concept is called Polymorphism.
It allows you to have a base class which provides some interface, and a set of subclasses that implement these methods in some different ways. The classic example is a Drawable class method draw, and its subclasses Circle and Rectangle, that both override the draw method to render themselves in some specific manner.
So goes for your Card base class, it calls its own interface method match, but as an object is actually not an instance of Card, but of a PlayingCard subclass, subclass method gets called instead to provide specific implementation.
In your view controller .m file, the property "deck" must be initialized as class PlayingCardDeck, and in PlayingCardDeck.m, the class of card is PalyingCard. So even though you declared your card as class Card, the method it calls will still be the one in class PlayingCard.

Refactoring similar methods for objective C

How do I refactor similar methods for the following (Objective C)?
- (void)insertNewSong:(Song *)newSong forArtist:(Artist *)artist {
NSMutableArray *newSongList = [[artist songs] mutableCopy];
BOOL hasInserted = NO;
for (int i = 0; i < [[artist songs] count]; i++) {
Song *existingSong = [[artist songs] objectAtIndex:i];
if ([[newSong title] caseInsensitiveCompare:[existingSong title]] == NSOrderedAscending) {
[newSongList insertObject:newSong atIndex:i];
hasInserted = YES;
break;
}
}
if (hasInserted == NO) {
[newSongList addObject:newSong];
}
artist.songs = newSongList;
}
- (void)insertNewArtistToSongList:(Artist *)newArtist {
BOOL hasInserted = NO;
for (int i = 0; i < [_artists count]; i++) {
Artist *existingArtist = [_artists objectAtIndex:i];
if ([[newArtist name] caseInsensitiveCompare:[existingArtist name]] == NSOrderedAscending) {
[_artists insertObject:newArtist atIndex:i];
hasInserted = YES;
break;
}
}
if (hasInserted == NO) {
[_artists addObject:newArtist];
}
}
For the insertNewSong method, a NSMutableArray [artist songs] containing each Song object is used.
For the insertNewArtist method, a NSMutableArray instance variable _artists containing each Artist Object is used.
Both methods insert an object into an NSMutableArray by comparing the text property of the input object against the text property found within the arrays.
Currently the above methods contain some duplication but is easy to understand (in my case). I was thinking whether there might be a way of simplifying it into a more general method, and does not hurt readability?
There is no general rule, but here are some general rules:
Sometimes it makes sense to combine code like this, sometimes not. Lots of pluses/minuses.
Sometimes it's best to abstract PART of the operation, and leave the other part custom.
Generally, if you have a lot of "if thingA then do this, else that" logic, you've done it wrong (or should not do it at all).
It's best when you can write a single routine and just pass in different parameters (that aren't simply Boolean switches) to differentiate the multiple cases.
It's hard.
And, as a general rule, I don't try too hard to abstract until I have the third instance of nearly the same logic.
(Generally speaking.)

Invalid Initializer for CGPoint

Hey I have a bit of code that keeps returning an error message, but i can't figure out what the problem is. I am fairly new to Objective-c syntax so it could be something fairly simple, however i can not seem to find the problem. The method is
-(void)setPlayerPosition:(CGPoint) position {
CGPoint tileCoord = [self tileCoordForPosition:position];
int tileGid = [metaLayer tileGIDAt:tileCoord];
if (tileGid) {
NSDictionary *properties = [tileMap propertiesForGID:tileGid];
if (properties) {
NSString *collision = [properties valueForKey:#"Collidable"];
if (collision && [collision compare:#"True"] == NSOrderedSame) {
return;
}
NSString *collectable = [properties valueForKey:#"Collectable"];
if (collectable && [collectable compare:#"True"] == NSOrderedSame) {
[metaLayer removeTileAt:tileCoord];
[foreground removeTileAt:tileCoord];
}
}
}
player.position = position;
}
It returns the error Invalid initializer for the 2nd line and also says that my class may not respond to 'tileCoordForPosition:' Any help would be appreciated!
I assume you are following the article at http://www.raywenderlich.com/1186/collisions-and-collectables-how-to-make-a-tile-based-game-with-cocos2d-part-2
So after briefly reading it myself, my guess is you are either missing the method required or are not declaring it properly in your class.
You should have the following method declared and implemented
- (CGPoint)tileCoordForPosition:(CGPoint)position
And it should be in the same class as where you call it on self
[self tileCoordForPosition:position]
If you do have that method implemented in your class then make sure you are declaring it correctly too. Try adding it to the top of your .m file like so
#interface YourControllerNameHere()
- (CGPoint)tileCoordForPosition:(CGPoint)position;
#end
You need to declare tileCoordForPosition: in your header so the compiler knows what type it returns (in this case, a CGPoint).

OCMock: Make a stub do something

I'm getting used to OCMock. Coming from a Java/JMock background I'm now looking for the ability to say [[[myMock stub] returnValueFromCustomMethod] someMockedMethod]; where returnValueFromCustomMethod is defined in the test class. I was originally thinking something along the terms of [[[myMock stub] usingSelector:#selector(myMethod:)] someMockedMethod]; but after writing I wonder if my first approach makes more sense. Either way, could someone show me if and how this can be done?
My original answer was off-track: OCMock doesn't support this! If you wanted to change OCMock to support this, you would need to do something like adding a BOOL returnValueIsFromInvocation field to OCMockRecorder, and add a method to set this up:
- (id)andReturnResultOfInvocation:(NSInvocation *)anInvocation {
returnValueIsFromInvocation = YES;
returnValueIsBoxed = NO;
returnValueShouldBeThrown = NO;
[returnValue autorelease];
returnValue = [anInvocation retain];
return self;
}
Then teach setUpReturnValue to call the invocation (changes are in bold):
- (void)setUpReturnValue:(NSInvocation *)anInvocation
{
if (returnValueIsFromInvocation) {
NSInvocation *returnValueInvocation = (NSInvocation *)returnValue;
[returnValueInvocation invoke];
void *buffer = malloc([[anInvocation methodSignature] methodReturnLength]);
[returnValueInvocation getValue:buffer];
[anInvocation setReturnValue:buffer];
free(buffer);
}
else if(returnValueShouldBeThrown)
{
#throw returnValue;
}
else if(returnValueIsBoxed)
{
if(strcmp([[anInvocation methodSignature] methodReturnType],
[(NSValue *)returnValue objCType]) != 0)
[NSException raise:NSInvalidArgumentException
format:#"Return value does not match method signature."];
void *buffer = malloc([[anInvocation methodSignature] methodReturnLength]);
[returnValue getValue:buffer];
[anInvocation setReturnValue:buffer];
free(buffer);
}
else
{
const char *returnType = [[anInvocation methodSignature] methodReturnType];
const char *returnTypeWithoutQualifiers = returnType + (strlen(returnType) - 1);
if(strcmp(returnTypeWithoutQualifiers, #encode(id)) == 0)
[anInvocation setReturnValue:&returnValue];
}
}
This change is difficult to do by introducing subclasses because you have to override the methods that return OCMockRecorders (like stub, expect and so on) but the concrete subclasses of OCMockObject (OCClassMockObject and OCProtocolMockObject) are hidden by the framework.