NSMutableArray - 强制数组只保存特定的对象类型 [英] NSMutableArray - force the array to hold specific object type only

查看:25
本文介绍了NSMutableArray - 强制数组只保存特定的对象类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法强制 NSMutableArray 只保存一种特定的对象类型?

我的类定义如下:

@interface Wheel:NSObject{整数大小;浮子直径;}@结尾@接口车:NSObject{NSString *模型;NSString *make;NSMutableArray *wheels;}@结尾

如何强制 wheels 数组仅使用代码保存 Wheel 对象?(绝对不是其他对象)

解决方案

2015年更新

这个答案最初写于 2011 年初,开始于:

<块引用>

我们真正想要的是参数多态性,这样你就可以声明,比如,NSMutableArray;但可惜没有.

在 2015 年,Apple 显然改变了这一点,将轻量级泛型"引入 Objective-C,现在您可以声明:

NSMutableArray*onlyStrings = [NSMutableArray 新];

但一切都不是看起来的那样,注意轻量级"...然后注意上述声明的初始化部分不包含任何通用符号.虽然 Apple 引入了参数集合,并直接向上述数组添加了一个非字符串,onlyStrings,如:

[onlyStrings addObject:@666];//<- 警告:不兼容的指针类型...

将按照指示非法警告,类型安全性只是肤浅的.考虑方法:

- (void) push:(id)obj 到:(NSMutableArray *)array{[数组添加对象:对象];}

以及同一个类的另一个方法中的代码片段:

NSMutableArray*oops = [NSMutableArray 新];[self push:@"asda" on:oops];//添加一个字符串,很好[self push:@42 on:oops];//添加一个数字,没有警告...

Apple 实现的本质上是一个提示系统,以协助与 Swift 的自动互操作,它确实具有类型安全泛型的味道.然而,在 Objective-C 方面,虽然编译器提供了一些额外的提示,但系统是轻量级的",类型完整性最终仍然取决于程序员——就像 Objective-C 的方式一样.

那么你应该使用哪个?新的轻量级/伪泛型,还是为您的代码设计自己的模式?确实没有正确的答案,找出在您的场景中有意义的内容并使用它.

例如:如果你的目标是与 Swift 的互操作,你应该使用轻量级泛型!但是,如果集合的类型完整性在您的场景中很重要,那么您可以将轻量级泛型与您自己在 Objective-C 端的代码结合起来,这会强制 Swift 在其端的类型完整性.

2011 年答案的剩余部分

这里的另一个选项是 NSMutableArray 的快速通用子类,您可以使用单态数组中所需的对象类型对其进行初始化.这个选项不会给你静态类型检查(就像你在 Obj-C 中得到的一样多),你会在插入错误类型时得到运行时异常,就像你得到索引越界等的运行时异常一样.

没有经过彻底测试,并假设有关覆盖 NSMutableArray 的文档是正确的...

@interface MonomorphicArray : NSMutableArray{类元素类;NSMutableArray *realArray;}- (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems;- (id) initWithClass:(Class) 元素;@结尾

和实现:

@implementation MonomorphicArray- (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems{元素类 = 元素;realArray = [NSMutableArray arrayWithCapacity:numItems];回归自我;}- (id) initWithClass:(Class) 元素{元素类 = 元素;realArray = [NSMutableArray 新];回归自我;}//覆盖原始的 NSMutableArray 方法并强制执行单态- (void) insertObject:(id)anObject atIndex:(NSUInteger)index{if ([anObject isKindOfClass:elementClass])//允许子类,使用 isMemeberOfClass 进行精确匹配{[realArray insertObject:anObject atIndex:index];}别的{NSException* myException = [NSExceptionexceptionWithName:@"InvalidAddObject"原因:@"添加的对象类型错误"用户信息:无];@throw myException;}}- (void) removeObjectAtIndex:(NSUInteger)index{[realArray removeObjectAtIndex:index];}//覆盖原始 NSArray 方法- (NSUInteger) 计数{返回 [realArray 计数];}- (id) objectAtIndex:(NSUInteger)index{返回 [realArray objectAtIndex:index];}//阻止所有其他 init(可能支持一些)静态 ID NotSupported(){NSException* myException = [NSExceptionexceptionWithName:@"InvalidInitializer"原因:@"仅支持 initWithClass: 和 initWithClass:andCapacity:"用户信息:无];@throw myException;}- (id)initWithArray:(NSArray *)anArray { return NotSupported();}- (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag { return NotSupported();}- (id)initWithContentsOfFile:(NSString *)aPath { return NotSupported();}- (id)initWithContentsOfURL:(NSURL *)aURL { return NotSupported();}- (id)initWithObjects:(id)firstObj, ... { return NotSupported();}- (id)initWithObjects:(const id *)objects count:(NSUInteger)count { return NotSupported();}@结尾

用作:

MonomorphicArray *monoString = [[MonomorphicArray alloc] initWithClass:[NSString class] andCapacity:3];[monoString addObject:@"一个字符串"];[monoString addObject:[NSNumber numberWithInt:42]];//会抛出[monoString addObject:@"另一个字符串"];

Is there a way to force NSMutableArray to hold one specific object type only?

I have classes definitions as follow:

@interface Wheel:NSObject  
{    
  int size;  
  float diameter;  
}  
@end  


@interface Car:NSObject  
{  
   NSString *model;  
   NSString *make;  
   NSMutableArray *wheels;  
}  
@end

How can I force wheels array to hold Wheel objects only with code? (and absolutely not other objects)

解决方案

Update in 2015

This answer was first written in early 2011 and began:

What we really want is parametric polymorphism so you could declare, say, NSMutableArray<NSString>; but alas such is not available.

In 2015 Apple apparently changed this with the introduction of "lightweight generics" into Objective-C and now you can declare:

NSMutableArray<NSString *> *onlyStrings = [NSMutableArray new];

But all is not quite what it seems, notice the "lightweight"... Then notice that the initialisation part of the above declaration does not contain any generic notation. While Apple have introduced parametric collections, and adding a non-string directly to the above array, onlyStrings, as in say:

[onlyStrings addObject:@666]; // <- Warning: Incompatible pointer types...

will illicit the warning as indicated, the type security is barely skin deep. Consider the method:

- (void) push:(id)obj onto:(NSMutableArray *)array
{
   [array addObject:obj];
}

and the code fragment in another method of the same class:

NSMutableArray<NSString *> *oops = [NSMutableArray new];
[self push:@"asda" onto:oops]; // add a string, fine
[self push:@42 onto:oops];     // add a number, no warnings...

What Apple have implemented is essentially a hinting system to assist with automatic inter-operation with Swift, which does have a flavour of type-safe generics. However on the Objective-C side, while the compiler provides some extra hints the system is "lightweight" and type-integrity is still ultimately down to the programmer - as is the Objective-C way.

So which should you use? The new lightweight/pseudo generics, or devise your own patterns for your code? There really is no right answer, figure out what makes sense in your scenario and use it.

For example: If you are targeting interoperation with Swift you should use the lightweight generics! However if the type integrity of a collection is important in your scenario then you could combine the lightweight generics with your own code on the Objective-C side which enforces the type integrity that Swift will on its side.

The Remainder of the 2011 Answer

As another option here is a quick general subclass of NSMutableArray which you init with the kind of object you want in your monomorphic array. This option does not give you static type-checking (in as much as you ever get it in Obj-C), you get runtime exceptions on inserting the wrong type, just as you get runtime exceptions for index out of bounds etc.

This is not thoroughly tested and assumes the documentation on overriding NSMutableArray is correct...

@interface MonomorphicArray : NSMutableArray
{
    Class elementClass;
    NSMutableArray *realArray;
}

- (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems;
- (id) initWithClass:(Class)element;

@end

And the implementation:

@implementation MonomorphicArray

- (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems
{
    elementClass = element;
    realArray = [NSMutableArray arrayWithCapacity:numItems];
    return self;
}

- (id) initWithClass:(Class)element
{
    elementClass = element;
    realArray = [NSMutableArray new];
    return self;
}

// override primitive NSMutableArray methods and enforce monomorphism

- (void) insertObject:(id)anObject atIndex:(NSUInteger)index
{
    if ([anObject isKindOfClass:elementClass]) // allows subclasses, use isMemeberOfClass for exact match
    {
        [realArray insertObject:anObject atIndex:index];
    }
    else
    {
        NSException* myException = [NSException
            exceptionWithName:@"InvalidAddObject"
            reason:@"Added object has wrong type"
            userInfo:nil];
        @throw myException;
    }
}

- (void) removeObjectAtIndex:(NSUInteger)index
{
    [realArray removeObjectAtIndex:index];
}

// override primitive NSArray methods

- (NSUInteger) count
{
    return [realArray count];
}

- (id) objectAtIndex:(NSUInteger)index
{
    return [realArray objectAtIndex:index];
}


// block all the other init's (some could be supported)

static id NotSupported()
{
    NSException* myException = [NSException
        exceptionWithName:@"InvalidInitializer"
        reason:@"Only initWithClass: and initWithClass:andCapacity: supported"
        userInfo:nil];
    @throw myException;
}

- (id)initWithArray:(NSArray *)anArray { return NotSupported(); }
- (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag { return NotSupported(); }
- (id)initWithContentsOfFile:(NSString *)aPath { return NotSupported(); }
- (id)initWithContentsOfURL:(NSURL *)aURL { return NotSupported(); }
- (id)initWithObjects:(id)firstObj, ... { return NotSupported(); }
- (id)initWithObjects:(const id *)objects count:(NSUInteger)count { return NotSupported(); }

@end

Use as:

MonomorphicArray *monoString = [[MonomorphicArray alloc] initWithClass:[NSString class] andCapacity:3];

[monoString addObject:@"A string"];
[monoString addObject:[NSNumber numberWithInt:42]]; // will throw
[monoString addObject:@"Another string"];

这篇关于NSMutableArray - 强制数组只保存特定的对象类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆