简体   繁体   English

如何将 Class object 转换为符合协议

[英]How to cast Class object to conformance witih protocol

I'm trying to cast a Class object to a certain protocol, which defines class methods (+) that that class implements.我正在尝试将 Class object 转换为某个协议,该协议定义了 class 实现的 class 方法 (+)。

I know how to do this with (id< protocol>), as outlined in this question , but I can't seem to figure out the right way for Class objects.我知道如何使用 (id< protocol>) 执行此操作,如该问题中所述,但我似乎无法找出 Class 个对象的正确方法。

The basic scenario is as follows.基本场景如下。

I have a protocol:我有一个协议:

@protocol Protocol <NSObject>
+ (id)classMethod:(id)arg;
@end

I then have a function which accepts a Class object, which it knows sometimes conforms to the protocol based on another argument (this is obviously very simplified):然后我有一个 function 接受 Class object,它知道有时符合基于另一个参数的协议(这显然非常简化):

- (id)someMethodWithClass:(Class)cls andUseArg:(BOOL)arg
{
    id instance;
    if (arg != nil) {
        instance = [(Class<Protocol>)cls classMethod:arg];
    }
}

Now I don't get any warnings on this, and it looks right to me.现在我没有收到任何警告,它看起来对我来说是正确的。 (I'm not going to see any errors in any case, because I can guarantee that if arg.= nil then the class conforms.) (我不会在任何情况下看到任何错误,因为我可以保证如果 arg.= nil 那么 class 符合。)

However, I'm not getting autocompletion in Xcode, which makes me wonder if this is the right way to do it.但是,我没有在 Xcode 中自动完成,这让我想知道这是否是正确的方法。 Any thoughts?有什么想法吗? (Note that I am not interested in instance being id< Protocol>.) (请注意,我对实例是 id<Protocol> 不感兴趣。)

If you want to determine whether cls conforms to a particular protocol (and assuming that classMethod: is a required class method of that protocol), you can simply: 如果要确定cls是否符合特定协议(并假设classMethod:是该协议的必需类方法),您可以简单地:

- (id)someMethodWithClass:(Class)cls andUseArg:(BOOL)arg
{
    id instance;
    if ([cls conformsToProtocol:@protocol(Protocol)]) {
        instance = [cls classMethod:arg];
    }

    return instance;
}

Alternatively, just see if it responds to a particular class method selector: 或者,只需查看它是否响应特定的类方法选择器:

- (id)someMethodWithClass:(Class)cls andUseArg:(BOOL)arg
{
    id instance;
    if ([cls respondsToSelector:@selector(classMethod:)]) {
        instance = [cls classMethod:arg];
    }

    return instance;
}

The question is 11 years old and there is nothing wrong with the Rob's answer , but I find it unfortunate that the centrepiece part of it (whether type-casting a Class object with a protocol is a correct syntax) never got proper attention.这个问题已有 11 年历史, Rob 的回答没有任何问题,但我发现不幸的是它的核心部分(使用协议对Class object 进行类型转换是否是正确的语法)从未得到适当的关注。

First of all static typing in Objective-C is very artificial thing, and it exists solely for the compiler to emit a warning (not even an error).首先 static 输入 Objective-C 是非常人为的事情,它的存在仅仅是为了编译器发出警告(甚至不是错误)。 Let's start with what Class objects really is - if you take a look at the documentation , you will find that the Class type is actually an alias for objc_class * type:让我们从Class对象真正是什么开始——如果你看一下文档,你会发现Class类型实际上是objc_class *类型的别名:

typedef struct objc_class *Class;

You can find definition of objc_class type in the source codes of Apple's objc runtime library :您可以在Apple 的 objc 运行时库的源代码中找到objc_class类型的定义:

// inherits objc_object with some adjustments
struct objc_class : objc_object { ... }

As you can see, objc_class is just an extension to a objc_object .如您所见, objc_class只是objc_object的扩展。 Any Objective-C class is in fact instance of this objc_object .任何 Objective-C class 实际上都是这个objc_object的实例。 Eg here is how NSObject or id aliases look like:例如,这是NSObjectid别名的样子:


// "translation" of an Objective-C class declaration
typedef struct objc_object NSObject;

// the same for `id` type but with the pointer type included
typedef struct objc_object *id;

It means that "static typing" doesn't exist in Objective-C, the "typing" of an instance happens via introspection of a given instance (different kind of meta-information objc_object stores).这意味着 Objective-C 中不存在“静态类型”,实例的“类型”是通过对给定实例的内省(不同类型的元信息objc_object存储)发生的。 It makes all Objective-C classes compatible with each other (first - because it's a pointer, second - because it's a pointer to the same structure).它使所有 Objective-C 类彼此兼容(首先 - 因为它是一个指针,其次 - 因为它是指向同一结构的指针)。 Eg you can write code like this:例如你可以这样写代码:

Class obj = [NSObject new];

..and it will happily compile. ..它会很高兴地编译。

However this purely dynamic nature of the language makes it very error-prone, exposing all kinds of mistakes a programmer can make.然而,这种语言的纯粹动态特性使其非常容易出错,暴露出程序员可能犯的各种错误。 In order to avoid that clang in fact does compile time checking of the specified types , but it purely relies on the programmer to provide correct data for a type of an instance, and if the types are incompatible from Objective-C perspective, the compiler can emit a warning for you.为了避免clang 实际上确实对指定类型进行编译时检查,但它纯粹依赖于程序员为实例类型提供正确的数据,如果从 Objective-C 的角度来看这些类型不兼容,则编译器可以发出一个警告你。 This works for instance objects, but unfortunately there is no syntax in Objective-C to type a class object other than with the Class alias.这适用于实例对象,但不幸的是,Objective-C 中没有语法来键入 class object,而不是Class别名。 It means that for the compiler all such objects are indistinguishable during compile time.这意味着对于编译器来说,所有这些对象在编译期间都是无法区分的。

And all of this is true for protocols typing.所有这一切都适用于协议类型。 Here I mean that when you add a protocol conformance token to a variable type ( id<TDWLoadable> var ) you merely ask the compiler to check whether the assigned to the variable object conforms to the given protocol:在这里我的意思是,当您将协议一致性标记添加到变量类型 ( id<TDWLoadable> var ) 时,您只需要求编译器检查分配给变量 object 的值是否符合给定的协议:

@protocol TDWLoadable

+ (void)classMethod;
- (void)instanceMethod;

@end

@interface TDWObject : NSObject
@end

// Initializing '__strong id<TDWLoadable>' with an expression of incompatible type 'TDWObject *'
id<TDWLoadable> loadable = [TDWObject new];

For a class object, however, the same check is just ignored, because Class objects cannot be typed:然而,对于 class object,相同的检查将被忽略,因为无法键入Class对象:

Class<TDWLoadable> loadable = [[TDWObject new] class];

This behavior is described in the Type Checking section of Protocols part in The Objective-C Programming Language (emphasis mine):此行为在 Objective-C 编程语言(强调我的)的协议部分的类型检查部分中进行了描述:

...the declaration ...声明

id <Formatting> anObject;

groups all objects that conform to the Formatting protocol into a type, regardless of their positions in the class hierarchy.将所有符合 Formatting 协议的对象归为一个类型,而不管它们在 class 层次结构中的位置。 The compiler can make sure only objects that conform to the protocol are assigned to the type.编译器可以确保只将符合协议的对象分配给该类型。

In each case, the type groups similar objects—either because they share a common inheritance, or because they converge on a common set of methods.在每种情况下,类型都将相似的对象组合在一起——要么是因为它们共享一个公共的 inheritance,要么是因为它们集中在一组公共的方法上。

The two types can be combined in a single declaration:这两种类型可以组合在一个声明中:

 Formatter <Formatting> *anObject;

Protocols can't be used to type class objects .协议不能用于键入 class 对象 Only instances can be statically typed to a protocol, just as only instances can be statically typed to a class. (However, at runtime, both classes and instances respond to a conformsToProtocol: message.)只有实例可以静态类型化为协议,就像只有实例可以静态类型化为 class 一样。(但是,在运行时,类和实例都会响应 conformsToProtocol conformsToProtocol:消息。)

Also, if we take into account that objc_class is in fact just an extension to objc_object then two expressions of kind:另外,如果我们考虑到objc_class实际上只是objc_object的扩展,那么有两个 kind 表达式:

  • Class<TDWLoadable> classObj;
  • id<TDWLoadable> obj;

Should follow the same contract (ie + (void)classMethod has to refer to metaclass of classObj and - (void)instanceMethod to the class object itself).应该遵循相同的契约(即+ (void)classMethod必须引用classObj的元类, - (void)instanceMethod必须引用 class object 本身)。


Having that said, since the syntax essentially has no effect and just ignored by the compiler, you are free to come up with your own convention to the Class<Protocol> typing.话虽如此,由于语法基本上没有效果,只是被编译器忽略,您可以自由地为Class<Protocol>类型制定自己的约定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM