Цель C - средства доступа, т.е. получатели / установщики - PullRequest
6 голосов
/ 20 декабря 2011

Я внимательно прочитал уже опубликованные вопросы и не могу найти ответ, который ищу.

Я полностью понимаю концепцию использования директивы @syntesize для создания методов получения и установки (т. Е. Если у меня было @property int width и @synthesize width, я непреднамеренно создаю метод получения width и метод установки setWidth:).

Однако, когда я не использую директиву @synthesize, а объявляю переменные экземпляра в разделе @implementation, которые являются объектами, я не до конца понимаю, как работают методы доступа. Вот что я не понимаю в следующем коде:

1) в main, где говорится:

NSLog(@"Origin at (%i, %i)", myRect.origin1.x, myRect.origin1.y);

Мне кажется, что он будет вызывать метод [[myRect origin1] x], который сначала определит, что [myRect origin1] возвращает origin, а затем немедленно вызовет [origin x] в результате (а затем сделает то же самое для * 1022). *). Что меня отталкивает, так это то, что если бы я изменил имя метода-получателя

-(XYpoint *) origin1;

содержится в Rectangle.h до

-(XYpoint *) origin2;

программа получает массу ошибок и перестает компилироваться. Примечание: я также менял имя этого метода везде, на который он ссылается, включая изменение предыдущего кода в main на

NSLog(@"Origin at (%i, %i)", myRect.origin2.x, myRect.origin2.y);

Однако, если я также изменю имя метода установки с:

-(void) setOrigin1: (XYpoint *) pt

до:

-(void) setOrigin2: (XYpoint *) pt

тогда все работает как раньше. Мне кажется, это работает правильно только тогда, когда мои геттер и сеттер названы в соответствии с x setX соглашением об именах. Я предположил, что это в основном то, что мне нужно объяснить:

A) Если я создаю переменную экземпляра, которая оказывается объектом (например, в данном случае 'origin'), я должен создать для нее методы получения и установки?

B) Могу ли я создать метод получения, но не метод установки или наоборот

C) Обязательно ли, если я создаю метод getter и setter для origin, чтобы они оба были названы в порядке x setX. В этом случае как -(XYpoint *) origin1 и -(void) setOrigin1: (XYpoint *) pt. Как, если я изменю имя получателя, я должен соответственно изменить имя установщика?

Вот весь код:

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

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

XYpoint.h:

#import <Foundation/Foundation.h>

@interface XYpoint : NSObject

@property int x, y;

-(void) setX: (int) xVal andY: (int) yVal;
@end

XYpoint.m:

#import "XYpoint.h"

@implementation XYpoint

@synthesize x,y;

-(void) setX: (int) xVal andY: (int) yVal
{
    x = xVal;
    y = 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;
}

Ответы [ 3 ]

5 голосов
/ 20 декабря 2011

A) Если я создаю переменную экземпляра, которая оказывается объектом (например, 'origin' в этом случае) я должен создать методы получения и установки для него?

Нет. Если вы объявляете свойство, вам нужно либо предоставить свои собственные методы доступа, либо использовать директиву @synthesize для их создания. Но вы можете иметь все переменные экземпляра, которые вам нравятся, без доступа к ним.

B) Могу ли я создать метод получения, но не метод установки или наоборот

Да, вы можете указать только получателя, если объявите свою собственность readonly.

C) Обязательно ли, если я создаю метод получения и получения для 'origin', чтобы они оба были названы в порядке x setX В этом регистр как - (XYpoint *) origin1 и - (void) setOrigin1: (XYpoint *) pt. Как если бы я изменил имя получателя, я должен изменить имя соответственно сеттер?

Вы можете указать собственные имена для методов доступа, но вам следует придерживаться обычного соглашения, если вы хотите, чтобы ваш класс соответствовал кодированию значения ключа для рассматриваемого свойства:

@property (getter=isBar, setter=setBar) int bar;
3 голосов
/ 21 декабря 2011

После обсуждения по электронной почте мы выяснили, что на самом деле проблема заключается в 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)

Забавно, что этот сбой не происходит при использовании сеттеров для необъектных типов (например, int) или когда определен геттер.

3 голосов
/ 20 декабря 2011

Скорее всего, вы забыли изменить имена методов в заголовке или файлах реализации. Вполне допустимо иметь свойства только для чтения (без методов установки).

Лучше всего, если у вас есть свойство объекта, к которому вы хотите получить доступ с помощью точечной нотации (т. Е. myRect.origin1), это убедиться, что вы определили соответствующее свойство в заголовочном файле, т.е. включите строку, такую ​​как:

@property(readonly) XYPoint *origin1; // for read only properties
@property(retain) XYPoint *origin1; // for read/write properties

Используйте их, даже если вы не используете @synthesize, и используйте их вместо обычных объявлений методов в заголовочном файле. Эти строки на самом деле не создают геттеры и сеттеры, они просто сообщают компилятору, что у вашего класса есть эти свойства. Компилятор будет ожидать геттеры (и сеттеры, если вы не используете только для чтения) с именами -origin1 и -setOrigin1. Важны имена сеттеров / геттеров (подробности см. В документации Apple по кодированию значения ключа)

Вы также должны знать о принципах управления памятью Cocoa: если вы не используете Автоматический подсчет ссылок, ваш класс Rectangle отвечает за сохранение или копирование объекта XYPoint в установщике. [РЕДАКТИРОВАТЬ]: Я только что понял, что вы, очевидно, используете ARC, так как вы используете синтаксис @autoreleasepool.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...