当前位置:  开发笔记 > IOS > 正文

有没有办法在NSArray,NSMutableArray等上强制输入?

如何解决《有没有办法在NSArray,NSMutableArray等上强制输入?》经验,为你挑选了5个好方法。

我可以创建一个所有元素都是类型的NSMutableArray实例吗?SomeClass



1> Logan..:

没有人把它放在这里,所以我会这样做!

现在,Objective-C正式支持这一点.从Xcode 7开始,您可以使用以下语法:

NSArray *myArray = @[[MyClass new], [MyClass new]];

注意

重要的是要注意这些只是编译器警告,并且您在技术上仍然可以将任何对象插入到数组中.有些脚本可以将所有警告转换为错误,从而阻止构建.


@DeanKelly - 你可以这样做:`@property(非原子的,强大的)NSArray >*protocolObjects;`看起来有点笨重,但是诀窍!

2> Barry Wark..:

对于人们从强类型语言(如C++或Java)过渡到更弱或动态类型的语言(如Python,Ruby或Objective-C),这是一个相对常见的问题.在Objective-C中,大多数对象都继承自NSObject(type id)(其余的继承自其他根类,例如NSProxy也可以是类型id),任何消息都可以发送到任何对象.当然,将消息发送到它无法识别的实例可能会导致运行时错误(并且还会导致编译器警告用适当的-W标志).只要实例响应您发送的消息,您可能不关心它属于哪个类.这通常被称为"鸭子打字",因为"如果它像鸭子一样嘎嘎叫[即响应选择器],它就是一只鸭子[即它可以处理信息;谁在乎它是什么类]".

您可以使用该-(BOOL)respondsToSelector:(SEL)selector方法测试实例是否在运行时响应选择器.假设你要调用数组中的每个实例的方法,但不保证所有实例可以处理消息(所以你不能只是使用NSArray-[NSArray makeObjectsPerformSelector:],像这样的工作:

for(id o in myArray) {
  if([o respondsToSelector:@selector(myMethod)]) {
    [o myMethod];
  }
}

如果您控制实现您希望调用的方法的实例的源代码,则更常见的方法是定义@protocol包含这些方法的实例,并声明所讨论的类在其声明中实现该协议.在此用法中,a @protocol类似于Java接口或C++抽象基类.然后,您可以测试整个协议的一致性,而不是对每种方法的响应.在前面的示例中,它不会产生太大的影响,但如果您调用多个方法,则可能会简化操作.那么这个例子就是:

for(id o in myArray) {
  if([o conformsToProtocol:@protocol(MyProtocol)]) {
    [o myMethod];
  }
}

假设MyProtocol声明myMethod.第二种方法很受欢迎,因为它比第一种方法更能说明代码的意图.

通常,这些方法之一使您无需关心数组中的所有对象是否都是给定类型.如果你仍然关心,标准的动态语言方法是单元测试,单元测试,单元测试.因为此要求中的回归将产生(可能是不可恢复的)运行时(非编译时)错误,所以您需要具有测试覆盖率来验证行为,以便您不会将崩溃释放到野外.在这种情况下,执行修改数组的操作,然后验证数组中的所有实例是否属于给定的类.通过适当的测试覆盖,您甚至不需要额外的运行时开销来验证实例标识.你确实有良好的单元测试覆盖率,不是吗?


单元测试不能代替体面的类型系统.
是的,谁需要键入数组的工具才能提供.我敢肯定@BarryWark(以及任何触及任何需要使用,阅读,理解和支持的代码库的人)都拥有100%的代码覆盖率.但是我敢打赌,除非必要,否则不要使用原始的`id`s,而不是Java编码器传递`Object`s.为什么不?如果你有单元测试,不需要它吗?因为它存在并使您的代码更易于维护,就像键入数组一样.听起来人们投资于该平台并不希望承认某一点,因此发明了为什么这种遗漏实际上是一种好处的原因.

3> Chuck..:

您可以使用一种-addSomeClass:方法创建一个类别,以允许编译时静态类型检查(因此编译器可以让您知道,如果您尝试通过该方法添加它知道的不同类的对象),但是没有真正的方法可以强制执行数组只包含给定类的对象.

通常,在Objective-C中似乎不需要这样的约束.我不认为我曾经听过有经验的Cocoa程序员对该功能的期望.唯一似乎是来自其他语言的程序员仍在使用这些语言的人.如果只需要数组中给定类的对象,则只在该类中粘贴该类的对象.如果要测试代码的行为是否正常,请对其进行测试.


我认为'经验丰富的Cocoa程序员'只是不知道他们缺少什么 - 使用Java的经验表明,类型变量可以提高代码理解度并使更多重构成为可能.
得同意@tgdavies.我怀念使用C#的intellisense和重构功能.当我想要动态类型时,我可以在C#4.0中获得它.当我想要强烈类型的东西时,我也可以拥有它.我发现这两件事都有时间和地点.
@charkrit什么是Objective-C让它"没必要"?你觉得在使用C#时有必要吗?我听到很多人说你在Objective-C中不需要它,但我认为这些人认为你不需要任何语言,这使它成为偏好/风格的问题,而不是必要的问题.
这不是关于允许您的编译器实际帮助您找到问题.当然你可以说"如果你只想要数组中给定类的对象,那么只能在那里粘贴那个类的对象." 但如果测试是强制执行的唯一方法,那么你处于劣势.远离编写代码而发现问题,问题就越成本.
好吧,Java的Generics支持本身就严重破坏了,因为他们从一开始就没有把它放进去......
@GreenKiwi:是的,在一种允许这种类型系统的语言中,它可以帮助您找到问题.Objective-C没有这样的类型系统,因此编译器可以帮助您的程度是有限的.而在实践中,对于大多数人来说,这似乎不是一个非常昂贵的问题.自从熟悉Objective-C以来,您花了多少时间来调试异构数组引起的问题?甚至一个小时?我是有用的静态类型系统的粉丝,但Objective-C不是这样的语言.无论如何,这是Objective-C的正确答案,无论喜欢与否.
@bacar:除非你知道接收器的类型,否则你无法施放.我的观点是,Objective-C通过指针访问所有内容,这些指针可以转换为任何其他类型而无需编译器投诉.它不是一种类型安全的语言.泛型会给你更多的类型安全性,但是在一种像Objective-C一样普遍动态的语言中,它是池塘里的一滴水.动态类型与Objective-C一样普遍存在的唯一其他语言根本没有静态类型系统--JavaScript,Python,Ruby等.Java和C#都没有生成`id`类型 - 泛型是它们的等价物.

4> bendytree..:

您可以子类化NSMutableArray以强制类型安全.

NSMutableArray是一个类集群,因此子类化并不简单.我最终继承NSArray并转发调用到该类内的数组.其结果是一类叫做ConcreteMutableArray很容易的子类.这是我想出的:

CustomArray.h

CustomArray.m

更新:结帐这从迈克灰博客帖子上继承一个类集群.

在项目中包含这些文件,然后使用宏生成您希望的任何类型:

MyArrayTypes.h

CUSTOM_ARRAY_INTERFACE(NSString)
CUSTOM_ARRAY_INTERFACE(User)

MyArrayTypes.m

CUSTOM_ARRAY_IMPLEMENTATION(NSString)
CUSTOM_ARRAY_IMPLEMENTATION(User)

用法:

NSStringArray* strings = [NSStringArray array];
[strings add:@"Hello"];
NSString* str = [strings get:0];

[strings add:[User new]];  //compiler error
User* user = [strings get:0];  //compiler error

其他想法

它继承自NSArray支持序列化/反序列化

根据您的喜好,您可能希望覆盖/隐藏通用方法,例如

- (void) addObject:(id)anObject



5> Barry Wark..:

查看https://github.com/tomersh/Objective-C-Generics,这是Objective-C的编译时(预处理器实现的)泛型实现.这篇博文有一个很好的概述.基本上你得到编译时检查(警告或错误),但是对于泛型没有运行时惩罚.

推荐阅读
mobiledu2402852413
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有