iPhone:使用反射替换函数

发布于 2024-12-25 10:53:06 字数 910 浏览 3 评论 0原文

我有一个小函数要重写,以便该函数对每个类都有效。 目前我有 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都是来自两个不同类的 NSMutableArray。 是否可以查看一个类是否包含 NSMutableArray,如果是,那么它应该调用 .... modelObject.MyMutableArray?

I have a small function which I want to rewrite, so that function is valid for every class.
At the moment I have 10 of the same functions which all work same but every function is for another class.
I know, that I have to do it with reflections, but I am not so sure how to do it.
I already read this link:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html

The functions I am talking about are:

-(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 and DamageAccountList are both NSMutableArrays from two different classes.
Is it possible to see if a class consists a NSMutableArray and if yes then it should call the .... modelObject.MyMutableArray?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我的黑色迷你裙 2025-01-01 10:53:06

您可以像这样使用反射:

- (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

You can use reflection like this:

- (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]];
}

But a more common technique among cocoa programmers would be:

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

Where you would accept any object which confirms to the protocol MyCustomProtocol. The protocol is defined in a header files somewhere, using:

@protocol MyCustomProtocol

@property (readonly) NSArray *missionArray;

@end

And then in each of your classes, declare it as implementing the protocol:

@interface MissionSectionListClass <MyCustomProtocol>

And add a method implementation:

@implementation MissionSectionListClass <MyCustomProtocol>

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

@end

Using protocols is a bit more code, but it's the "right" way to go. It allows you to add support for new classes, without any change to your MissiongGet... method.

More info about protocols: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProtocols.html

素食主义者 2025-01-01 10:53:06

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

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

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

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

@property (nonatomic, retain) NSMutableArray * list;

然后在 ..MissionGetReferencedNested 方法中:

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

如果我错了,请纠正我...

EDIT : Cleared all my answer to this :

I think it's not possible to check if a class has a member variable of specified type. You can only check if a class has a specified method.

So, in this case it will be best if you make all your NSMutableArray list the same name, and then create a declared property for this list, and then do a respondsToSelector in your ...GetReferencedNested method.

So, for example, in all of your class create this property :

@property (nonatomic, retain) NSMutableArray * list;

and then in the ..MissionGetReferencedNested method :

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

Correct me if i'm wrong...

谁对谁错谁最难过 2025-01-01 10:53:06

在风格方面我也会遵循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

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

In terms of style I'd also follow Abhi's suggestion.

But if you really want to inspect a class that you are stuck with and, for example build a NSCountedSet with the first NSMutableArray variable you can find, you could do it like this:

#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

Of course this has very limited real world use because it depends on you knowing that the first array will be the one you're interested in.

慵挽 2025-01-01 10:53:06

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

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

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

I think I have to go with the runtime type editing.(http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html)

The idea with the protocols was good but there I have to change a lot of things in the classes.(which is not possible/allowed) for me. My intension was only to change the functions so that I have only one function for all classes.

I think with the runtime type editing I can check what classes and attributes I have (?) Am I right?
Did somebody already work with runtime type editing?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文