是否使用 getter 和 setter 将消息从父 UIViewController 传递到 UIView class 中的方法?

Is using getters and setters the way to pass a message from a parent UIViewController to a method in a UIView class?

我正在尝试通过将属于 UIView 的代码与属于 UIViewController 的代码分开来重组早期项目。一个热门问题 (found here) 的答案似乎没有解决我需要做的事情,所以让我用两个例子来说明我的问题。

此处方法 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;
        }
    }

在下面的代码中,我尝试通过使用 getter 和 setter 来引用 ViewControllerzone 的值来初始化 CustomView 中的背景颜色](适合于原始项目中的 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;
    }

我可以告诉我上面的 代码不起作用,因为 CustomView 中的 getSelected:zone 无法引用 setSelected:zone 设置的 zoneViewController. 但我不明白为什么。

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

但是 an article found here 甚至让我质疑使用 getter 和 setter 是否是最好的方法 - 特别是这个:

The biggest danger here is that by asking for data from an object, you are only getting data. You’re not getting an object—not in the large sense. Even if the thing you received from a query is an object structurally (e.g., a String) it is no longer an object semantically. It no longer has any association with its owner object. Just because you got a string whose contents was “RED”, you can’t ask the string what that means. Is it the owners last name? The color of the car? The current condition of the tachometer? An object knows these things, data does not.

那么如何将消息从父 UIViewController 传递到 UIView class 中的方法?

vc 完全可以设置其视图的属性。这是第一个示例的注释代码...

- (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 subclass 作为该视图控制器的视图,那也没关系。您可以用自定义实例替换您的视图,或者用具有相同框架的子视图覆盖默认视图。但是给一个视图一个指向它的视图控制器的指针是不明智的(更不明智的是调用这个指针"parent")

因此对于您的第二个示例,自定义视图 class 应该大大简化...

@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;
//}