我什么时候定义 Objective-C 方法?
我正在学习 Objective-C,并且有 C/C++ 背景。
在面向对象的 C++ 中,您始终需要在定义(实现)方法之前声明它,即使它是在父类中声明的。
在过程式 C、IIRC 中,您可以只定义一个函数,只要它仅从稍后出现在文件中的同一编译单元(即同一文件)中的其他内容调用即可(好吧,前提是您不使用“extern”在其他地方声明它)。
现在,在 Objective-C 中,似乎您只需要在头文件中声明选择器(如果它们将被外部对象使用),并且您可以在 .m 文件中很好地组成选择器,并且在 .m 文件中调用它们。 另外,委托方法或继承方法似乎永远不会(重新)定义。
我走在正确的轨道上吗? 什么时候需要在 Objective-C 中定义选择器?
I'm learning Objective-C, and have a C/C++ background.
In object-oriented C++, you always need to declare your method before you define (implement) it, even if it is declared in the parent class.
In procedural-style C, IIRC, you can get away with just defining a function so long as it is only called from something else in the same compilational unit (ie. the same file) that came later on in the file (well, provided you don't declare it elsewhere with "extern").
Now, in Objective-C, it appears that you only need to declare selectors in the header file if they are going to be used by something external, and that you can make up selectors in your .m file just fine, and call them within the .m file. Also, it appears that delegate methods or inherited methods are never (re)defined.
Am I on the right track? When do you need to define a selector in Objective-C?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对于 Objective-C 方法,一般做法是将您希望公开的方法放在头文件的
@interface
部分中,以便其他代码可以仅包含 .h 并知道如何与您的代码交互。 基于顺序的“惰性声明”就像 C 中的函数一样 - 您不必声明方法原型,除非您有无法通过排序解决的依赖项,但您可以添加方法如果需要,可以在@implementation
中添加原型。所以是的,你走在正确的道路上。 不要重复继承方法的方法原型 - 编译器会在父级的头文件中找到它。 委托方法可以定义为类别中的原型(附加到类上)并根据需要实现,但委托不需要提供方法原型,因为它已经定义了。 (如果想清楚的话,它仍然可以,等等)
由于您刚刚学习 Objective-C,所以这个答案的其余部分比您要求的要详细得多。 你被警告了。 ;-)
当您静态键入变量(例如
MyClass*
而不是id
)时,当您尝试调用类的方法时,编译器会警告您不宣传它实现,无论它是否实现。 如果您动态输入变量,编译器不会阻止您调用您喜欢的任何内容,并且只有在调用不存在的内容时才会出现运行时错误。 就语言而言,您可以在运行时调用类实现的任何方法而不会出现错误 - 无法限制谁可以调用方法。就我个人而言,我认为这实际上是一件好事。 我们已经习惯了封装和保护我们的代码免受其他代码的影响,以至于有时我们将调用者视为狡猾的恶棍,而不是值得信赖的同事或客户。 我发现以“你做你的工作,我做我的”的心态来编码是非常愉快的,每个人都尊重界限并照顾自己的事情。 你可能会说Objective-C的“态度”是一种社区信任,而不是严格执行。 例如,我很乐意帮助任何来到我办公桌前的人,但如果有人弄乱我的东西或在没有询问的情况下移动东西,我会非常生气。 设计良好的代码不一定是偏执或反社会的,它只需能够很好地协同工作即可。 :-)
也就是说,有很多方法可以构建界面,具体取决于您向用户公开界面时想要/需要的粒度级别。 您在公共标头中声明的任何方法对于任何人来说本质上都是公平的。 隐藏方法声明有点像锁上你的车或房子——它可能不会把每个人都拒之门外,但是(1)它不会用他们不应该乱搞的东西来诱惑他们,从而“让诚实的人保持诚实”,并且(2 )任何确实进入的人肯定知道他们不应该这样做,并且不能真正抱怨负面后果。
以下是我用于文件命名的一些约定,以及每个文件中的内容 - 从底部的 .m 文件开始,每个文件都包含其上面的文件。 (使用严格的包含链可以防止重复符号警告等情况。)其中一些级别仅适用于较大的可重用组件,例如 Cocoa 框架。 根据您的需要调整它们,并使用任何适合您的名称。
MyClass.h
— 公共 API(应用程序编程接口)MyClass_Private.h
— 公司内部 SPI(系统编程接口)MyClass_Internal.h
— 项目-internal IPI(内部编程接口)MyClass.m
— 通常所有 API/SPI/IPI 声明的实现MyClass_Foo.m
— 附加实现,例如类别API 是供所有人使用,并且得到公开支持(通常在 Foo.framework/Headers 中)。 SPI 为代码的内部客户端公开了额外的功能,但要理解支持可能有限并且接口可能会发生变化(通常在
Foo.framework/PrivateHeaders
中)。 IPI 由特定于实现的细节组成,这些细节永远不应在项目本身之外使用,并且这些标头根本不包含在框架中。 任何选择使用 SPI 和 IPI 调用的人都需要自行承担风险,并且当更改破坏其代码时通常会造成损害。 :-)For Objective-C methods, the general practice is to put methods you wish to expose in the
@interface
section of the header file so other code can include only the .h and know how to interact with your code. Order-based "lazy declaration" works just like functions in C — you don't have to declare a method prototype unless you have a dependency that can't be resolved by ordering, but you can add method prototypes inside the@implementation
if needed.So yes, you're on the right track. Don't repeat the method prototype for inherited methods — the compiler finds it in the parent's header file. Delegate methods may be defined as prototypes in a category (tacked onto a class) and implemented as desired, but the delegate does not need to provide a method prototype, since it is already defined. (It still can if it wants to for clarity, etc.)
Since you're just learning Objective-C, the rest of this answer is much more detail than you asked for. You have been warned. ;-)
When you statically type a variable (e.g.
MyClass*
instead ofid
) the compiler will warn you when you try to call a method that a class doesn't advertise that it implements, whether it does or not. If you dynamically type the variable, the compiler won't stop you from calling whatever you like, and you'll only get runtime errors if you call something that doesn't exist. As far as the language is concerned, you can call any method that a class implements without errors at runtime — there is no way to restrict who can call a method.Personally, I think this is actually a good thing. We get so used to encapsulation and protecting our code from other code that we sometimes treat the caller as a devious miscreant rather than a trustworthy coworker or customer. I find it's quite pleasant to code with a mindset of "you do your job and I do mine" where everyone respects boundaries and takes care of their own thing. You might say that the "attitude" of Objective-C is one of community trust, rather than of strict enforcement. For example, I'm happy to help anyone who comes to my desk, but would get really annoyed if someone messed with my stuff or moved things around without asking. Well-designed code doesn't have to be paranoid or sociopathic, it just has to work well together. :-)
That said, there are many approaches for structuring your interfaces, depending on the level of granularity you want/need in exposing interfaces to users. Any methods you declare in the public header are essentially fair game for anyone to use. Hiding method declarations is a bit like locking your car or house — it probably won't keep everyone out, but (1) it "keeps honest people honest" by not tempting them with something they shouldn't be messing with, and (2) anyone who does get in will certainly know they weren't supposed to, and can't really complain of negative consequences.
Below are some conventions I use for file naming, and what goes in each file — starting from a .m file at the bottom, each file includes the one above it. (Using a strict chain of includes will prevent things like duplicate symbol warnings.) Some of these levels only apply to larger reusable components, such as Cocoa frameworks. Adapt them according to your needs, and use whatever names suit you.
MyClass.h
— Public API (Application Programming Interface)MyClass_Private.h
— Company-internal SPI (System Programming Interface)MyClass_Internal.h
— Project-internal IPI (Internal Programming Interface)MyClass.m
— Implementation, generally of all API/SPI/IPI declarationsMyClass_Foo.m
— Additional implementation, such as for categoriesAPI is for everyone to use, and is publicly supported (usually in
Foo.framework/Headers
). SPI exposes additional functionality for internal clients of your code, but with the understanding that support may be limited and the interface is subject to change (usually inFoo.framework/PrivateHeaders
). IPI consists of implementation-specific details that should never be used outside the project itself, and these headers are not included in the framework at all. Anyone who chooses to use SPI and IPI calls does so at their own risk, and usually to their detriment when changes break their code. :-)在头文件中声明方法只会停止编译器警告。 Objective-C 是一种动态语言,因此您可以向对象调用方法(发送消息),无论该方法是否在外部声明。
此外,如果您在 .m 文件中在调用该方法的任何代码上方定义一个方法(惰性声明),则不会生成任何警告。 然而,同样的情况也适用,您可以在不声明对象的情况下向对象发送消息。
当然 - 这意味着 Objective-C 中没有私有方法。 类实现的任何方法都可以被调用。
个人喜好。 如果它是一个公共方法(即外部使用的方法)。 在 .h 中声明并在 .m 中定义。 如果您想限制它的可见性,或者至少表明它是私有方法,请在 . .m 文件。 尽管很多示例代码都使用了惰性声明方法。
Declaring the methods in the header file will only stop compiler warnings. Objective-C is a dynamic language, so you can call a method (send a message) to an object whether or not that method is declared externally.
Also, if you define a method in the .m file above any code that calls it (lazy declaration) then that won't generate any warnings. However the same thing applies, you can send a message to an object without it being declared.
Of course - this means that there are no private methods in Objective-C. Any method that a class implements can be called.
Personal preference. If it's a public method (i.e one used externally). declare it in the .h and define in the .m. If you want to limit it's visibility, or at least indicate that it is a private method, use categories/class extensions in the .m file. Although lots of example code uses the lazy declaration method.
Objective-C 将函数视为“消息”,因此,您可以向任何对象发送“消息”——即使是没有在其接口中明确声明它可以接受的对象。 因此,Obj-C 中不存在私有成员之类的东西。
这可能非常强大,但对于新的 Obj-C 程序员来说却是一个困惑的根源——尤其是那些来自 C++、Java 或 C# 的程序员。 以下是基本经验规则:
其中大部分是个人喜好,但它有助于避免烦人的编译器警告并保持代码井井有条。 并且易于理解。
Objective-C treats functions as "messages" and as such, you can send a "message" to any object - even one that doesn't explicitly state in its interface that it can accept. As a result, there are no such things as private members in Obj-C.
This can be very powerful, but is a source of confusion for new Obj-C programmers - especially those coming from C++, Java or C#. Here are the basic rules of thumb:
Much of this is personal preference, however it helps to avoid annoying compiler warnings and keeps your code organized. and easy to understand.