2

我有一个要重写的小函数,因此该函数对每个类都有效。目前我有 10 个相同的功能,它们都工作相同,但每个功能都用于另一个类。我知道,我必须通过反射来做到这一点,但我不太确定该怎么做。我已经阅读了这个链接:http: //developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html

我正在谈论的功能是:

-(NSCountedSet *)MissionGetReferecedNested:(id)modelObject
{
    setOfObjects = [[NSCountedSet alloc]initWithArray:modelObject.MissionSectionList];
    return setOfObjects;
}
-(NSCountedSet *)MissionGetSectionReferecedNested:(id)modelObject
{
    setOfObjects = [[NSCountedSet alloc]initWithArray:modelObject.DamageAccountList];
    return setOfObjects;
}

MissionSectionList 和 DamageAccountList 都是来自两个不同类的 NSMutableArrays。是否可以查看一个类是否包含 NSMutableArray,如果是,那么它应该调用 ....modelObject.MyMutableArray?

4

4 回答 4

2

您可以像这样使用反射:

- (NSCountedSet *)MissionGet:(id)modelObject
{
    SEL propertySelector = NULL;

    if ([modelObject respondsToSelector:@selector(MissionSectionList)]) {
        propertySelector = @selector(MissionSectionList);
    } else if ([modelObject respondsToSelector:@selector(DamageAccountList)]) {
        propertySelector = @selector(DamageAccountList);
    }

    if (!propertySelector) {
      [NSException raise:@"Invalid modelObject value" format:@"Model object %@ does not contain any recognised selectors", modelObject];
    }

    return [[NSCountedSet alloc] initWithArray:[modelObject performSelector:propertySelector]];
}

但可可程序员中更常见的技术是:

- (NSCountedSet *)MissionGet:(id <MyCustomProtocol>)modelObject
{
    return [[NSCountedSet alloc] initWithArray:[modelObject missionArray]];
}

您将在哪里接受任何符合协议的对象MyCustomProtocol。该协议在某处的头文件中定义,使用:

@protocol MyCustomProtocol

@property (readonly) NSArray *missionArray;

@end

然后在您的每个类中,将其声明为实现协议:

@interface MissionSectionListClass <MyCustomProtocol>

并添加一个方法实现:

@implementation MissionSectionListClass <MyCustomProtocol>

- (NSArray *)missionArray
{
    return self.MissionSectionList;
}

@end

使用协议需要更多代码,但这是“正确”的方式。它允许您添加对新类的支持,而无需更改您的MissiongGet...方法。

有关协议的更多信息:http: //developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProtocols.html

于 2012-01-08T17:50:14.170 回答
0

编辑:清除了我对此的所有答案:

我认为不可能检查一个类是否具有指定类型的成员变量。您只能检查一个类是否具有指定的方法。

因此,在这种情况下,最好将所有 NSMutableArray 列表命名为相同名称,然后为该列表创建声明的属性,然后在 ...GetReferencedNested 方法中执行 respondsToSelector。

因此,例如,在您的所有班级中创建此属性:

@property (nonatomic, retain) NSMutableArray * list;

然后在 ..MissionGetReferencedNested 方法中:

if ([modelObject respondsToSelector:@selector(list)])
    ...

如我错了请纠正我...

于 2012-01-08T16:25:32.450 回答
0

在风格方面,我也会遵循 Abhi 的建议。

但是如果你真的想检查一个你坚持使用的类,例如用你能找到的第一个 NSMutableArray 变量构建一个 NSCountedSet,你可以这样做:

#import "Utilities.h"
#import <Foundation/Foundation.h>
#import <objc/objc-runtime.h>

@implementation Utilities

+ (NSCountedSet*)initCountedSetWithFirstArrayinObject:(id)someObject {

    unsigned int c;

    Ivar *ivar_arr = class_copyIvarList([someObject class], &c);

    for (unsigned int i = 0; i < c; i++) {
        if ([@"@\"NSMutableArray\"" isEqualToString:
             [NSString stringWithCString:ivar_getTypeEncoding(ivar_arr[i]) encoding:NSUTF8StringEncoding]
             ]) {
             return [[NSCountedSet alloc] initWithArray:object_getIvar(someObject, ivar_arr[i])];
        }
    }

    return nil;
}

@end

当然,这在现实世界中的用途非常有限,因为它取决于您是否知道第一个数组将是您感兴趣的数组。

于 2012-01-08T18:33:28.110 回答
0

我想我必须使用运行时类型编辑。(http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html)

协议的想法很好,但是我必须在类中更改很多东西。(这是不可能/不允许的)对我来说。我的意图只是改变功能,以便我对所有类只有一个功能。

我认为通过运行时类型编辑,我可以检查我有哪些类和属性(?)对吗?有人已经使用运行时类型编辑了吗?

于 2012-01-09T08:44:11.853 回答