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.
Related
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
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?
Assume the following class hierarchy. Class A is publicly declared:
#interface A : NSObject
+ (A)createInstance;
- (void)a;
#end
Class _B is a private subclass of A:
#interface _B : A
- (void)a;
- (void)b;
#end
Assume objects of class A should only be created using the factory method createInstance, which creates and returns an instance of _B.
I want to enhance the functionality of an instance of A on a per-instance basis. So I decided to do some ISA swizzling to achieve:
#interface ExtA : A
- (void)a;
#end
#implementation ExtA
- (void)a
{
NSLog("ExtA_a");
[super a];
}
#end
And I do the ISA swizzling using the following method on an NSObject category (naive implementation shown here):
- (void)changeToSubclass:(Class)cls prefix:(NSString*)prefix suffix:(NSString*)suffix
{
NSString* className = [NSString stringWithFormat:#"%#%#%#", prefix ? prefix : #"", NSStringFromClass(object_getClass(self)), suffix ? suffix : #""];
if([className isEqualToString:NSStringFromClass(object_getClass(self))])
{
className = [NSString stringWithFormat:#"%#(%#)", NSStringFromClass(object_getClass(self)), NSStringFromClass(cls)];
}
Class newSubclass = objc_getClass(className.UTF8String);
if(newSubclass == nil)
{
newSubclass = objc_allocateClassPair(object_getClass(self), className.UTF8String, 0);
objc_registerClassPair(newSubclass);
unsigned int listCount = 0;
Method *list = class_copyMethodList(cls, &listCount);
for(int i = 0; i < listCount; i++)
{
class_addMethod(newSubclass, method_getName(list[i]), method_getImplementation(list[i]), method_getTypeEncoding(list[i]));
}
free(list);
listCount = 0;
list = class_copyMethodList(objc_getMetaClass(class_getName(cls)), &listCount);
for(int i = 0; i < listCount; i++)
{
class_addMethod(objc_getMetaClass(class_getName(newSubclass)), method_getName(list[i]), method_getImplementation(list[i]), method_getTypeEncoding(list[i]));
}
free(list);
}
object_setClass(self, newSubclass);
}
Everything seemingly works, but I noticed that [super a]; does not behave as expected, actually the implementation of -[A a] is called, if if the superclass in runtime is actually _B.
Replacing the call to super with the following code works, but is ugly, and requires knowledge of and work by developers:
struct objc_super superInfo = {
self,
[self superclass]
};
objc_msgSendSuper(&superInfo, #selector(a));
What does the compiler emit when calling super and any way to change this emitted code?
The difference is minor, but important. The compiler is issuing a function call, not to objc_msgSendSuper, but to objc_msgSendSuper2.
What's the difference, you may ask? It's minor, but important.
From apple's open source:
/********************************************************************
*
* id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);
*
* struct objc_super {
* id receiver;
* Class class;
* };
********************************************************************/
ENTRY _objc_msgSendSuper
MESSENGER_START
// search the cache (objc_super in %a1)
movq class(%a1), %r11 // class = objc_super->class
CacheLookup SUPER // calls IMP on success
/* Snipped code for brevity */
/********************************************************************
* id objc_msgSendSuper2
********************************************************************/
ENTRY _objc_msgSendSuper2
MESSENGER_START
// objc_super->class is superclass of class to search
// search the cache (objc_super in %a1)
movq class(%a1), %r11 // cls = objc_super->class
movq 8(%r11), %r11 // cls = class->superclass
CacheLookup SUPER2 // calls IMP on success
For those reading who are unfamiliar with x86_64 assembly, the important line of code is here:
movq 8(%r11), %r11 // cls = class->superclass
What does this do, you may ask? It's fairly simple - instead of the caller passing the superclass to search, the objc_msgSend implementation does it.
However, this important distinction causes one crucial problem - when doing a super call, it does not invoke [self class]. Instead, it uses the class of the current implementation, which is, of course, ExtA.
Therefore, the only way to 'fix' this is to change the superclass of ExtA at run-time, which should cause your method invoking to perform as expected.
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.
I have created a few sprites using a spriteclass and I have loaded them into an array. In my app, I loop over the array checking for particular conditions (position, etc.). I want to create an explosion method that I can pass one of these objects to and then using the pointer pull the position of the object on the screen and show an explosion there. I don't know how to pass the pointer/object that is in my array to the method to be used.
Here is essentially what I had in mind:
for (int i=1; i<4; i++) {
EnemySprite *currentenemy = [enemies objectAtIndex:i-1];
//Blow this guy up
[self explosion:currentenemy]
}
-(void)explosion someobject {
explosion.position = someobject.position
someobject.setHidden=YES;
}
You would write it like this for one param
// definition
-(void) explosion:(EnemySprite*) someObject
{
}
// usage
[self explosion: object];
For two params things are a bit more involved. Consider;
// definition
-(void) explosion:(EnemySprite*) someObject radius:(float)explosionRadius
{
...
if (pos < explosionRadius)
...
}
// usage
[self explosion: object radius:10.0f];
Everything before the : is used for the external name, everything after is the name internal to the function.
This is why you will often see Objective-C functions written with function names that end with the name of the first type:
-(void) explodeSprite:(EnemySprite*) sprite radius:(float)radius;
Both the sprite and radius params then appear to be "named" when the function is written;
[self explodeSprite:sprite radius:10.0f];
Why not make your object the receiver of the explosion?
for (id currentenemy in enemies)
{
[currentenemy explode];
}