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

Posted

技术标签:

【中文标题】是否使用 getter 和 setter 将消息从父 UIViewController 传递到 UIView 类中的方法?【英文标题】:Is using getters and setters the way to pass a message from a parent UIViewController to a method in a UIView class? 【发布时间】:2017-04-04 22:35:18 【问题描述】:

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

示例 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

下面的代码中,我尝试使用getter和setter来初始化CustomView中的背景颜色,以引用ViewControllerzone的值(在原始项目中适合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:zonesetSelected:zone 中设置的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

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

这里最大的危险是通过从一个对象请求数据,你 只是获取数据。你没有得到一个对象——不是大的 感觉。即使您从查询中收到的东西是一个对象 在结构上(例如,一个字符串),它在语义上不再是一个对象。 它不再与其所有者对象有任何关联。只是因为 你得到一个内容为“RED”的字符串,你不能问这个字符串 那是什么意思。是业主姓氏吗?车的颜色?这 转速表的现状?一个对象知道这些事情, 数据没有。

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

【问题讨论】:

【参考方案1】:

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 子类作为该视图控制器的视图,那也没关系。您可以使用自定义实例替换您的视图,也可以使用具有相同框架的子视图覆盖默认视图。但是给视图一个指向它的视图控制器的指针是不明智的(甚至更不明智地将此指针称为“父”)

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

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

【讨论】:

danh,感谢您的详细解释。这是我在项目中缺少的完美简单的解决方案。我将不得不考虑“给视图一个指向它的视图控制器的指针是不明智的(甚至更不明智地将此指针称为“父”)。 :-) 乐于助人。命名点是 UIView 使用“父级”来指代它出现的视图,而不是管理它的视图控制器。完全保留指针不明智的原因更多地在于设计传统,强大的所有权和信息流视图控制器视图,而不是相反.视图有时确实需要在该链上进行反向通信,一种常见的方法是“委托”。

以上是关于是否使用 getter 和 setter 将消息从父 UIViewController 传递到 UIView 类中的方法?的主要内容,如果未能解决你的问题,请参考以下文章

用 mapState 和 mapMutations 替换计算的 getter/setter

使用 sqldelight 为 getter 和 setter 加前缀

c# 使用基类中的 setter 或 getter

是否有任何 Maven 插件可用于从 Jhipster 中删除生成类的 getter/setter 并添加 lombok [关闭]

setter 和 getter 的模板

Typescript Vuex - 如何使用 setter 和 getter 定义状态?