日々精進

新しく学んだことを書き留めていきます

performSelectorの戻り値にクラスクラスタを期待している場合

たとえば、performSelectorの戻り値としてNSNumberかNSDateが返る場合

            NSObject *property1 = [obj1 performSelector:@selector(objectWithStockAttribute:) withObject:sortByStockAttribute];
            NSObject *property2 = [obj2 performSelector:@selector(objectWithStockAttribute:) withObject:sortByStockAttribute];

上記のコードで戻り値を取得できるが、取得したオブジェクトの型はクラスクラスタではなく実クラスになっている。
NSNumberの場合だとNSCFNumberになっていたりする。


そうすると、以下のように取得したオブジェクトに対してクラスクラスタで定義されているメソッドを呼ぶとEXC_BAD_ACCESSになる。

NSObject *comparisonResult = [property1 performSelector:@selector(compare:) withObject:property2];

こういう場合はcompare:を呼ぶ前にisKindOfClassなどを使って実クラスを特定し、適切にキャストしてやらないといけない。例は以下。

- (NSComparisonResult)compareWithProperty1:(NSObject *)property1 property2:(NSObject *)property2 {
    if ([property1 isKindOfClass:[NSNumber class]]){
        NSNumber *num1 = (NSNumber *)property1;
        NSNumber *num2 = (NSNumber *)property2;
        return (enum _NSComparisonResult)[num1 compare:num2];
    } else if ([property1 isKindOfClass:[NSDate class]]){
        NSDate *date1 = (NSDate *)property1;
        NSDate *date2 = (NSDate *)property2;
        return (enum _NSComparisonResult)[date1 compare:date2];
    } else if ([property1 isKindOfClass:[NSString class]]){
        NSString *string1 = (NSString *)property1;
        NSString *string2 = (NSString *)property2;
        return (enum _NSComparisonResult)[string1 compare:string2];
    } else {
        [NSException raise:@"IllegalClassException" format:@"%@ class is not expected.", NSStringFromClass([property1 class])];
    }
}