Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 如何定制NSArray的描述?_Objective C_Cocoa_Nsarray - Fatal编程技术网

Objective c 如何定制NSArray的描述?

Objective c 如何定制NSArray的描述?,objective-c,cocoa,nsarray,Objective C,Cocoa,Nsarray,我想为NSArray类的description方法提供我自己的实现,以便我可以像这样简单地使用它: NSLog(@"%@", @[]); 我的想法是为NSArray提供一个类别,并简单地覆盖description方法。但是它不起作用,因为NSArray是一个类集群,它的真正类是\uu NSArrayI,所以我的类别实现从未被调用。不幸的是,我无法为\uu NSArrayI提供类别,因为此类不可用 当然,我可以子类NSArray并在我的子类中实现此方法,但是,由于NSArray是一个类集群,我必

我想为NSArray类的
description
方法提供我自己的实现,以便我可以像这样简单地使用它:

NSLog(@"%@", @[]);
我的想法是为
NSArray
提供一个类别,并简单地覆盖
description
方法。但是它不起作用,因为
NSArray
是一个类集群,它的真正类是
\uu NSArrayI
,所以我的类别实现从未被调用。不幸的是,我无法为
\uu NSArrayI
提供类别,因为此类不可用

当然,我可以子类
NSArray
并在我的子类中实现此方法,但是,由于
NSArray
是一个类集群,我必须为一系列不同的方法提供实现,比如
objectAtIndex:
,我不想这样做,因为这对于简单地改变数组打印到控制台的方式来说太麻烦了

伙计们,你们有什么想法吗?谢谢

伙计们,你们有什么想法吗?谢谢

我们的想法。解决。。。你必须决定

从中可以看出,您不能只关心
说明
。具体来说,从该文件中

Objective-C对象,打印为返回的字符串 descriptionWithLocale:如果可用,或描述其他。阿尔索 使用CFTypeRef对象,返回 CFCopyDescription函数

我们不能对
CFTypeRef
对象做太多的工作,除非我们想使用链接器和/或动态加载程序

然而,我们可以对
description
descriptionWithLocale:
做一些事情,尽管这有点粗糙

您也可以考虑<代码>调试描述> /COD>。 这是一种接近你的目标的方法,虽然我认为它是“教育”的,你应该用你最好的判断来决定你是否想走这条路。 首先,您需要确定替换的

description
实现是什么样子的。我们将声明一个类似于这样的
description
的简单替换(忽略原始实现)

现在,我们如何使
NSArray
实现使用此代码?一种方法是找到
NSArray
的所有子类并替换它们的方法

static void swizzleMethod(Class class, SEL selector, IMP newImp) {
    Method method = class_getInstanceMethod(class, selector);
    if (method) {
        IMP origImp = method_getImplementation(method);
        if (origImp != newImp) {
            method_setImplementation(method, newImp);
        }
    }
}

static void swizzleArrayDescriptions() {
    int numClasses = objc_getClassList(NULL, 0);
    if (numClasses <= 0) return;
    Class *classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * numClasses);
    numClasses = objc_getClassList(classes, numClasses);

    Class target = [NSArray class];
    for (int i = 0; i < numClasses; i++) {
        for (Class c = classes[i]; c; c = class_getSuperclass(c)) {
            if (c == target) {
                c = classes[i];
                swizzleMethod(c, @selector(description), (IMP)swizzledDescription);
                swizzleMethod(c, @selector(descriptionWithLocale:), (IMP)swizzledDescriptionWithLocale);
                break;
            }
        }
    }
    free(classes);
}
现在,你应该能够玩它,看看你如何相处

作为一个非常简单的测试

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Insert code here to initialize your application
    NSArray *array = @[@"One", @"Two", @3, @"4", @"FIVE", @(6.0), @".7.", @8, @9, @10, @"Eleven" ];
    NSLog(@"%@", array);
    NSLog(@"%@", [array mutableCopy]);
}
产生这个输出

2015-11-08 14:30:45.501 TestApp[72183:25861219] Array instance (0x6000000c5780) of type __NSArrayI with 11 elements
0x6000000c5780:  0: One
0x6000000c5780:  1: Two
0x6000000c5780:  2: 3
0x6000000c5780:  3: 4
0x6000000c5780:  4: FIVE
0x6000000c5780:  5: 6
0x6000000c5780:  6: .7.
0x6000000c5780:  7: 8
0x6000000c5780:  8: 9
0x6000000c5780:  9: 10
0x6000000c5780: 10: Eleven
2015-11-08 14:30:45.501 TestApp[72183:25861219] Array instance (0x600000045580) of type __NSArrayM with 11 elements
0x600000045580:  0: One
0x600000045580:  1: Two
0x600000045580:  2: 3
0x600000045580:  3: 4
0x600000045580:  4: FIVE
0x600000045580:  5: 6
0x600000045580:  6: .7.
0x600000045580:  7: 8
0x600000045580:  8: 9
0x600000045580:  9: 10
0x600000045580: 10: Eleven
当然,你应该比我做更多的测试,因为我所做的只是在教堂后整理一下,因为它看起来有点有趣(下雨了,所以野餐取消了)

如果需要调用原始实现,则需要创建原始实现的缓存(按类设置键控),并相应地调用它们。但是,对于这样的情况,如果您想要修改返回的字符串,您可能不需要这样做,而且在任何情况下都应该是直接的

另外,请注意关于swizzling的一般注意事项,在使用类集群时,这些注意事项会更加突出


注意,您也可以这样做,在运行时创建自定义子类。您甚至可以以正常方式将您的子类定义为
NSArray
的直接子类,然后在不影响任何非您的类的情况下切换它们的类型。。。或者一堆不同的东西。。。记住Objective运行时是您的朋友。

您已经大致了解了各种选项和缺点。我认为没有其他选择。我想您可以使用swizzle,但您可能不得不接受不完全覆盖,除非您可以完全覆盖所有类集群成员。请记住NSMutableArray也是一个类群集:)如果您想在特定设计中为特定数组执行此操作,那么可能最简单的方法是编写一个方法/函数,以在数组的所有者(无论是数组的ViewController还是包装器对象)中生成描述,或者在其他一些专门用于描述此集合的特殊类中-(NSString)descripbemyarray:(NSArray)array{…}为什么要提供自定义的
描述
?目标是什么?对于这个问题,可能有一个比将功能附加到基集合类上更好的解决方案。
@implementation AppDelegate

+ (void)initialize {
    if (self == [AppDelegate class]) {
        swizzleArrayDescriptions();
    }
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Insert code here to initialize your application
    NSArray *array = @[@"One", @"Two", @3, @"4", @"FIVE", @(6.0), @".7.", @8, @9, @10, @"Eleven" ];
    NSLog(@"%@", array);
    NSLog(@"%@", [array mutableCopy]);
}
2015-11-08 14:30:45.501 TestApp[72183:25861219] Array instance (0x6000000c5780) of type __NSArrayI with 11 elements
0x6000000c5780:  0: One
0x6000000c5780:  1: Two
0x6000000c5780:  2: 3
0x6000000c5780:  3: 4
0x6000000c5780:  4: FIVE
0x6000000c5780:  5: 6
0x6000000c5780:  6: .7.
0x6000000c5780:  7: 8
0x6000000c5780:  8: 9
0x6000000c5780:  9: 10
0x6000000c5780: 10: Eleven
2015-11-08 14:30:45.501 TestApp[72183:25861219] Array instance (0x600000045580) of type __NSArrayM with 11 elements
0x600000045580:  0: One
0x600000045580:  1: Two
0x600000045580:  2: 3
0x600000045580:  3: 4
0x600000045580:  4: FIVE
0x600000045580:  5: 6
0x600000045580:  6: .7.
0x600000045580:  7: 8
0x600000045580:  8: 9
0x600000045580:  9: 10
0x600000045580: 10: Eleven