mary-jiang / FBUTwitter

0 stars 0 forks source link

Project Feedback #3

Open angelacaq opened 3 years ago

angelacaq commented 3 years ago

Most of my feedback will revolve around the model-view-controller, the architecture design generally used in iOS. In essence:

  1. Models: handle data
  2. Views: handle UI/gestures
  3. View Controllers: connect models and views

Models can be seen as objects (e.g. a Tweet) that has methods that handles state changes (e.g. a Tweet is favorited). Views don't handle logic involving data changes, but rather just displays those changes — which they get from the VC.

Hopefully this will also help a bit with understanding how to implement an APIManager (which essentially was a model in Flix)


Model <-> Views

https://github.com/mary-jiang/FBUTwitter/blob/618bd9895559591ac234705f3144798dcd311040/twitter/Views/TweetCell.m#L31-L64

didTapFavorite and didTapRetweet logic can be moved to the Tweet model, such that you can call [tweet favorite] and [tweet retweet]. TweetCell is a view, such that in MVC, it handles UI updates (i.e. setting the content of the labels).

In this case, because the purpose of the TweetCell is specifically meant to present the Tweet model (and not to be reused), you don't need to separate out the model from the view.

However, if this wasn't a TweetCell but rather a TweetView that is reused (e.g. in DetailsViewController), then you'd want to completely separate the models/views. In that case, you could create a delegate in the view, call the delegate method in didTapFavorite (e.g. [self.delegate didTapFavorite]) and have the view controller conform to the delegate's protocol and call[tweet favorite]. That way, the tweet cell view is in complete isolation from model changes.

This might feel extra right now, but as you might start reusing views and/or what you can do to a tweet expands, the separation of the three keeps code clean and organized.


View Controllers <-> Views

https://github.com/mary-jiang/FBUTwitter/blob/618bd9895559591ac234705f3144798dcd311040/twitter/View%20Controllers/DetailsViewController.m#L100-L137

A nice thing about having the logic moved to the Tweet model is that you can use it across VCs 😎 (i.e. no repeated code for favoriting/retweeting)

Here, it looks like you are using the view controller as a view too. By the way things work @ FB, the views are generally isolated no matter what (even if it's potentially only used in one place). In this case, you'd want to create a DetailsView.h/.m. You could initialize the view with

- (instancetype)initWithName:(NSString *)name text:(NSString *)text date:(NSString *)date; // etc.

And when making updates, refreshing using custom methods like

- (void)toggleFavorite;

Basically, considering the view as a separate "template" of sorts, and the VC fills the template.

FWIW, I'm not sure how the custom views end up looking like on Storyboard, but I believe you change the class of main UIView already attached to the UIViewController


If any of this is confusing, let me know! Unfortunately, I can't look at the autolayout via GitHub, but if that's also something you'd like me to look at, I'm happy to take the time.

angelacaq commented 3 years ago

Delegates

I liked to consider delegates as instances in when I want to speak "upwards." Two cases are:

1/ MVC: [similar example as Model <-> Views header] I have a generic view that contains a button. What the button does is different depending on the view controller (VC) that initializes the view. I create a delegate in the view. VC1 and VC2 contain the view. In the VCs, I conform to the delegate protocol and create the delegate method. The logic in the delegate method for VC1 can be different from that of VC2; that is, what happens when the button is tapped is personalized by VC.

2/ View Controller <-> View Controller: I have VC1 that segues to VC2. In VC2, something happens that I want to impact VC1. I create a delegate in VC2, and in VC1, I conform to the delegate protocol by creating the delegate method. Now, In VC2, I can call [self.delegate doSomethingWithThisString:(NSString*)thisString], and VC1 will implement - (void)doSomethingWithThisString:(NSString *)thisString] and do whatever it needs to with thisString.

What I mean by speaking "upwards": In example 1, the VC creates the view (VC -> view), and delegates are used to communicate from the view back to the VC (VC <- view). In example 2, VC1 segues to VC2 (VC1 -> VC2), and delegates are used to communicate from VC2 back to VC1 (VC1 <- VC2).