【问题标题】:Selectors in Objective-C?Objective-C 中的选择器?
【发布时间】:2010-10-18 19:49:40
【问题描述】:

首先,我不确定我是否真的理解选择器是什么。根据我的理解,它是一个方法的名称,你可以将它分配给一个'SEL'类型的类,然后运行诸如respondToSelector之类的方法来查看接收者是否实现了该方法。有人可以提供更好的解释吗?

其次,到目前为止,我有以下代码:

NSString *thing = @"Hello, this is Craig";

SEL sel = @selector(lowercaseString:);
NSString *lower = (([thing respondsToSelector:sel]) ? @"YES" : @"NO");
NSLog (@"Responds to lowercaseString: %@", lower);
if ([thing respondsToSelector:sel]) //(lower == @"YES")
    NSLog(@"lowercaseString is: %@", [thing lowercaseString]);

然而,尽管thing 显然是一种 NSString,并且应该响应小写字符串,但我无法让 'respondsToSelector' 条件返回“YES”...

【问题讨论】:

  • 您想阅读 Apple 开发者网站上的 Selector 描述:Selectors
  • 斯坦福课程 CS193P 作业 1B?我在这里有完全相同的问题! :)

标签: objective-c selector


【解决方案1】:

您必须非常小心方法名称。在这种情况下,方法名称只是“lowercaseString”,而不是“lowercaseString:”(注意没有冒号)。这就是返回 NO 的原因,因为 NSString 对象响应 lowercaseString 消息而不是 lowercaseString: 消息。

您如何知道何时添加冒号?如果您在调用它时添加一个冒号,则在消息名称中添加一个冒号,如果它接受一个参数就会发生这种情况。如果它接受零个参数(如lowercaseString 的情况),则没有冒号。如果它需要多个参数,则必须添加额外的参数名称及其冒号,如compare:options:range:locale:

您还可以查看documentation 并注意是否存在尾随冒号。

【讨论】:

    【解决方案2】:

    Selectors 是直接在已编译代码中引用方法的有效方式 - 编译器实际上将值分配给 SEL。

    Other 已经涵盖了您的 q 的第二部分,末尾的“:”匹配的签名与您要查找的签名不同(在这种情况下,该签名不存在)。

    【讨论】:

      【解决方案3】:

      那是因为你想要@selector(lowercaseString),而不是@selector(lowercaseString:)。有一个细微的差别:第二个暗示一个参数(注意末尾的冒号),但- [NSString lowercaseString] 不带参数。

      【讨论】:

        【解决方案4】:

        在这种情况下,选择器的名称是错误的。这里的冒号是方法签名的一部分;这意味着该方法采用一个参数。我相信你想要的

        SEL sel = @selector(lowercaseString);
        

        【讨论】:

          【解决方案5】:

          NSString 的方法是lowercaseString(0 个参数),而不是lowercaseString:(1 个参数)。

          【讨论】:

            【解决方案6】:

            不要将冒号视为函数名称的一部分,将其视为分隔符,如果您没有任何要分隔的内容(函数没有任何值),那么您就不需要它。

            我不知道为什么,但所有这些面向对象的东西对于 Apple 开发人员来说似乎都是陌生的。我强烈建议使用 Visual Studio Express 并使用它。不是因为一个比另一个更好,只是它是看待设计问题和思维方式的好方法。

            喜欢

            introspection = reflection
            + before functions/properties = static
            - = instance level
            

            以不同的方式看待问题总是好的,而编程是终极难题。

            【讨论】:

              【解决方案7】:

              根据我对 Apple 文档的理解,选择器代表您要调用的方法的名称。选择器的好处是您可以在要调用的确切方法不同的情况下使用它们。作为一个简单的示例,您可以执行以下操作:

              SEL selec;
              if (a == b) {
              selec = @selector(method1)
              }
              else
              {
              selec = @selector(method2)
              };
              [self performSelector:selec];
              

              【讨论】:

                【解决方案8】:

                根据苹果文档: https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/Selector.html

                选择器是用于选择要为对象执行的方法的名称,或者是在编译源代码时替换名称的唯一标识符。选择器本身不做任何事情。它只是标识一种方法。使选择器方法名称与纯字符串不同的唯一原因是编译器确保选择器是唯一的。使选择器有用的是(与运行时一起)它就像一个动态函数指针,对于给定的名称,它会自动指向适用于与它一起使用的任何类的方法的实现。假设您有一个用于方法 run 的选择器,以及 Dog、Athlete 和 ComputerSimulation 类(每个都实现了一个方法 run)。选择器可以与每个类的实例一起使用以调用其 run 方法——即使每个类的实现可能不同。

                示例: (lldb) 断点 -- 设置选择器 viewDidLoad

                这将为您应用中的所有 viewDidLoad 实现设置断点。 所以选择器是一种方法的全局标识符。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-08-20
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多