我已经广泛阅读了已经发布的问题,并且找不到我正在寻找的答案。
我完全理解使用@syntesize
指令创建getter和setter方法的概念(即如果我有@property int width
和@synthesize width
,我无意中创建了一个{{1}的getter方法1}}和width
的setter方法。
但是,当我没有使用setWidth:
指令但在@synthesize
部分中声明实例变量作为对象时,我并不完全理解存取器方法的工作原理。这是我对以下代码不了解的内容:
1)在@implementation
中说:
main
在我看来好像会调用NSLog(@"Origin at (%i, %i)", myRect.origin1.x, myRect.origin1.y);
方法首先确定[[myRect origin1] x]
返回[myRect origin1]
,然后立即调用origin
作为结果(然后对[origin x]
)执行相同的操作。现在,让我失望的是,如果我要更改getter方法的名称
y
包含在Rectangle.h中
-(XYpoint *) origin1;
该程序遇到大量错误并停止编译。注意:我还在所引用的任何地方更改了此方法的名称,包括将main中的前面代码更改为
-(XYpoint *) origin2;
但是,如果我也改变了setter方法的名称:
NSLog(@"Origin at (%i, %i)", myRect.origin2.x, myRect.origin2.y);
为:
-(void) setOrigin1: (XYpoint *) pt
然后一切都像以前一样有效。在我看来,只有当我的getter和setter都在-(void) setOrigin2: (XYpoint *) pt
x
命名约定中命名时,它才能正常工作。我认为这主要是我需要解释的内容:
A)如果我创建一个碰巧是对象的实例变量(在这种情况下就像'origin'),我必须为它创建getter和setter方法吗?
B)我可以创建一个getter方法但不能创建setter方法,反之亦然
C)如果我确实为'origin'创建了getter和setter方法,它们都必须以setX
x
方式命名。在本例中为setX
和-(XYpoint *) origin1
。如果我更改了getter的名称,我必须相应地更改setter的名称吗?
以下是所有代码:
Rectangle.h:
-(void) setOrigin1: (XYpoint *) pt
Rectangle.m:
#import <Foundation/Foundation.h>
@class XYpoint;
@interface Rectangle : NSObject
@property int width, height;
-(XYpoint *) origin1;
-(void) setOrigin1: (XYpoint *) pt;
-(void) setWidth: (int) w andHeight: (int) h;
-(int) area;
-(int) perimeter;
@end
XYpoint.h:
#import "Rectangle.h"
@implementation Rectangle
{
XYpoint *origin;
}
@synthesize width, height;
-(void) setWidth:(int) w andHeight:(int)h
{
width = w;
height = h;
}
-(void) setOrigin1: (XYpoint *) pt
{
origin = pt;
}
-(int) area
{
return width * height;
}
-(int) perimeter
{
return (width + height) * 2;
}
-(XYpoint *) origin1
{
return origin;
}
@end
XYpoint.m:
#import <Foundation/Foundation.h>
@interface XYpoint : NSObject
@property int x, y;
-(void) setX: (int) xVal andY: (int) yVal;
@end
的main.m:
#import "XYpoint.h"
@implementation XYpoint
@synthesize x,y;
-(void) setX: (int) xVal andY: (int) yVal
{
x = xVal;
y = yVal;
}
@end
答案 0 :(得分:5)
A)如果我创建一个碰巧是对象的实例变量(比如 在这种情况下'origin')我必须为它创建getter和setter方法吗?
没有。如果声明属性,则需要提供自己的访问器或使用@synthesize指令创建它们。但是你可以拥有你喜欢的所有实例变量而不需要访问它们。
B)我可以创建一个getter方法但不能创建setter方法,反之亦然
是的,如果您声明属性readonly
,则可以仅提供获取者。
C)如果我确实创建了getter和setter方法,那是强制性的吗? 对于'origin',它们都以x setX方式命名。在这 case as - (XYpoint *)origin1和 - (void)setOrigin1:(XYpoint *)pt。 如果我改变了getter的名字,我必须更改名称 相应的setter?
您可以为访问者提供自己的名称,但如果您希望您的类符合相关属性的键值编码,则应遵循通常的惯例:
@property (getter=isBar, setter=setBar) int bar;
答案 1 :(得分:3)
您很可能忘记更改标题或实现文件中的方法名称。拥有只读属性(没有setter方法)是完全有效的。
如果您想要使用点符号(即myRect.origin1
)访问对象属性,最佳做法是确保在头文件中定义相应的属性,即。包括如下行:
@property(readonly) XYPoint *origin1; // for read only properties
@property(retain) XYPoint *origin1; // for read/write properties
即使您不使用@synthesize
,也要使用它们,并使用它们代替头文件中的常规方法声明。这些行实际上并不创建getter和setter,它们只是通知编译器您的类具有这些属性。然后,编译器将指向名为-origin1
和-setOrigin1
的getter(如果不使用readonly,则为setter)。 setter / getter的名称很重要(有关详细信息,请参阅Apple关于键值编码的文档)
您还应该了解Cocoa的内存管理指南:除非您使用自动引用计数,否则Rectangle类负责在setter中保留或复制XYPoint对象。 [编辑]:我刚才意识到你使用ARC显然是因为你使用了@autoreleasepool
语法。
答案 2 :(得分:3)
通过电子邮件讨论后,我们发现问题实际上似乎是clang中的一个错误。考虑以下迷你程序:
#import <Foundation/Foundation.h>
@interface TestObject : NSObject
-(void)setIdVar:(id)someId;
@end
@implementation TestObject
-(void)setIdVar:(id)someId;
{
NSLog(@"-setIdVar called with argument: %@", someId);
}
@end
int main (int argc, const char * argv[])
{
@autoreleasepool {
TestObject *testObj = [[TestObject alloc] init];
testObj.idVar = @"test";
}
return 0;
}
显然,我们希望这个程序能够运行并输出-setIdVar called with argument: test
。这正是在没有ARC的情况下编译它时会发生的情况(例如...使用clang -framework Foundation main.m
)。
但如果我们用ARC编译它,clang会崩溃。 (clang -framework Foundation -fobjc-arc main.m
)
有趣的是,当使用setter作为非对象类型(例如int)或定义了getter时,不会发生这种崩溃。