ReflectionCzęść NR.6Prawdopodobnie ostatni wpis z tego cyklu. Uczę się Objective-C od dwóch tygodni po godzinach, ale tempo nauki musi zostać jeszcze bardziej zwiększone.

Chociaż być może jeszcze napiszę o rzutowaniu. Podstawy refleksji przydają się na codziennie w programowaniu. Jak więc refleksja wygląda w Objective-C.

Zanim przejdziemy do przykładów oto kod klas z Objective-C użytych w przykładach.

Klasy użyte w przykładach

Objective-C. Interfejsy dwóch klas.

#import <Foundation/Foundation.h>
@class MyOtherObject;

@interface MyObject : NSObject

@property(nonatomic,weak)id delegate;

@property(nonatomic,retain)MyOtherObject* obj;

@end
#import "MyObject.h"
#import "MyOtherObject.h"

@implementation MyObject
-(id)init
{
    self = [super self];
    
    if (self)
    {
        self.obj = [[MyOtherObject alloc]init];
    }
    return self;
}

A teraz ich implementacja.

#import <Foundation/Foundation.h>
#import "MyObject.h"

@interface MyOtherObject : NSObject

-(void) DoSomething;

@property(nonatomic,retain)MyObject* obj;

@end

 

#import "MyOtherObject.h"

@implementation MyOtherObject

-(void)DoSomething {
    NSLog(@"Log");
}

@end

A oto tworzenie ich instancji.

MyObject* myObject = [[MyObject alloc]init];
MyOtherObject* myOtherObject =   myObject.obj;

Type of

TypeOf jest bardzo użytecznym słowem kluczowym. Jak sama nazwa wskazuje zwraca on typ danej klasy.

Type t = typeof(MyClass);
Class c = [MyObject class];

W Objective-C używamy słowa kluczowego “class” zamiast Type. Uzyskujemy dostęp także do statycznej metody tej właśnie klasy.

Type t = myObj.GetType();
Class c2 = myObject.class;

Ponownie nie widać tutaj wielkiej różnicy. W Objective-C odwołaliśmy się do właściwości “class” .

Oto jak wygląda odpowiednik słowa kluczowego “is” w objective-C

bool chceck = myObj is MyClass;
Class c = [MyObject class];
        
Class c2 = myObject.class;
        
BOOL yy = [myObject isKindOfClass:c2];
BOOL yyy = [myOtherObject isKindOfClass:[myOtherObject class]];
        
NSLog(@"1: %s \n2: %s",yy ? "true" : "false",yyy ? "true" : "false");

A jak sprawdzić czy dana klas implementuje dany protokół? Rozwiązanie zagadki poniżej.

bool chceck2 = myObj is IEnumerable<string>;
BOOL hasProtcol = [myObject conformsToProtocol:@protocol(MyDelegate)];

Przejdźmy do bardziej złożonych przykładów.

Wszystkie właściwości danego obiektu

PropertyInfo[] props = myObj.GetType().GetProperties();
foreach(PropertyInfo pi in props)
{
    string actualName = pi.name;
}
unsigned int outCount;
objc_property_t *properties = class_copyPropertyList([myObject class],&outCount);
        
 for(int i = 0; i < outCount;i++)
{
     objc_property_t prop = properties[i];
     const char* name = property_getName(prop);
     NSString* realName = [NSString stringWithUTF8String:name];
     NSLog(realName);
}

Uzyskanie wartości właściwość znając jej nazwę

object val = myObj.GetType().GetProperty("PropertyName").GetValue(myObj, null);
id val = [myObject valueForKey:@"obj"];

Wywołanie metody bez parametrów znając jej nazwę

myObj.GetType().GetMethod("Method").Invoke(myObj);
SEL method = NSSelectorFromString(@"DoSomething");
        
[myOtherObject performSelector:method];

Wywołanie metody w taki sposób jest trochę niebezpieczne. Warto zauważyć, że metoda “DoSomething” nic nie zwraca a ja jak idiota chciałem wynik tej metody przypisać do zmiennej. Niestety, ale wyjątki w Objective-C nie są tak jasne, jak w C# więc trzeba definitywnie myśleć i uważać.