Search code examples
iosobjective-carchitectureuiviewcontroller

can I use uiview as viewcontroller?


I have a uiviewcontroller, it's view has 4 subviews, they don't need communication but need many user interaction and have many many content , but they need many network request to fetch data and refresh them. as the trandional mvc, viewcontroller fetch data and then refresh subviews. I think the viewcontroller is too heavy, can I take the 4 subviews as child viewcontroller, they request the data by themself. Is it a good practise or not ?

plan 1:tranditional MVC

#import "TTViewController.h"

@interface TTViewController ()

@property (nonatomic, strong) id modelA;
@property (nonatomic, strong) id modelB;
@property (nonatomic, strong) id modelC;
@property (nonatomic, strong) id modelD;

@property (nonatomic, strong) CustomView *aView;

@property (nonatomic, strong) CustomView *bView;
@property (nonatomic, strong) CustomView *cView;
@property (nonatomic, strong) CustomView *dView;



@end

@implementation TTViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.aView];
    [self.view addSubview:self.bView];
    [self.view addSubview:self.cView];
    [self.view addSubview:self.dView];
    [self reqeustAData];
    [self requetBData];
    [self requestCData];
    [self reqeustDData];
}

- (void)reqeustAData {
    [self.aView  refresh:modelA];
}

- (void)requetBData {
    [self.bView  refresh:modelB];

}

- (void)requestCData {
    [self.cView  refresh:modelC];
}

- (void)reqeustDData {
    [self.dView  refresh:modelD];
}
    #pragma mark - delegate

- (void)delegateAuserAction {
    // handle user's touch when Aview's delegate tell vc
}

- (void)delegateBuserAction {
    // handle user's touch when Bview's delegate tell vc

}

- (void)delegateCuserAction {
    // handle user's touch when Cview's delegate tell vc

}

- (void)delegateDuserAction {
    // handle user's touch when Dview's delegate tell vc
}

@end

plan 2:Take subview as child viewcontroller

#import "TTViewController.h"
#import "CustomView.h"

@interface TTViewController ()

@property (nonatomic, strong) CustomView *aView;
@property (nonatomic, strong) CustomView *bView;
@property (nonatomic, strong) CustomView *cView;
@property (nonatomic, strong) CustomView *dView;

@end

@implementation TTViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self.view addSubview:self.aView];
    [self.view addSubview:self.bView];
    [self.view addSubview:self.cView];
    [self.view addSubview:self.dView];
    [self.aView reqeust];
    [self.bView reqeust];
    [self.cView reqeust];
    [self.dView reqeust];
}

@end


#import "CustomView.h"

@interface CustomView  ()
@property (nonatomic, strong) id model;

@end

@implementation CustomView


- (void)reqeust {
    [self refreshUI:model];
}

- (void)refreshUI:(id)model {
    
}

#pragma mark - handle user action
- (void)handleUserAction {
    // don't delegate to vc, handle it by self
}
@end

Solution

  • Object / class "naming" can be taken too literally. Don't confuse yourself with UIViewController being the only class that can "control views."

    As a very simple example - well, it seems simple to me - let's look at a commonly used view: a UITextField ...

    Suppose in my view controller code I add a UITextField as a subview. After that point, maybe in response to a "Submit" button tap, I may:

    • get the text of that text field
    • do something with the resulting string

    But... what does my controller do when the user is editing the field? Do I have code in my controller that says:

    • user tapped "A" on the keyboard
    • figure out where the insertion point is
    • insert "A" into that string
    • redraw the text field

    No - all of that code is self-contained inside the UITextField view class itself.

    So, in your case, you could think in terms of:

    • the view controller manages the size/positions of the 4 subviews
    • the view controller perhaps sets some initial properties of those 4 subviews
    • perhaps at some point the view controller asks each subview for an update of what it has been doing -- or maybe it never needs to.

    It is perfectly acceptable for each subview to have its own internal code to handle "doing its own thing."

    The trap that people run into - and the reason MVC is stressed - is when they write code in a subview (which is a subview of a subview of a subview...) that relies on a distinct coupling with one or more of its parent views.

    TL;DR - if a view has code to manage (control) its subviews, that doesn't mean it has to be a UIViewController class, nor does it mean it violates the MVC pattern.


    Edit - in response to comment...

    A little searching, and we can find hundreds of articles / discussions about MVC and views vs controllers - far too much to go into here.

    But, a quick example...

    Suppose I have a view that looks like this:

    enter image description here

    Each time a color quadrant is tapped, it increases the "number of taps" for that quadrant.

    Should I put all of the tap handling and value tracking into my UIViewController holding this view? Or, can I put that inside the UIView itself?

    Personally, I would put it inside the view.

    Now, suppose I then want to save the values to persistent storage (data file, database, remote db, etc)?

    In that case, it would make much more sense to have the view (via protocol/delegate or closure) inform the controller of the changes. The controller would then handle updating the model / storing the data.

    It could be argued that I've violated MVC ...

    Of course, suppose I have 8 of these views? Would it make more sense to build a big, heavy controller with all of the tap and value tracking logic, and the view itself only, ummm, does nothing?

    I'd suggest searching the web for uiviewcontroller vs uiview mvc -- and spend a few days reading all of the different opinions.