Objective c 目标C-接受者,即接受者/接受者

Objective c 目标C-接受者,即接受者/接受者,objective-c,Objective C,我已经广泛地阅读了已经发布的问题,并没有找到我想要的答案 我完全理解使用@syntesize指令创建getter和setter方法的概念(即,如果我有@property int-width和@synthetic-width,我无意中创建了width的getter方法和setWidth:的setter方法) 但是,当我没有使用@synthesis指令,而是在@implementation部分声明作为对象的实例变量时,我并不完全理解访问器方法是如何工作的。这是我对以下代码不了解的地方: 1) 在ma

我已经广泛地阅读了已经发布的问题,并没有找到我想要的答案

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

但是,当我没有使用
@synthesis
指令,而是在
@implementation
部分声明作为对象的实例变量时,我并不完全理解访问器方法是如何工作的。这是我对以下代码不了解的地方:

1) 在
main
中显示:

NSLog(@"Origin at (%i, %i)", myRect.origin1.x, myRect.origin1.y);
在我看来,它似乎将调用
[[myRect origin1]x]
方法,该方法首先确定
[myRect origin1]
返回
原点
,然后立即调用
[origin x]
(然后对
y
执行相同操作)。现在,让我感到不安的是,如果我要更改getter方法的名称

-(XYpoint *) origin1;
包含在矩形中。h到

-(XYpoint *) origin2;
程序出现大量错误并停止编译。注意:我还在引用该方法的任何地方都更改了该方法的名称,包括将main中前面的代码更改为

NSLog(@"Origin at (%i, %i)", myRect.origin2.x, myRect.origin2.y);
但是,如果我还将setter方法的名称从:

-(void) setOrigin1: (XYpoint *) pt
致:

然后一切都像以前一样工作。在我看来,只有当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的名称

以下是所有代码:

矩形。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
XYpoint.h:

#import <Foundation/Foundation.h>

@interface XYpoint : NSObject

@property int x, y;

-(void) setX: (int) xVal andY: (int) yVal;
@end
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;
}
#导入
#导入“Rectangle.h”
#导入“XYpoint.h”
int main(int argc,const char*argv[]
{
@自动释放池{
矩形*myRect=[[Rectangle alloc]init];
XYpoint*myPoint=[[XYpoint alloc]init];
[myPoint setX:100 andY:200];
[myRect setWidth:5,height:8];
myRect.origin1=myPoint;
NSLog(@“矩形w=%i,h=%i”,myRect.width,myRect.height);
NSLog(@“原点在(%i,%i)”,myRect.origin1.x,myRect.origin1.y);
NSLog(@“面积=%i,周长=%i”,[myRect面积],[myRect周长];
}
返回0;
}

您很可能忘记更改头文件或实现文件中的方法名称。拥有只读属性(没有setter方法)是完全有效的

如果要使用点表示法(即myRect.origin1)访问对象属性,最好的做法是确保在头文件中定义相应的属性,即包括一行,例如:

@property(readonly) XYPoint *origin1; // for read only properties
@property(retain) XYPoint *origin1; // for read/write properties
即使不使用
@synthesis
,也要使用它们,而不是头文件中的常规方法声明。这些行实际上并不创建getter和setter,它们只是通知编译器类具有这些属性。然后,编译器需要名为
-origin1
-setOrigin1
的getter(如果不使用readonly,则需要setter)。setter/getter的名称很重要(有关详细信息,请参阅苹果关于键值编码的文档)

您还应该了解Cocoa的内存管理准则:除非使用自动引用计数,否则矩形类负责在setter中保留或复制XYPoint对象。[编辑]:我刚刚意识到您显然在使用ARC,因为您使用了
@autoreleasepool
语法

A) 如果我创建的实例变量恰好是一个对象(如 (本例中为“origin”)我必须为其创建getter和setter方法吗

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

B) 我可以创建一个getter方法而不是setter方法吗

是的,如果您将属性声明为只读,则可以只提供getter

C) 如果我同时创建getter和setter方法,这是必须的吗 对于“origin”,它们都以x setX方式命名。在这个 大小写为-(XYpoint*)origin1和-(void)setOrigin1:(XYpoint*)pt。 如果我更改getter的名称,我必须更改getter的名称 塞特

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

@property (getter=isBar, setter=setBar) int bar;

通过电子邮件讨论后,我们发现这个问题实际上似乎是一个叮当声中的bug。考虑下面的迷你程序:

#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;
}
#导入
@接口测试对象:NSObject
-(void)setIdVar:(id)someId;
@结束
@实现测试对象
-(void)setIdVar:(id)someId;
{
NSLog(@“-setIdVar,用参数%@”调用,someId);
}
@结束
int main(int argc,const char*argv[]
{
@自动释放池{
TestObject*testObj=[[TestObject alloc]init];
testObj.idVar=@“测试”;
}
返回0;
}
显然,我们希望这个程序运行并输出
-setIdVar,并使用参数test调用。这正是编译时发生的情况
@property(readonly) XYPoint *origin1; // for read only properties
@property(retain) XYPoint *origin1; // for read/write properties
@property (getter=isBar, setter=setBar) int bar;
#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;
}