在 Objective-C 中使用 (id)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1208303/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 21:59:43  来源:igfitidea点击:

Using (id) in Objective-C

objective-c

提问by Jason George

I have a function that I want to operate on two different custom objects. My first thought was to accept the argument as an (id) and operate on the id object. I can't quite seem to figure out how to do that, however.

我有一个函数,我想对两个不同的自定义对象进行操作。我的第一个想法是将参数作为 (id) 接受并对 id 对象进行操作。但是,我似乎无法弄清楚如何做到这一点。

Both classes (say apples and oranges) have interface variables:

这两个类(比如苹果和橙子)都有接口变量:

NSDecimalNumber *count;

I want to do something similar to this:

我想做类似的事情:

-(NSDecimalNumber*)addCount:(id)addObject{

    return [count decimalNumberByAdding:addObject.count];
}

I can't seem to figure out the syntax to make that happen. Is this the proper approach, or would it be better to subclass (from say a fruit class) and operate on the parent class?

我似乎无法弄清楚实现这一点的语法。这是正确的方法,还是子类化(从水果类)并在父类上操作会更好吗?

-(NSDecimalNumber*)addCount:(Fruit*)addFruit{

    return [count decimalNumberByAdding:addFruit.count];
}

回答by LBushkin

While you can send a message to any object (id) - property accessors require that the compiler be aware of the type you are dealing with - this is because property accessors are syntactic sugar around calling specific getter and setter methods.

虽然您可以向任何对象 (id) 发送消息 - 属性访问器要求编译器知道您正在处理的类型 - 这是因为属性访问器是围绕调用特定 getter 和 setter 方法的语法糖。

You have a few of ways of working around this:

您有几种方法可以解决此问题:

  1. Instead of accessing the count property, call the corresponding [getCount] methods.

  2. If the different classes have different versions of this method, you can use a runtime type check:

  3. Provide a base class for both types so that you can pass in something more specific than (id).

  4. Define and implement a Protocol that both objects implement that defines a count property (or method).
  1. 调用相应的 [getCount] 方法,而不是访问 count 属性。

  2. 如果不同的类有不同版本的这个方法,你可以使用运行时类型检查:

  3. 为这两种类型提供一个基类,以便您可以传入比 (id) 更具体的内容。

  4. 定义并实现两个对象都实现的协议,该协议定义了计数属性(或方法)。

Example of a dynamic type check:

动态类型检查的示例:

if( [object isKindOfClass:[Apple Class] )
   // call one overload of getCount
else if( [object isKindOfClass:[Orange Class] )
   // call another overload of getCount

Personally, I favor strong typing in my code because it makes it easier to understand the intent. It also allows the IDE to support your coding effort with intellisense, static analysis, and refactoring features. So, in your case, I would use either #3 or #4 as an approach - depending on whether inheritance is really appropriate for the problem.

就我个人而言,我喜欢在我的代码中使用强类型,因为它可以更容易地理解意图。它还允许 IDE 通过智能感知、静态分析和重构功能支持您的编码工作。所以,在你的情况下,我会使用 #3 或 #4 作为一种方法 - 取决于继承是否真的适合这个问题。

回答by pgb

You should try not to access instance variables from another class.

您应该尽量不要从另一个类访问实例变量。

In Objective-C it's enough that the two objects respond to the same selector (say count), however that would give you a compiler warning.

在 Objective-C 中,两个对象响应同一个选择器(比如count)就足够了,但是这会给你一个编译器警告。

There are two ways you can get rid of this warning: either by subclassing from a common Fruitclass or by having your two classes conform to a protocol. I'd go with the protocol:

有两种方法可以消除此警告:通过从公共Fruit类进行子类化或使两个类符合协议。我会去的协议:

@protocol FruitProtocol

- (NSDecimalNumber *)count;

@end

@interface Orange : NSObject<FruitProtocol>
@end

@interface Apple : NSObject<FruitProtocol>
@end

Then your method can look like this:

那么你的方法可以是这样的:

-(NSDecimalNumber*)addCount:(id<FruitProtocol>)addFruit {
    return [count decimalNumberByAdding:[addFruit count]];
}

Here you are saying that your addCountexpects any object that conforms to the FruitProtocolprotocol, and hence can respond to the countselector, so the compiler will accept it.

在这里你是说你addCount期望任何符合FruitProtocol协议的对象,因此可以响应count选择器,所以编译器会接受它。

回答by bobDevil

The fact that you are trying to access 'addFruit.count' is the problem. The dot syntax is only for properties declared with @property (or for structs). If you change it to

您尝试访问“addFruit.count”这一事实是问题所在。点语法仅适用于用@property(或结构)声明的属性。如果你把它改成

[addFruit count]

and add

并添加

-(NSDecimalNumber*)count
{
     return [[count retain] autorelease];
}

to each class, then it would work. However, you will notice you'll get a warning saying 'id' may not respond to the 'count' message, and unless you can be absolutely sure the items sent to this method implement a 'count' method, this is a problematic approach.

到每个班级,然后它就会起作用。但是,您会注意到您会收到一条警告,说 'id' 可能不会响应 'count' 消息,除非您可以绝对确定发送到此方法的项目实现了 'count' 方法,这是一种有问题的方法.

I agree with pgb's approach. You should define a protocol, and declare both classes to implement that protocol. This eliminates the problem of not knowing whether the object will respond to 'count' or not, as you now have a 'contract' of sorts.

我同意 pgb 的方法。您应该定义一个协议,并声明两个类来实现该协议。这消除了不知道对象是否会响应“计数”的问题,因为您现在拥有各种“合同”。

If you want to keep the dot syntax with a property, you can declare it in the protocol:

如果你想保留带有属性的点语法,你可以在协议中声明它:

@protocol FruitProtocol

@property(readonly) NSDecimalNumber * count;

- (NSDecimalNumber *)count

@end

and then, your function would be:

然后,您的功能将是:

-(NSDecimalNumber*)addCount:(id<FruitProtocol>)addObject{

    return [count decimalNumberByAdding:addObject.count];

}

回答by Gordon Gustafson

You're sending the message to count, what is count? id is a pointer to any type of object. If you expect the object to have a count property, then you should only be able to pass in an Array (or some other type restriction).

你发送消息来计数,什么是计数?id 是指向任何类型对象的指针。如果您希望对象具有 count 属性,那么您应该只能传入一个数组(或其他一些类型限制)。

-(NSDecimalNumber*)addCount:(NSArray*) Object{

return [count decimalNumberByAdding: [Object count]]; 

}

回答by jergason

As I understand it, iddoes not have any methods or variables associated with it because it is a generic pointer that does not refer to any specific class. This pagehas some good info on ids if you scroll down a bit.

据我了解,id它没有任何方法或变量与之关联,因为它是一个不指向任何特定类的通用指针。如果您向下滚动一下,此页面会提供一些关于 id 的好信息。

anObject this will not have a countvariable, which is why your first attempt won't work. Creating a base class and using that as a parameter to the method seems like the best idea to me.

anObject this 不会有count变量,这就是为什么您的第一次尝试不起作用。创建一个基类并将其用作方法的参数对我来说似乎是最好的主意。