目标C - 访问者,即Getters/Setters

Rei*_*oke 6 objective-c

我已经广泛阅读了已经发布的问题,并且找不到我正在寻找的答案.

我完全理解使用该@syntesize指令创建getter和setter方法的概念(即如果我有,@property int width并且@synthesize width,我无意中创建了getter方法width和setter方法setWidth:).

但是,当我没有使用该@synthesize指令但是在作为@implementation对象的部分中声明实例变量时,我并不完全理解存取器方法的工作原理.这是我对以下代码不了解的内容:

1)在main哪里说:

NSLog(@"Origin at (%i, %i)", myRect.origin1.x, myRect.origin1.y);
Run Code Online (Sandbox Code Playgroud)

在我看来,好像它将调用[[myRect origin1] x]首先确定[myRect origin1]返回的方法,origin然后立即调用[origin x](然后执行相同的操作y).现在,让我失望的是,如果我要更改getter方法的名称

-(XYpoint *) origin1;
Run Code Online (Sandbox Code Playgroud)

包含在Rectangle.h中

-(XYpoint *) origin2;
Run Code Online (Sandbox Code Playgroud)

程序得到大量错误并停止编译.注意:我还在所引用的任何地方更改了此方法的名称,包括将main中的前面的代码更改为

NSLog(@"Origin at (%i, %i)", myRect.origin2.x, myRect.origin2.y);
Run Code Online (Sandbox Code Playgroud)

但是,如果我还更改了setter方法的名称:

-(void) setOrigin1: (XYpoint *) pt
Run Code Online (Sandbox Code Playgroud)

至:

-(void) setOrigin2: (XYpoint *) pt
Run Code Online (Sandbox Code Playgroud)

然后一切都像以前一样有效.在我看来,只有当我的getter和setter都在x setX命名约定中命名时它才能正常工作.我认为这主要是我需要解释的:

A)如果我创建一个碰巧是对象的实例变量(在这种情况下就像'origin'),我必须为它创建getter和setter方法吗?

B)我可以创建一个getter方法但不能创建setter方法,反之亦然

C)如果我确实为'origin'创建了getter和setter方法,那么它们都必须以这种x setX方式命名.在这种情况下作为-(XYpoint *) origin1-(void) setOrigin1: (XYpoint *) pt.如果我更改了getter的名称,我必须相应地更改setter的名称?

这是所有代码:

Rectangle.h:

#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
Run Code Online (Sandbox Code Playgroud)

Rectangle.m:

#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
Run Code Online (Sandbox Code Playgroud)

XYpoint.h:

#import <Foundation/Foundation.h>

@interface XYpoint : NSObject

@property int x, y;

-(void) setX: (int) xVal andY: (int) yVal;
@end
Run Code Online (Sandbox Code Playgroud)

XYpoint.m:

#import "XYpoint.h"

@implementation XYpoint

@synthesize x,y;

-(void) setX: (int) xVal andY: (int) yVal
{
    x = xVal;
    y = yVal;
}
@end
Run Code Online (Sandbox Code Playgroud)

main.m文件:

#import <Foundation/Foundation.h>
#import "Rectangle.h"
#import "XYpoint.h"

int main (int argc, const char * argv[])
{

    @autoreleasepool {
        Rectangle *myRect = [[Rectangle alloc] init];
        XYpoint *myPoint = [[XYpoint alloc] init];

        [myPoint setX: 100 andY: 200];
        [myRect setWidth: 5 andHeight:8];
        myRect.origin1 = myPoint;
        NSLog(@"Rectangle w = %i, h = %i", myRect.width, myRect.height);
        NSLog(@"Origin at (%i, %i)", myRect.origin1.x, myRect.origin1.y);
        NSLog(@"Area = %i, Perimeter = %i", [myRect area], [myRect perimeter]);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Cal*_*leb 5

A)如果我创建一个碰巧是对象的实例变量(在这种情况下就像'origin'),我必须为它创建getter和setter方法吗?

不可以.如果您声明属性,则需要提供自己的访问者或使用@synthesize指令来创建它们.但是你可以拥有你喜欢的所有实例变量而不需要访问它们.

B)我可以创建一个getter方法但不能创建setter方法,反之亦然

是的,如果您声明您的财产,您可以提供吸气剂readonly.

C)如果我确实为'origin'创建了getter和setter方法,那么它们都必须以x setX方式命名.在这种情况下,作为 - (XYpoint*)origin1和 - (void)setOrigin1:(XYpoint*)pt.如果我更改了getter的名称,我必须相应地更改setter的名称?

您可以为访问者提供自己的名称,但如果您希望您的类符合相关属性的键值编码,则应遵循通常的约定:

@property (getter=isBar, setter=setBar) int bar;
Run Code Online (Sandbox Code Playgroud)


Jak*_*ger 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;
}
Run Code Online (Sandbox Code Playgroud)

显然,我们期望这个程序运行并输出-setIdVar called with argument: test。这正是在不使用 ARC 的情况下编译它时发生的情况(例如使用clang -framework Foundation main.m)。

但如果我们用 ARC 编译它,clang 就会崩溃。( clang -framework Foundation -fobjc-arc main.m)

有趣的是,当对非对象类型(例如 int)使用 setter 或定义 getter 时,不会发生这种崩溃。