不同类型 NSArray 的快速枚举

发布于 2024-12-20 20:36:09 字数 373 浏览 1 评论 0 原文

我有这个问题这里(以及有关SO的其他问题),以及有关Objective-C集合和快速枚举的Apple文档。不清楚的是,如果 NSArray 填充了不同的类型,并且创建了一个循环,如下所示:

for ( NSString *string in myArray )
    NSLog( @"%@\n", string );

这里到底发生了什么?循环会跳过任何非 NSString 的内容吗?例如,如果(为了论证)数组中有一个 UIView,那么当循环遇到该项目时会发生什么?

I have this question here (as well other quesrtions on SO), and the Apple docs about Objective-C collections and fast enumeration. What is not made clear is if an NSArray populated with different types, and a loop is created like:

for ( NSString *string in myArray )
    NSLog( @"%@\n", string );

What exactly happens here? Will the loop skip over anything that is not an NSString? For example, if (for the sake of argument) a UIView is in the array, what would happen when the loop encounters that item?

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

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

发布评论

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

评论(5

恏ㄋ傷疤忘ㄋ疼 2024-12-27 20:36:09

你为什么要这么做?我认为这会导致错误和意外行为。如果您的数组填充有不同的元素,请改用:

for (id object in myArray) {
    // Check what kind of class it is
    if ([object isKindOfClass:[UIView class]]) {
       // Do something
    }
    else {
       // Handle accordingly
    }
}

相同

for (id object in myArray) {
    NSString *string = (NSString *)object;
    NSLog(@"%@\n", string);
}

您在示例中所做的实际上与“只是因为您将 object 转换为 (NSString *)” 并不意味着 string 实际上会指向 NSString 对象。这样调用NSLog()会根据- (NSString *)description方法/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/description" rel="noreferrer">NSObject 协议,数组中引用的类可能符合也可能不符合。如果符合,它将打印出来。否则,就会崩溃。

Why would you want to do that? I think that would cause buggy and unintended behavior. If your array is populated with different elements, use this instead:

for (id object in myArray) {
    // Check what kind of class it is
    if ([object isKindOfClass:[UIView class]]) {
       // Do something
    }
    else {
       // Handle accordingly
    }
}

What you are doing in your example is effectively the same as,

for (id object in myArray) {
    NSString *string = (NSString *)object;
    NSLog(@"%@\n", string);
}

Just because you cast object as (NSString *) doesn't mean string will actually be pointing to an NSString object. Calling NSLog() in this way will call the - (NSString *)description method according to the NSObject protocol, which the class being referenced inside the array may or may not conform to. If it conforms, it will print that. Otherwise, it will crash.

薯片软お妹 2024-12-27 20:36:09

你必须明白 obj-c 中的指针没有类型信息。即使你写了NSString*,它也只是一个编译检查。在运行时,一切都只是一个id

Obj-c 运行时从不检查对象是否属于给定类。你可以毫无问题地将 NSNumber 放入 NSString 指针中。仅当您尝试调用未在对象上定义的方法(发送消息)时,才会出现错误。

快速枚举是如何工作的?它完全相同:


for (NSUInteger i = 0; i < myArray.count; i++) {
    NSString* string = [myArray objectAtIndex:i];

    [...]
}

它只是更快,因为它在较低级别上运行。

You have to understand that a pointer in obj-c has no type information. Even if you write NSString*, it's only a compilation check. During runtime, everything is just an id.

Obj-c runtime never checks whether objects are of the given class. You can put NSNumbers into NSString pointers without problems. An error appears only when you try to call a method (send a message) which is not defined on the object.

How does fast enumeration work? It's exactly the same as:


for (NSUInteger i = 0; i < myArray.count; i++) {
    NSString* string = [myArray objectAtIndex:i];

    [...]
}

It's just faster because it operates on lower level.

女皇必胜 2024-12-27 20:36:09

我只是尝试了一个简单的例子...这是我的代码。

NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:1];
NSNumber *number = [NSNumber numberWithInteger:6];
[array addObject:number];
[array addObject:@"Second"];

现在,如果我只是记录该对象,就没有问题了。 NSNumber 实例被转换为 NSString,但这两种方法都响应 -description,所以这不是问题。

for (NSString *string in array)
{
    NSLog(@"%@", string);
}

但是,如果我尝试在 NSString 上记录 -length...

for (NSString *string in array)
{
    NSLog(@"%i", string.length);
}

...它会抛出 NSInvalidArgumentException 因为 NSNumber > 不响应 -length 选择器。长话短说,Objective-C 为您提供了很多帮助。不要用它来吊死自己。

I just tried a quick example... Here is my code.

NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:1];
NSNumber *number = [NSNumber numberWithInteger:6];
[array addObject:number];
[array addObject:@"Second"];

Now if I simply log the object, no problem. The NSNumber instance is being cast as an NSString, but both methods respond to -description, so its not a problem.

for (NSString *string in array)
{
    NSLog(@"%@", string);
}

However, if I attempt to log -length on NSString...

for (NSString *string in array)
{
    NSLog(@"%i", string.length);
}

... it throws an NSInvalidArgumentException because NSNumber doesn't respond to the -length selector. Long story short, Objective-C gives you a lot of rope. Don't hang yourself with it.

待"谢繁草 2024-12-27 20:36:09

有趣的问题。 快速枚举的最通用语法是

for ( NSObject *obj in myArray )
    NSLog( @"%@\n", obj );

我相信,

for ( NSString *string in myArray )
    NSLog( @"%@\n", string );

,通过这样做,您只需将每个对象转换为 NSString 即可。也就是说,我相信上面的内容相当于

for ( NSObject *obj in myArray ) {
    NSString *string = obj;
    NSLog( @"%@\n", string );
}

我在苹果的 快速枚举文档,但您可以查看示例并看看会发生什么。

Interesting question. The most generic syntax for fast enumeration is

for ( NSObject *obj in myArray )
    NSLog( @"%@\n", obj );

I believe that by doing

for ( NSString *string in myArray )
    NSLog( @"%@\n", string );

instead, you are simply casting each object as an NSString. That is, I believe the above is equivalent to

for ( NSObject *obj in myArray ) {
    NSString *string = obj;
    NSLog( @"%@\n", string );
}

I could not find precise mention of this in Apple's documentation for Fast Enumeration, but you can check it on an example and see what happens.

睡美人的小仙女 2024-12-27 20:36:09

由于所有 NSObject 都会响应 isKindOfClass,因此您仍然可以将转换保持在最低限度:

for(NSString *string in myArray) {
    if (![string isKindOfClass:[NSString class]])
        continue;
    // proceed, knowing you have a valid NSString *
    // ...
}

Since all NSObject's respond to isKindOfClass, you could still keep the casting to a minimum:

for(NSString *string in myArray) {
    if (![string isKindOfClass:[NSString class]])
        continue;
    // proceed, knowing you have a valid NSString *
    // ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文