ObjectiveC中variables位置的声明/定义?
自从开始在iOS应用程序和目标C上工作以来,我一直困惑于可以声明和定义variables的不同位置。 一方面,我们有传统的C方法,另一方面,我们有新的ObjectiveC指令,在其上添加OO。 你们可以帮助我理解最好的实践和情况,我想用这些位置来表示我的变数,也许正确的理解我现在的想法吗?
下面是一个示例类(.h和.m):
#import <Foundation/Foundation.h> // 1) What do I declare here? @interface SampleClass : NSObject { // 2) ivar declarations // Pretty much never used? } // 3) class-specific method / property declarations @end
和
#import "SampleClass.h" // 4) what goes here? @interface SampleClass() // 5) private interface, can define private methods and properties here @end @implementation SampleClass { // 6) define ivars } // 7) define methods and synthesize properties from both public and private // interfaces @end
- 我对1和4的理解是这些是基于C风格的基于文件的声明和定义,它们不了解类的概念,因此必须准确使用它们如何在C中使用。我见过它们之前用于实现基于静态variables的单例。 我还有其他方便的用途吗?
- 我和iOS一起工作的地方是ivars已经完全停止在@synthesize指令之外,因此可以被忽略。 是这样吗?
- 关于5:为什么我会想要在私有接口中声明方法? 我的私人类方法似乎编译得很好,没有在接口声明。 这主要是为了可读性吗?
谢谢你们,伙计们!
我可以理解你的困惑。 特别是最近更新Xcode和新的LLVM编译器改变了Ivars和属性的声明方式。
在“现代”Objective-C(在“旧”Obj-C 2.0)之前,你没有太多的select。 实例variables用于在大括号{ }
之间的标题中声明:
// MyClass.h @interface MyClass : NSObject { int myVar; } @end
您只能在您的实现中访问这些variables,而不能从其他类访问这些variables。 要做到这一点,你必须声明访问器方法,看起来像这样:
// MyClass.h @interface MyClass : NSObject { int myVar; } - (int)myVar; - (void)setMyVar:(int)newVar; @end // MyClass.m @implementation MyClass - (int)myVar { return myVar; } - (void)setMyVar:(int)newVar { if (newVar != myVar) { myVar = newVar; } } @end
这样,您就可以从其他类中获取和设置该实例variables,并使用通常的方括号语法来发送消息(调用方法):
// OtherClass.m int v = [myClass myVar]; // assuming myClass is an object of type MyClass. [myClass setMyVar:v+1];
由于手动声明和实现每个访问器方法都非常烦人,因此引入了@property
和@synthesize
来自动生成访问器方法:
// MyClass.h @interface MyClass : NSObject { int myVar; } @property (nonatomic) int myVar; @end // MyClass.m @implementation MyClass @synthesize myVar; @end
结果是更清晰和更短的代码。 访问器方法将为您执行,您仍然可以像以前一样使用括号语法。 但是另外,您也可以使用点语法来访问属性:
// OtherClass.m int v = myClass.myVar; // assuming myClass is an object of type MyClass. myClass.myVar = v+1;
由于Xcode 4.4,你不必自己声明一个实例variables,你也可以跳过@synthesize
。 如果你没有声明一个ivar,编译器会为你添加它,它也会生成访问器方法,而不必使用@synthesize
。
自动生成的ivar的默认名称是以下划线开头的名称或属性。 您可以使用@synthesize myVar = iVarName;
更改生成的ivar的名称@synthesize myVar = iVarName;
// MyClass.h @interface MyClass : NSObject @property (nonatomic) int myVar; @end // MyClass.m @implementation MyClass @end
这将完全按照上面的代码工作。 为了兼容性的原因,你仍然可以在头文件中声明ivars。 但是,因为你想这样做(而不是声明一个属性)的唯一原因是创build一个私有variables,你现在可以在实现文件中这样做,这是首选的方法。
实现文件中的@interface
块实际上是一个扩展 ,可用于转发声明方法(不再需要)和(重新)声明属性。 你可以例如在你的头文件中声明一个readonly
属性。
@property (nonatomic, readonly) myReadOnlyVar;
并在您的实现文件中将其重新声明为readwrite
,以便能够使用属性语法来设置它,而不仅仅通过直接访问伊娃。
至于完全在@interface
或@implementation
块之外声明variables,是的,这些是简单的Cvariables,工作原理是一样的。
首先阅读@ DrummerB的回答。 这是一个很好的概述,你通常应该做什么。 考虑到这一点,针对您的具体问题:
#import <Foundation/Foundation.h> // 1) What do I declare here?
这里没有实际的variables定义(如果你确切地知道你在做什么,在技术上是合法的,但从来不这样做)。 你可以定义几种其他types的东西:
- typdefs
- 枚举
- 实习医生
Externs看起来像variables声明,但它只是一个承诺,实际上在别的地方宣布它。 在ObjC中,它们只应该用来声明常量,而且通常只是string常量。 例如:
extern NSString * const MYSomethingHappenedNotification;
然后你会在你的.m
文件中声明实际的常量:
NSString * const MYSomethingHappenedNotification = @"MYSomethingHappenedNotification";
@interface SampleClass : NSObject { // 2) ivar declarations // Pretty much never used? }
正如DrummerB所指出的,这是遗产。 不要在这里放任何东西。
// 3) class-specific method / property declarations @end
是的。
#import "SampleClass.h" // 4) what goes here?
外部常量,如上所述。 此外文件静态variables可以在这里。 这些与其他语言中的类variables相当。
@interface SampleClass() // 5) private interface, can define private methods and properties here @end
是的
@implementation SampleClass { // 6) define ivars }
但是很less。 几乎总是应该允许clang(Xcode)为你创buildvariables。 exception通常围绕非ObjC ivars(如Core Foundation对象,特别是C ++对象(如果这是一个ObjC ++类)或具有奇怪存储语义的ivars(如由于某种原因不与某个属性匹配的ivars))。
// 7) define methods and synthesize properties from both public and private // interfaces
一般你不应该@synthesize了。 铿锵(Xcode)会为你做,而你应该放过它。
在过去的几年中,情况变得非常简单。 副作用是现在有三个不同的时代(易碎ABI,非易碎ABI,非易碎ABI +自动合成)。 所以当你看到较旧的代码时,可能会有点混乱。 因此,简单的混乱:D
我也很新,所以希望我不要把任何东西搞砸。
1&4:C风格的全局variables:文件范围广。 两者之间的区别在于,由于它们是文件范围广的,所以第一个对于任何人来说都是可用的,而第二个则不是。
2:实例variables。 大多数实例variables都是通过使用属性的访问器进行合成和检索/设置的,因为它使内存pipe理变得简单易行,同时还提供了易于理解的点符号。
6:实施ivars是有点新的。 这是放置私有ivars的好地方,因为你只想公开头部需要的东西,但子类不会inheritance它们。
3&7:公共方法和属性声明,然后执行。
5:私人界面。 我总是使用私人界面,只要我能保持干净,创造一种黑匣子的效果。 如果他们不需要知道的话,把它放在那里。 我也是为了可读性,不知道是否有其他原因。
这是在Objective-C中声明的各种variables的一个例子。 variables名称表示其访问权限。
文件:Animal.h
@interface Animal : NSObject { NSObject *iProtected; @package NSObject *iPackage; @private NSObject *iPrivate; @protected NSObject *iProtected2; // default access. Only visible to subclasses. @public NSObject *iPublic; } @property (nonatomic,strong) NSObject *iPublic2; @end
File:Animal.m
#import "Animal.h" // Same behaviour for categories (x) than for class extensions (). @interface Animal(){ @public NSString *iNotVisible; } @property (nonatomic,strong) NSObject *iNotVisible2; @end @implementation Animal { @public NSString *iNotVisible3; } -(id) init { self = [super init]; if (self){ iProtected = @"iProtected"; iPackage = @"iPackage"; iPrivate = @"iPrivate"; iProtected2 = @"iProtected2"; iPublic = @"iPublic"; _iPublic2 = @"iPublic2"; iNotVisible = @"iNotVisible"; _iNotVisible2 = @"iNotVisible2"; iNotVisible3 = @"iNotVisible3"; } return self; } @end
请注意,iNotVisiblevariables不能从任何其他类中看到。 这是一个可见性问题,所以用@public
或@public
声明它们不会改变它。
在构造函数中,最好使用下划线来访问使用@property
声明的variables,以避免副作用。
让我们尝试访问这些variables。
文件:Cow.h
#import "Animal.h" @interface Cow : Animal @end
File:Cow.m
#import "Cow.h" #include <objc/runtime.h> @implementation Cow -(id)init { self=[super init]; if (self){ iProtected = @"iProtected"; iPackage = @"iPackage"; //iPrivate = @"iPrivate"; // compiler error: variable is private iProtected2 = @"iProtected2"; iPublic = @"iPublic"; self.iPublic2 = @"iPublic2"; // using self because the backing ivar is private //iNotVisible = @"iNotVisible"; // compiler error: undeclared identifier //_iNotVisible2 = @"iNotVisible2"; // compiler error: undeclared identifier //iNotVisible3 = @"iNotVisible3"; // compiler error: undeclared identifier } return self; } @end
我们仍然可以使用运行时访问不可见的variables。
File:Cow.m(part 2)
@implementation Cow(blindAcess) - (void) setIvar:(NSString*)name value:(id)value { Ivar ivar = class_getInstanceVariable([self class], [name UTF8String]); object_setIvar(self, ivar, value); } - (id) getIvar:(NSString*)name { Ivar ivar = class_getInstanceVariable([self class], [name UTF8String]); id thing = object_getIvar(self, ivar); return thing; } -(void) blindAccess { [self setIvar:@"iNotVisible" value:@"iMadeVisible"]; [self setIvar:@"_iNotVisible2" value:@"iMadeVisible2"]; [self setIvar:@"iNotVisible3" value:@"iMadeVisible3"]; NSLog(@"\n%@ \n%@ \n%@", [self getIvar:@"iNotVisible"], [self getIvar:@"_iNotVisible2"], [self getIvar:@"iNotVisible3"]); } @end
让我们尝试访问不可见的variables。
文件:main.m
#import "Cow.h" #import <Foundation/Foundation.h> int main(int argc, char *argv[]) { @autoreleasepool { Cow *cow = [Cow new]; [cow performSelector:@selector(blindAccess)]; } }
这打印
iMadeVisible iMadeVisible2 iMadeVisible3
请注意,我能够访问_iNotVisible2
类是私有的后援ivar _iNotVisible2
。 在Objective-C中,所有variables都可以被读取或设置,即使那些被标记为@private
variables也不例外。
我没有包含关联对象或Cvariables,因为它们是不同的鸟类。 至于Cvariables,在@interface X{}
或@implementation X{}
之外定义的任何variables都是具有文件范围和静态存储的Cvariables。
我没有讨论内存pipe理属性,或者readonly / readwrite,getter / setter属性。
- 如何将应用程序内购买添加到iOS应用程序?
- Whatsapp的Web版本如何在iOS设备上运行,并在30秒内closures应用程序?
- UItesting失败 – 获取元素错误-25201的快照失败
- Xcode 4.6中的“po”命令第一次非常慢
- Objective-C和Swift URL编码
- “-webkit-overflow-scrolling:touch”打破了css的3D视angular
- iOS 10中的错误:无法从https://mesu.apple.com/assets/中复制资产types的资产信息
- 如何将构build上传到iTunes Connect for TestFlight?
- 通过使用查询而不是重复观察单个事件,加快为我的社交networking应用程序提取post