这里的初学者,为iPhone开发,有一个非常简单的问题:在头文件中声明方法然后在实现文件中填写它的原因是什么? 总是必须完成吗?
另外,我知道在头文件的@interface中声明变量,但为什么只有有时重复使用@property标记?这是否适用于其他类可能希望读取或写入的变量(因此它们会自动创建getter和setter方法)?
亲切的问候。
答案 0 :(得分:10)
在.h文件中声明方法称为前向声明。如果在.h文件中声明方法头,则编译器将在实际链接之前知道方法名称,参数和返回类型。您只能在.m文件中编写方法体。但该方法只能由该文件中声明的方法使用。但是如果你在标题中声明一个方法那么它就不是问题了。因为在编译器的第一次传递过程中,方法签名将被所有人知道,并且将在第二次传递中链接。
@property
和@synthesize
标记用于创建自动的getter和setter(或Accessors
和Mutators
,Objective-C
术语),但还有更多。在iOS
中,您必须手动执行内存管理(应该在iOS5
中进行更改,如Apple承诺的那样)。在@property
标记中,您可以了解内存在分配期间的行为。
iOS
通过维护保留计数来跟踪对象的内存管理。当您分配一个对象时,它的保留计数变为1.然后您可以通过retain方法手动增加保留计数(例如[myObj retain]
)或通过释放方法减少保留计数(例如[myObj release]
)。当保留计数降至0 iOS
时,从内存中删除该对象。使用@property
标记,您可以定义在分配期间如何管理保留计数。例如,@property
标记中最常用的两个参数是:
@property (nonatomic, retain)
@property (nonatomic, assign)
在分配期间的第一种情况下,对象的保留计数将自动增加1(例如self.myObj = anotherClass.anotherObjOfSameClass;
),在后一种情况下,保留计数不会增加。
答案 1 :(得分:4)
任何C语言中头文件的要点是将实现与可用方法分开。也就是说,您在头文件中定义类的模板,以便使用您的代码的人可以就像“哦,我想使用此方法和此方法,现在我知道如何实例化此类的对象”。这都是关于抽象的。 : - )
答案 2 :(得分:3)
我想这只是制作两个文件,一个用于公共API(.h),另一个用于(.m)中的逻辑和实现,以隐藏其他人。还有属性标记有助于为变量创建getter和setter。
你在头文件中使用@property而不是在实现中使用@synthesize,它允许你访问getter和setter。
更多阅读,
仅供参考,你也可以这样做,但不推荐
#import <UIKit/UIKit.h>
@interface FileSystemDemoViewController : UIViewController {
UITextView *actorListBox;
NSArray *dataToShow;
}
@property (nonatomic, retain) IBOutlet UITextView *actorListBox;
@property (nonatomic, retain) NSArray *dataToShow;
-(IBAction) covertToAscending:(id)sender;
-(IBAction) covertToDescending:(id)sender;
@end
@implementation
...Your implementation here...
@end
以上所有代码都在.m文件中,实现。
再次不推荐
快乐编码
答案 3 :(得分:2)
为什么要分开.h和.m文件?
从历史上看,在C中,当你包含.h文件时,它几乎完全等同于将文件粘贴到包含它的文件中。实际上,所有声明都在使用它们的每个文件中重复。没关系,在C中你可以重复声明你想要的任何声明,只要它们不会改变。但是,重复定义会导致函数的多个副本和一般破坏。因此,您不能包含模块的整个代码,只能包含其声明。
我认为Objective-C实际上更聪明,如果你想要根本没有.m文件,你可以将所有代码放在.h文件中。你也可以只在一个.m文件中定义一个类,并且没有.h文件,但是你不能真正制作这样的整个项目,因为没有什么能够访问其他任何东西。
但是,将声明与定义分开仍然是一种很好的做法。这就像在餐厅吃菜单而不必回到厨房,看看有什么做饭。 .h文件是其他模块如何使用模块内容的简短摘要。
为什么有些实例变量有属性而有些却没有?
正确,部分原因是实例变量不能自动用于其他类。默认属性是。但是,不一定。您可以将酒店设为私人。
您使用属性获得的另一件事是自动内存管理。如果使用retain属性,则在为属性赋值时,将增加值的保留计数,并减少先前值的保留计数(如果有)。它非常方便,避免了傻瓜。即使其他类不访问实例变量,它也很有用。如果不使用属性,则必须确保在实例方法中执行适当的保留和释放指令,以避免泄漏内存。您还可以在属性上获得其他自动行为,例如锁定或复制。
最后,您可以使用属性属性和@synthesize关键字获取内置行为,但您也可以决定不使用@synthesize关键字,并为您的属性编写自定义getter和setter。这些可以做很奇特的事情,比如在属性发生变化时更新相关的实例变量。
答案 4 :(得分:1)
如上所述,.h和.m文件的最初原因是C编译器单独处理每个源文件,然后仅在它们链接时才连接它们之间的点。因此,需要有一些声明可以传播的机制 - 以便可以单独检查每个文件的编译器错误和警告 - 但定义仍保留在一个位置 - 以便链接器可以确保公共资源最终位于公共位置。
从现代运行时开始,.h文件和.m文件之间的区别更好地被认为是接口和实现之间的区别。界面是您发布供所有人查看的内容。实现仅适用于该类的知识。您与外界的唯一合同是界面定义的合同。
与大多数面向对象语言一样,Objective-C采用对象属性的getter和setter概念。对象无法访问其他对象的实例变量,而是询问“这个值是什么?”或“请将其值设置为此”。在Objective-C 2.0之前,你必须自己编写getter和setter,这引入了大量重复的样板代码。@property
的最初目的是在界面中声明getter或setter。 @synthesize
用于为声明为@property
的内容生成默认实现。
从新运行时开始,不需要在接口中声明实例变量,您可以将它们完全保留在实现中。所以,例如:
SomeClass.h:
@interface SomeClass: NSObject
- (void)doSomeTask;
@end
SomeClass.m:
// declare a category with some unexposed properties
@interface SomeClass ()
@property (nonatomic, assign) NSMutableArray *arrayForMe;
@end
@implementation SomeClass
@synthesize arrayForMe; // you can now use the property self.arrayForMe,
// even though you didn't declare a backing
// instance variable
- (void)doSomePrecursorTask
{
// ...
}
- (void)doSomeTask
{
// as a fact of implementation, I need to do something else
// first. Because it's an implementation specific, I don't
// want to put it in the declared interface
[self doSomePrecursorTask];
// ...
}
@end
新的运行时可在iOS,Lion和64bit Snow Leopard上使用。作为一种良好的实践,现在将实例变量保留在头文件中可能是有意义的。只需将公共接口放在那里,并将它们视为形式化和通信的一种方式。我希望标题中的实例变量看起来很快就会成为NSEnumerator
。