Использует ли геттеры и сеттеры способ передать сообщение от родительского UIViewController методу в классе UIView?

Я пытаюсь реорганизовать ранний проект, отделив код, принадлежащий UIView, от кода, принадлежащего UIViewController. Ответы на популярный вопрос (здесь), похоже, не касаются того, что мне нужно сделать, поэтому позвольте мне проиллюстрировать свой вопрос с двумя примерами.

  • Пример 1

Здесь метод setBackground:zone изменяет цвет фона представления, чтобы указать различные состояния в приложении. Метод , показанный ниже, в настоящее время работает, и я хочу переместить код в представление, которому он принадлежит.

ViewController.h

#import <UIKit/UIKit.h>
#import "CustomView.h"

@interface ViewController : UIViewController {
}
@end

ViewController.m

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    int zone                            = 1; // or 2 or 3;

   self.view                            = [[UIView alloc] initWithFrame: [UIScreen mainScreen].bounds];
    [self setBackground:zone];
}

- (void)setBackground:(int)zone {
    switch (zone) {
        case 1:
            self.view.backgroundColor   = [UIColor orangeColor];
            break;
        case 2:
            self.view.backgroundColor   = [UIColor cyanColor];
            break;
        case 3:
            self.view.backgroundColor   = [UIColor greenColor];
            break;
        default:
            break;
        }
    }
  • Пример 2

В коде ниже я попытался инициализировать цвет фона в CustomView, используя методы получения и установки для ссылки на значение zone в ViewController (подходит, поскольку ViewControllers в исходном проекте уже получил и установил zone для изменения цвета фона).

CustomView.h

#import <UIKit/UIKit.h>

@interface CustomView : UIView {
    UIViewController *parent;
    int selectedZone;
}
- (void)setParent:(UIViewController *)parent;
- (int)getSelectedZone;
@end

CustomView.m

#import "CustomView.h"

@implementation CustomView
    - (void)setParent:(UIViewController *)theParent {
        parent                          = theParent;
    }

    - (int)getSelectedZone {
        return selectedZone;
    }

    - (id)initWithFrame:(CGRect)frame 
        {
        self                            = [super initWithFrame:[UIScreen mainScreen].bounds];
        if (self) {

        NSLog(@"selectedZone in CustomView is seen as %i", [self getSelectedZone]);

            int zone                    = [self getSelectedZone];
            [self setBackground:(int) zone];
        }
        return self;
    }

- (void)setBackground:(int)zone {
    switch (zone) {
        case 1:
            self.view.backgroundColor   = [UIColor orangeColor];
            break;
        case 2:
            self.view.backgroundColor   = [UIColor cyanColor];
            break;
        case 3:
            self.view.backgroundColor   = [UIColor greenColor];
            break;
        default:
            break;
        }
    }

ViewController.h

#import <UIKit/UIKit.h>
#import "CustomView.h"

    @interface ViewController : UIViewController {    
        int selectedZone;
    }

    - (void)setSelectedZone:(int)zone;
    - (int)getSelectedZone;

ViewController.m

#import "ViewController.h"

@implementation ViewController

    - (void)viewDidLoad {
        [super viewDidLoad];

        int zone                        = 1; // or 2 or 3;    
        [self setSelectedZone:(int)zone];
        NSLog(@"selectedZone in ViewController is now set to %i", [self getSelectedZone]);

        self.view                       = [[UIView alloc] initWithFrame: [UIScreen mainScreen].bounds];

        CustomView *cv                  = [[CustomView alloc]init];
        [self.view addSubview:cv];
    }

    - (void)setSelectedZone:(int)zone {
        selectedZone                    = zone;
    }

    - (int)getSelectedZone {
        return selectedZone;
    }

Я могу сказать, что мой код выше не работает, потому что getSelected:zone в CustomView не может ссылаться на zone, установленный setSelected:zone в ViewController.. Но я не понимаю, почему.

2017-04-05 07:04:26.126 ZoneIndicator[1865:1270743] selectedZone in ViewController is now set to 1 
2017-04-05 07:04:26.126 ZoneIndicator[1865:1270743] selectedZone in CustomView is seen as 0

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

Самая большая опасность здесь в том, что, запрашивая данные у объекта, вы получаете только данные. Вы не получаете объект - не в широком смысле. Даже если то, что вы получили в результате запроса, структурно является объектом (например, String), оно больше не является объектом семантически. Он больше не связан со своим объектом-владельцем. Просто потому, что у вас есть строка, содержимое которой было «КРАСНЫМ», вы не можете спросить эту строку, что это означает. Это фамилия владельцев? Цвет машины? Текущее состояние тахометра? Объект знает эти вещи, а данные - нет.

Итак, как передать сообщение от родительского UIViewController методу класса UIView?


person Greg    schedule 04.04.2017    source источник


Ответы (1)


Для виртуального компьютера совершенно нормально устанавливать свойства представления. Вот аннотированный код для вашего первого примера ...

- (void)viewDidLoad {
    [super viewDidLoad];

    // no need to do this, the UIViewController this inherits from creates the view
    // int zone                            = 1; // or 2 or 3;
    //self.view                            = [[UIView alloc] initWithFrame: [UIScreen mainScreen].bounds];
    [self setBackgroundColorForZone:zone];
}

// improved naming for clarity
- (void) setBackgroundColorForZone:(NSInteger)zone {
    // fine as you have it
    switch //...
    // ...
}

Если у вас есть более веская причина для разработки собственного подкласса UIView, который будет представлением этого контроллера представления, это тоже нормально. Вы можете либо заменить свое представление настраиваемым экземпляром, либо закрыть представление по умолчанию дочерним элементом с таким же фреймом. Но неразумно давать представлению указатель на его контроллер представления (и еще более неразумно называть этот указатель "родительским")

Итак, для вашего второго примера пользовательский класс представления должен быть существенно упрощен ...

@interface CustomView : UIView {
    // commented out bad stuff
    // UIViewController *parent;
    // this isn't needed either
    //int selectedZone;
}
// these aren't needed either
//- (void)setParent:(UIViewController *)parent;
//- (int)getSelectedZone;

// just this
- (void)setBackgroundColorForZone:(NSInteger)zone;

@end

И реализация может иметь тот же метод, что и в вашем первом примере. Он принимает целое число зоны и устанавливает self.backgroundColor (вместо self.view.backgroundColor).

Контроллер представления, который управляет этим представлением, теперь можно упростить до:

- (void)viewDidLoad {
    [super viewDidLoad];

    int zone                        = 1; // or 2 or 3; 
    // don't need this   
    //[self setSelectedZone:(int)zone];
    //NSLog(@"selectedZone in ViewController is now set to %i", [self getSelectedZone]);

    // never need this
    //self.view                       = [[UIView alloc] initWithFrame: [UIScreen mainScreen].bounds];

    // notice the change to init with frame
    CustomView *cv                  = [[CustomView alloc]initWithFrame:self.view.bounds];
    [cv setBackgroundColorForZone:zone];
    [self.view addSubview:cv];
}

// don't need any of this
//- (void)setSelectedZone:(int)zone {
//    selectedZone                    = zone;
//}

//- (int)getSelectedZone {
//    return selectedZone;
//}
person danh    schedule 05.04.2017
comment
Дань, спасибо за подробное объяснение. Это идеальное простое решение, которого мне не хватало в проекте. Мне придется подумать о том, что неразумно давать представлению указатель на его контроллер представления (и еще более неразумно называть этот указатель родительским). - person Greg; 05.04.2017
comment
:-) Рад был помочь. Точка именования заключается в том, что родительский элемент используется UIView для ссылки на представление, в котором он появляется, а не на контроллер представления, который им управляет. Причина, по которой неразумно оставлять указатель вообще, связана с традициями дизайна, сильное владение и информационный поток идет от контроллера представления к представлениям, а не наоборот . Иногда представления действительно нуждаются в обратной связи в этой цепочке, и общий подход к этому - делегирование. - person danh; 05.04.2017