Developing iOS apps with MVC: A practical example

Last week, I explored what the design pattern “Model-View-Controller” (MVC) is and created a playground to demonstrate the idea. But what does this look like a full-fledged application with API calls and Storyboards and design requirements? This week, we’ll see how that plays out.

Design

Imagine you’ve got a new project to do, and design have given you what to implement. It’s a news app which hooks up to NewsAPI, which generously allows you to request news sources and articles for free. Here’s what your designer hands off to you:

The application is very simple, but it does everything you need a news reader to do:

  1. We have a launch screen
  2. A list a square icons for each news source
  3. A table of news articles, with images, the author, and the title
  4. A web view with the full article

Planning

How does this design decompose into MVC components?

View Controller

Let’s start with view controllers, as view controllers are almost 1:1 with a designer’s screens. In this case, the launch screen will be done simply in our LaunchScreen.storyboard file, we’ll have a SourcesViewController, an ArticlesViewController, and then we’ll reach for the pre-built SFSafariViewController for the last view.

View

What views will each of these view controllers have? The launch screen will only need a UILabel, there isn’t much to do there. The SourcesViewControllerprobably needs a UICollectionView, with a custom SourceCollectionViewCell that we’ll make. The ArticlesViewController would be best as a UITableView, along with a custom ArticleTableViewCell.

Model

To determine what our model layer looks like, we cannot go from the designs, as it’s not a visual component, but rather, we must check the API documentation from NewsAPI.

Let’s start with the documentation for the response from the source’s API call:

status (string) – If the request was successful or not. Options: ok, error. In the case of error a code and message property will be populated.
sources (array) – A list of the news sources and blogs available on News API.

id (string) – The unique identifier for the news source. This is needed when querying the /articles endpoint to retrieve article metadata.
name (string) – The display-friendly name of the news source.
description (string) – A brief description of the news source and what area they specialize in.
url (string) – The base URL or homepage of the source.
category (string) – The topic category that the source focuses on.
Possible options: business, entertainment, gaming, general, music, politics, science-and-nature, sport, technology
language (string) – The 2-letter ISO-639-1 code for the language that the source is written in.
Possible options: en, de, fr
country (string) – The 2-letter ISO 3166-1 code of the country that the source mainly focuses on.
Available options: au, de, gb, in, it, us
sortBysAvailable (array) – The available headline lists for the news source. The possible options are top, latest and popular.

top Indicates this source can return a list of headlines sorted in the order they appear on the source’ homepage.
latest Indicates this source can return a list of headlines sorted in chronological order, newest first.
popular Indicates this source can return a list of its current most popular headlines.

There’s no one right way to do this, but roughly, our models are going to follow the structure and variables of our API. What I read here is that we’re going to need a SourcesResponse model with the status variable and the sources as an array of Source models. A Source model has an ID, a name, a description, a URL, a category (probably best to make this an enum, as it has a closed set of possible values), a language, and a country (again both these last ones are best as enums).

Let’s check out the documentation on the articles response:

status (string) – If the request was successful or not. Options: ok, error. In the case of error a code and message property will be populated.
source (string) – The identifier of the source requested.
sortBy (string) – Which type of article list is being returned. Options: top, latest, popular.
articles (array) The list of headline metadata requested.

author (string) – The author of the article.
description (string) – A description or preface for the article.
title (string) – The headline or title of the article.
url (string) – The direct URL to the content page of the article.
urlToImage (string) – The URL to a relevant image for the article.
publishedAt (string) – The best attempt at finding a date for the article, in UTC (+0).

Again, there’s no one right or settled way to turn JSON into model objects, but what I see here is that we’re going to need a ArticlesResponse model with an array of Article objects, which each have an author, description, title, url, urlToImage, and published at, all as Strings.

So in all, if we give a Swift struct to each entity and a Swift enum to each closed set of values, we’ll end up with these models:

  • Article
  • ArticlesResponse
  • Source
  • SourcesResponse
  • Category
  • Country
  • Language
  • Sort

Visualisation

How does this look like in the graphs we made last week? Let’s take the ArticlesViewController as an example:

But of course, this single MVC group is going to have to work with all the others in the full implementation. That looks something like this:

But this is beginning to get messy, so let’s separate all of our files into their respective layers:

Development

Now that we have a plan, it’s time to set it in motion. Fortunately, not only are we working with a designer, but an iOS architect that has created a shell of project for us using the information above, but it’s going to be up to us to add the implementation. You can download that shell here. You’ll note that it includes an API client pre-built for us, and the creation of an API client is outside the purview of our MVC discussion but it’s a very worthwhile topic I’ll devote time to in a latter post.

View

First, you should build your Storyboard to spec. First, add the label to the LaunchScreen.storyboard file. You’ll need one UINavigationController and two UIViewControllers, one with a UICollectionView and one with a UITableView. The collection view and table view will need a custom cell each, with an image view and labels each. Refer to the design to get this just right.

Now that we have these built in Storyboard, we’ll need to create corresponding source files for each cell type. Here’s what that SourceCollectionViewCell should look like:

class SourceCollectionViewCell: UICollectionViewCell, ReuseIdentifiable {
    static var ReuseIdentifier : String { return "SourceCollectionViewCell" }

    @IBOutlet weak var iconImageView: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        prepareForReuse()
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        iconImageView.image = nil
        nameLabel.text = ""
    }
}

You should use this as an example to build ArticleTableViewCell, which is much the same in form. You should also use this opportunity to connect the table view and collection view as IBOutlets to their respective UIViewController and set their delegates and data sources to, also, their respective view controller.

Model

Now that we have the easy stuff out the way, let’s build our first model. The article is a good place to start, I suspect it looks something like this:

struct Article {
 let author: String?
 let description: String?
 let title: String?
 let url: String?
 let urlToImage: String?
 let publishedAt: String?
}

We’re choosing a struct because it is a lighter entity in the Swift language than a class, but really there are reasons to go either way. These models do not exist in a vacuum however, we need to transform these models from JSON into structs. Fortunately, our architect has given a convenient means of doing so with the JSONTransformable protocol, which is very simple:

protocol JSONTransformable {
 init(json: Any)
}

When our model structs conform to this, we’ll add the implementation for converting them from JSON represented as an “Any”, which could be an array or dictionary depending on our API responses. What does our struct look like with this implementation?

struct Article: JSONTransformable {
    let author: String?
    let description: String?
    let title: String?
    let url: String?
    let urlToImage: String?
    let publishedAt: String?

    init(json: Any) {
        let jsonDictionary = json as? [String : Any]
        author = jsonDictionary?["author"] as? String
        description = jsonDictionary?["description"] as? String
        title = jsonDictionary?["title"] as? String
        url = jsonDictionary?["url"] as? String
        urlToImage = jsonDictionary?["urlToImage"] as? String
        publishedAt = jsonDictionary?["publishedAt"] as? String
    }
}

And with a little magic from Swift generics in our API client, these can now be converted from their JSON representations returned from the API. Let’s give the Articles response model the same treatment:

struct ArticlesResponse: JSONTransformable {
    let status: String?
    let articles: [Article]?

    init(json: Any) {
        let jsonDictionary = json as? [String : Any]
        status = jsonDictionary?["status"] as? String
        if let articlesJSONArray = jsonDictionary?["articles"] as? [[String: Any]] {
            var anArticles: [Article] = []
            for sourceJSONDictionary in articlesJSONArray {
                anArticles.append(Article(json: sourceJSONDictionary))
            }
            articles = anArticles
        } else {
            articles = nil
        }
    }
}

Notice how this initializer uses the JSON-based initializer from our Article class, meaning that when we request this response from our API, this initializer will cascade through all the article JSON entries to build structs for each. We’ll need to do the same for both the Source and SourcesResponse models, which is left as an exercise to the reader! (You’ll also find it as a download at the end.

But the Article and Source models aren’t the only types of models we have, there are also the enum models for the Language and Country, etc. Let’s see how one of those looks:

enum Category: String {
    case business = "business"
    case entertainment = "entertainment"
    case gaming = "gaming"
    case general = "general"
    case music = "music"
    case politics = "politics"
    case science = "science-and-nature"
    case sport = "sport"
    case technology = "technology"
}

This has the typed name on the left and the value on the right side of the equals sign, making it easy to parse these using the raw value initializer of these objects. You’ll see this in the initializer for Source. You should use this as an example to create the models for Country, Language, and Sort.

View Controller

Now that we have our models finished and our views finished, it’s time to write the glue code between our two layers: the view controllers. First, let’s get our Source view controller working:

class SourcesViewController: UIViewController {

    let api = NewsAPI()
    var sources: [Source] = []

    @IBOutlet weak var collectionView: UICollectionView!
    @IBOutlet weak var collectionViewFlowLayout: UICollectionViewFlowLayout!

    override func viewDidLoad() {
        super.viewDidLoad()

        api.load(.sources(categories: nil, languages: nil, countries: nil)) { [weak self] (response: SourcesResponse?, error:Error?) in
            self?.sources = response?.sources ?? []
            self?.collectionView.reloadData()
        }
    }
}

extension SourcesViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return sources.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell : SourceCollectionViewCell = collectionView.dequeueReusableCell(for: indexPath)
        cell.iconImageView.setIconImage(from: sources[indexPath.row].url)
        cell.nameLabel.text = sources[indexPath.row].name
        return cell
    }
}

extension SourcesViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let numberOfCellsPerLineFloat: CGFloat = 2
        let itemWidthWithoutConsideringInteritemSpace = collectionViewFlowLayout.collectionViewWidthWithoutInsets / numberOfCellsPerLineFloat
        let numberOfInteritemSpaces = (numberOfCellsPerLineFloat - 1)
        let amountOfInteritemSpacePerCell = (collectionViewFlowLayout.minimumInteritemSpacing / numberOfCellsPerLineFloat)
        let itemWidth = itemWidthWithoutConsideringInteritemSpace - (numberOfInteritemSpaces * amountOfInteritemSpacePerCell)
        return CGSize(width: itemWidth, height: 208)
    }
}

Notice how the view controller has access to both the model and view, but neither the model nor the view has access to each other. This property results in one of the big benefits of MVC, in that if either your model or view changes, as I assure you they will, you minimize the amount of code you will need to re-write because your models and views are completely independent, and in fact, could be re-used in other parts of your applications or even other applications.

But this isn’t quite the whole picture, let’s get our ArticlesViewController working:

class ArticlesViewController: UIViewController {
    let api = NewsAPI()
    var source: Source!
    var articles: [Article] = []
    
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        title = source.name

        api.load(.articles(source: source, sort: nil)) { [weak self] (response:ArticlesResponse?, error:Error?) in
            self?.articles = response?.articles ?? []
            self?.tableView.reloadData()
        }
    }
}

extension ArticlesViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return articles.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: ArticleTableViewCell = tableView.dequeueReusableCell(for: indexPath)
        cell.authorLabel.text = articles[indexPath.row].author
        cell.previewImageView.setImage(from: articles[indexPath.row].urlToImage)
        cell.theTitleLabel.text = articles[indexPath.row].title
        return cell
    }
}

If you try to transition between the two view controllers by selecting a source, you will notice a crash. That’s because we need to pass the selected source from the Source view controller to the Articles view controller in it’s prepareForSegue implementation (Be sure to add an identifier in your Storyboard, I also chose to represent my Segues as an enum).

class SourcesViewController: UIViewController {
    /* omitted to save space */
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        switch segue.identifier ?? "" {
        case Segue.sourcesToArticles.rawValue:
            let selectedIndexPath = collectionView.indexPathsForSelectedItems?.first ?? IndexPath(item: 0, section: 0)
            let destination = segue.destination as! ArticlesViewController
            destination.source = sources[selectedIndexPath.row]
        default:
            ()
        }
    }
}

This should result in a successful transition from one view controller to the next, but when you select an article from the table view of the Articles view controller, unfortunately we run into another crash. This is because we need to add the implementation of UITableViewDelegate’s didSelectItemAtIndexPath to our Articles view controller. So let’s take a look:

extension ArticlesViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let article = articles[indexPath.row]
        if let url = URL(string: article.url ?? "") {
            let svc = SFSafariViewController(url: url)
            present(svc, animated: true, completion: nil)
        }
    }
}

Now, if we run it, it should push a web view controller when we do select an article.

Final Product

Here’s a video of what this app will look like with everything finished!

It looks great! I’m sure our designer will be proud!

Conclusion

We’ve seen how you can take a design and decompose it into views and view controllers, take an API spec and decompose it into model entities, and use that plan to implement an iOS app in Swift. To see some of the benefits this approach has and the arguments for it, I recommend checking out my last post on this topic. You should also know that this approach isn’t the only right way to develop in Swift for iOS or even nearly perfect. But it is the official design pattern for iOS and for good reason: it’s a reasonable place to start. In a forthcoming post, we’ll explore adding view models to this example. I’ll also write a post about the considerations in designing an API client. If you have any questions, feel free to add a comment below, reach out to me, or if you happen to be reading this before September 20th, 2017, come check this out live at the Noble iOS Meetup. Here’s the full file for those that want to check out the full working version.

What is Model-View-Controller (MVC) and why does iOS use it?

Last week I explored some implementation details of MMVM on iOS, but I realized that for people just beginning with iOS, this post was going to be of no help because it assumes knowledge of the more basic Model-View-Controller (MVC) design pattern. To rectify that, today we’ll explore MVC. This post is meant for someone that is new to iOS, perhaps they’re in a bootcamp or a class or teaching themselves; this will only be useful to very junior developers, but let’s roll.

Some theory and graphs

MVC is a way of organizing your code that allows you to divvy up the work of writing a feature of an application into three independent parts: the model, the view, and the controller. The model is your representation of your app’s subject – for instance, if you’re making a social networking app, a natural “model” class would be the “User” class, where username, bio, and profile picture are stored. The view, on the other hand, is what the user actually sees, and it will more likely than not manifest itself as a “UIView” class, such as UITextView or UIImageView, which you might have in a “UserProfileView” for your social network, for example. The controller is what sits in between these two layers of code, requesting from the model the information to pass to the view for presentation to the user. Here’s a graph of what this relationship looks like:

This graphs makes it clear how the user actions flow through your layers and how this results in an update to what the user sees. The “view” picks up the user’s interaction and sends the message of being tapped or swiped to the controller, which uses this message to tell the model layer to update itself, which in turn sends a message back to the controller of success or failure to update, which cascade into the view, finally getting presented to the user there.

Your application isn’t limited to just one of these objects, quite the contrary, an application is going to have many MVC groups working together to create the final product:

As a project grows like this, you’ll eventually find that you stop thinking about features in terms of 3 unique MVC items each, but more as “layers”. The reason for this is that for big projects, a controller will end up with a multitude of views and models each, where a checkout view controller, for example, might also use a user model and product model to populate its checkout view and the subviews.

More practically, some code

Let’s write some code that illustrates just the bare bones principles outlined above: that we should strictly separate our views from our models, and use a controller to glue the two together. Our example app is going to be a tap counter that has a User for sake of staying true to some of the images above.

Model

The easy part should come first, here’s what a model looks like:

struct UserModel {
 var username: String
 var tapCount: Int
}

This struct models our “problem”: we want to display a username and the number of times that user has tapped our app, and so that’s all our struct represents. There is no mention of UIViews of UIViewControllers, this model is completely independent of that. In fact, all you need to be able to utilize this model is the Swift language, wherever it might be running, on a Mac, iPhone, iPad, and perhaps on day on the server too, but that’s a topic for another day.

View

Now let’s create a view. Our view is going to need a button to receive the tap, and a label to display the username and the tap count. On iOS and with Swift, that looks like this:

class ProfileView: UIView {
 let button = UIButton()
 let label = UILabel()
}

Because we’re doing this in a playground, we’re going to need to configure our UIView programmatically. This isn’t so relevant to modern iOS, but it also isn’t very difficult. In our ProfileView, we’re going to implement a custom initializer like this:

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .blue
        button.setTitleColor(UIColor.white, for: .normal)
        button.setTitleColor(UIColor.gray, for: .highlighted)
        button.addTarget(self, action: #selector(didTapButton(sender:)), for: .touchUpInside)
        button.backgroundColor = .black
        button.layer.borderWidth = 1
        button.layer.borderColor = UIColor.white.cgColor
        button.layer.cornerRadius = 5
        label.textColor = .white
        let stackView = UIStackView(arrangedSubviews: [button, label])
        stackView.axis = .vertical
        stackView.alignment = .center
        stackView.spacing = 20
        addSubview(stackView)
        stackView.bindFrameToSuperviewBounds() /* see implementation later in this exercise */
    }

Because we want a strict separation between the model layer and the view layer, we’re not going to add a variable for the user in our view, as that could lead to non-canonical user instances floating about, that is, versions of the user that aren’t controlled by their rightful controller, we’re going to add a function that configures our view for a user, like so:

    func configure(with user: UserModel) {
        button.setTitle("Tap here", for: .normal)
        label.text = "\(user.username) Tap Count: \(user.tapCount)"
    }

Going back to our graphs from earlier, we see that the UIView is meant to handle user interaction, and in our initializer we declared that our button was to tell this view when it is touched-up-inside, so we’re going to need to implement that function. Before we do that, to keep our separation between Controller and View layers, we’re also going to need a delegate using a Swift protocol to sit between the two layers. That’ll look like this:

protocol ProfileViewDelegate: NSObjectProtocol {
    func profileViewDidTapButton()
}

class ProfileView: UIView {
    /* ommitted to save space */
    
    weak var delegate: ProfileViewDelegate?
    
    /* ommitted to save space */
    
    func didTapButton(sender: UIButton) {
        delegate?.profileViewDidTapButton()
    }
}

Controller

Now that both our view and model are completely set up, it’s time to write some code that glues these two layers together. We’re going to create a UIViewController and give it a view and a model as properties:

class ProfileViewController: UIViewController {
    let profileView = ProfileView(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
    var userModel = UserModel(username: "PLJNS", tapCount: 0)
}

We’re now going to need to configure our view with our model and position it, let’s do that in viewDidLoad:

    override func viewDidLoad() {
        super.viewDidLoad()

        profileView.configure(with: userModel)
        profileView.center = view.center
        profileView.delegate = self

        view.addSubview(profileView)
    }

We now should find that this is all well and good, except that we need our view controller to conform to our view’s delegate’s protocol so that they can communicate when the user taps, let’s add it in an extension:

extension ProfileViewController: ProfileViewDelegate {
    func profileViewDidTapButton() {
        userModel.tapCount += 1
        profileView.configure(with: userModel)
    }
}

Okay, but why?

The benefits of adopting this style of divvying up the work are that it allows you to sometimes reuse code, it decouples view logic from model (or “business”) logic making your code more amenable to change, and it can reduce the amount of bugs you have by helping not to introduce them. In our example, we could take our UserModel everywhere. We could have another view controller conform to our view’s protocol. We could change the UILabel to a UITextView. We can do this because all of the parts are independent from one another.

This isn’t the only way to organize your project, and as you develop bigger projects you may find that this approach has downside too. For instance, our model and view layer aren’t really that separated in that the know about one another’s existence, so if you move from a UserModel to something else you’d have to update that code. One solution to this problem is know as MVVM, which I cover here. You might also find that because a “controller” is just whatever isn’t a view or model, it ends up being an awful lot indeed, perhaps 10s of thousands of lines if you’re not careful. This is playfully known as massive view controller, and it can be a serious hindrance to your application. One design patterns to solving this problem is known as VIPER, which I’ll cover in a future post.

You can find this code in this post in Playground form here.

Considerations in implementing MVVM in iOS with Swift

I’ve been researching iOS design patterns searching for new techniques for writing correct, fault-tolerant, and maintainable code as quickly as possible, and I’ve realized a terminological inexactitude has led to some confusion in design discussions I’ve had in the past. I think most people may be talking about implementing a layer of abstraction between the view controller and the model, delegating querying the model for information. This has it’s uses, but what I’ll be covering here is placing a layer of abstraction between the view and controller and calling that a view model.

One popular approach to application architecture in iOS is known as MVVM, or Model-View-ViewModel, developed by Microsoft around 2005. What I thought a view model was about was a “model” of a UIView’s desired input. Roughly, the “view model” of a UILabel would be a String, because you can set and get the string of the label. So imagine you had a custom UIView that looks something like this:

class ProfileView: UIView {
 @IBOutlet weak var userImageView: UIImageView!
 @IBOutlet weak var nameLabel: UILabel!
 @IBOutlet weak var biographyTextView: UITextView!
}

Instead of exposing the image view, label, and text view to the user of this class, which is desirable because the implementation of label or text view or that might very well change in the future, you “model” this view with a lightweight structure that looks something like this:

struct Model {
 let userImage: UIImage?
 let fullName: String?
 let biography: String?
}

Which enables you label the subviews of profile view as private and to write a derived property on your profile view that looks like this:

var model: Model? {
 get {
  return Model(userImage: userImageView.image,
  fullName: nameLabel.text,
  biography: biographyTextView.text)
 }
 set {
  userImageView.image = model?.userImage
  nameLabel.text = model?.fullName
  biographyTextView.text = model?.biography
 }
}

This allows you to hide the implementation of the view to users of it, define how you want the input of a view to be structured (“full name” or “first name” and “last name”, for instance), and you can then write extensions on your actual model layer to get the input you want. Like this, for instance:

class User {
 var image: UIImage?
 var firstName: String?
 var lastName: String?
 var biography: String?
}

extension User {
 var profileViewModel: ProfileView.Model {
   return ProfileView.Model(userImage: image,
                            fullName: "\(firstName) \(lastName)",
                            biography: biography)
 }
}

Another way of implementing this pattern that might have some benefits if you’re interested in testing is with protocols. You won’t be able to add the model as a nested class of your view, which can make organizing code easier. Instead of having the view model generated in an extension, you could make the view model a protocol:

protocol ProfileViewModelProtocol {
 var userImage: UIImage? { get }
 var fullName: String? { get }
 var biography: String? { get }
}

And then instead of making the view model a derived property on the user, you add conformance to this protocol in an extension on your model:

extension User: ProfileViewModelProtocol {
 var userImage: UIImage? {
   return image
 }
 var fullName: String? {
   return "\(firstName ?? "") \(lastName ?? "")"
 }
 var biography: String? {
   return bio
 }
}

And then the property of the profile view becomes something like this:

 var model: ProfileViewModelProtocol? {
  didSet {
    userImageView.image = model?.userImage
    nameLabel.text = model?.fullName
    biographyTextView.text = model?.biography
   }
 }

But this only defines communication one way. Models change. So how does this approach to MVVM tackle that? Let’s say the user can modify the biography in this profile. We’ll need to implement UITextViewDelegate on ProfileView and define a ProfileViewDelegate:

protocol ProfileViewDelegate: NSObjectProtocol {
 func biographyDidChange(_ biography: String)
}

class ProfileView: UIView, UITextViewDelegate {
  /* ... */
 weak var delegate: ProfileViewDelegate?
 
 func textViewDidChange(_ textView: UITextView) {
   delegate?.biographyDidChange(textView.text)
 }
}

And the pattern all comes together in our hypothetical ProfileViewController:

class ProfileViewController: UIViewController, ProfileViewDelegate {
 @IBOutlet fileprivate weak var profileView: ProfileView!
 var user: User?
 override func viewDidLoad() {
   super.viewDidLoad()
   profileView.model = user
 }
 
 func biographyDidChange(_ biography: String) {
   user?.bio = biography
   // inform API
 }
}

To make this version clear, here’s a nice graphic I made for you:

This graphic makes the benefits clear in that there’s a level of abstraction in-between the view and the controller which is responsible for translating between the model layer and the view layer. If I find a good example of the other variety of MVVM, I’ll investigate and write up a post about it. Here’s a playground with all the code from this post.

Getting Laravel to use the Bootstrap 4 Alpha

I’m developing a Markdown-based notes taking platform with Laravel, and I want it to use all the latest and greatest CSS framework: the Boostrap 4 Alpha. To get this set up, I had to learn how web applications and Laravel maintains dependancies and packages code. The default site that Laravel generates has some links on the default page, and if you add the built-in authentication with PHP Artisan, those pages are served with an older version of Bootstrap. So how do you change this?

First, you need to add Bootstrap 4 Alpha as a dependency in the NPM dependency file “package.json” like, as well as Laravel’s version of Gulp called “Elixir” and it’s version of “Webpack”, another JS tool, like so:

"laravel-elixir": "^3.0.0",
"bootstrap-v4-dev": "^4.0.0-alpha.6",
"laravel-elixir-webpack": "^1.0.1"

You should then run NPM’s install to get the latest files. Now, navigate to the SCSS file in your Resources/Assets/SASS directory from your root Laravel directory. In app.scss, remove any unneeded lines, and make it look like this:

@import "node_modules/bootstrap-v4-dev/scss/bootstrap.scss";

This imports the new version of Bootstrap instead of whatever version your project came with. When we run Gulp, this will compile the latest Bootstrap SCSS files for your Laravel application, but we’ll also need to update the JavaScript file. Navigation to the Bootstrap JS file in Resources/Assets/JS, and make replace any mention of the Bootstrap JS (probably “bootstrap-sass”) file with this line:

require('bootstrap-v4-dev');

With your dependancies installed and your assets pointing towards Bootrap 4, it’s time to set up Gulp so that you can compile these into your web application. Create a “gulpfile.js” in your root directory and add these lines:

var elixir = require('laravel-elixir');
var elixir = require('laravel-elixir');
require("laravel-elixir-webpack");

elixir(function(mix) {
   mix.sass('app.scss').webpack('app.js');
});

Now, when you run “gulp” in your root directory, you should find that your CSS and JavaScript have been updated to Bootstrap 4.

How I picked Laravel Homestead as my first backend development platform

As an experienced iOS developer, I interface all the time with backend services, and JSON RESTful APIs in particular. It’s a fairly common story for iOS developers to begrudge their work being blocked by backend holdups or bugs, and so, I thought I might as well try to try my hand at backend development to see if I could fix these problems myself.

Working on Apple platforms is simple. Language? Swift. OS? MacOS. IDE? Xcode. On and on, many questions have one answer. So you can imagine my uneasiness when asking the same questions on my first steps into backend development. Language? Uh, Ruby or PHP or Javascript or Java or … OS? Well, you can develop on whatever you want and you can run software on whatever you want, but probably something UNIXIDE? Well, what OS did you pick? And what language? And why aren’t you using Vim you filthy casual? (Emacs get out.)

Okay. I had some choices to make. I’ve heard from a few sources that backend should be old, boring, and crucially, reliable. I could think of no better candidate than PHP, and given that a few of the projects I’ve worked on have successfully deployed with PHP and I have some previous experience with it, it seemed like a reasonable first choice.

But I don’t want to fall into the trap of writing bad code, which I understand is easy to do in PHP, and I also don’t want to write code that has been written better by people that came before me. So I did some digging for PHP frameworks, and I found Symphony, CodeIgniter, and Laravel. The way that I picked one of these was the very scientific approach of picking the one with the most starts on GitHub, for better or worse, which at time of writing is Laravel.

I now set out to get a development environment up and running for Laravel, and to do that, here’s what you do. You’ll need to download Vagrant, which is a manager for virtual machines, VirtualBox, which is a virtualization engine, and Homestead, which is a nicely configured Laravel virtual machine. Homestead uses Vagrant which runs on VirtualBox.

To get this up and running, I found these tutorials very useful:

It took a while, but I now have it working, and I’m ready to start developing my Laravel app.

Display an HTML encoded String in a UITextView without changing characters to emoji

I wanted to display some text in a UITextView, and one of the glyphs was a Unicode checkmark, which I didn’t think anything of. But what I was finding was that when iOS rendered the checkmark, it was an emoji version instead of the boring old Unicode variant.

Before I ran into that issue though, I had to solve how to turn an encoded HTML string into something useable. A string like this:

<b>Hello</b><br><p>This is normal text.</p><br>

So I wrote an extension on attributed string to solve this problem, which uses some hackery to coax iOS into parsing and rendering the string for me:

extension NSAttributedString {
    convenience init?(htmlEncodedString: String) throws {
        if let data = htmlEncodedString.data(using: .unicode) {
            let rawHTML = try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil).string
            let styledHTML = "\(rawHTML)"

            if let htmlData = styledHTML.data(using: .unicode) {
                try self.init(data: htmlData, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil)
            } else {
                return nil
            }
        } else {
            return nil
        }
    }

It abuses the fact that NSAttributedString can take an NSData, which can understand HTML encoding, and then you can grab the decoded HTML string from it. At runtime, the raw HTML variable will look like:

<b>Hello</b><br><p>This is normal text.</p><br>

After that, NSAttributedString can understand this HTML and turn it into something you can render for the user. The weirdness comes when you include Unicode characters like the following:

✉✔✌✍❤☀☂☯☢☎❄▶◀

I cannot guarantee that these are rendering the same on your machine, particularly if iOS has the same behavior in browser. For sake of precision, these values in encoded Unicode are supposed to be:

0x2709, 0x2714, 0x270C, 0x270D, 0x2764, 0x2600, 0x2602, 0x262F, 0x2622, 0x260E, 0x2744

But these were rendering in the UITextView as all emoji!? I found that solution was to use this scantily documented “Unicode variance selector” by suffixing the   violating Unicode values with it. Granted, I do not know if this is a definitive list of the Unicode values which do this on iOS, but I’ve wrapped all this up in an extension which you can use for your own purposes:

extension String {
    var escapingCharactersWithVariationSelector0E: String {
        var newStr = ""
        for unicodeScalar in unicodeScalars {
            switch unicodeScalar.value {
            case 0x2709, 0x2714, 0x270C, 0x270D, 0x2764, 0x2600, 0x2602, 0x262F, 0x2622, 0x260E, 0x2744:
                var escapedScalar = String(Character(unicodeScalar))
                escapedScalar.append("\u{0000FE0E}")
                newStr.append(escapedScalar)
            default:
                newStr.append(Character(unicodeScalar))
            }
        }

        return newStr
    }
}

To wrap this all up, if you’d like to display:

var str = "&lt;b&gt;Hello&lt;/b&gt;&lt;br&gt;&lt;p&gt;This is normal text.&lt;/p&gt;&lt;br&gt; ✉✔✌✍❤☀☂☯☢☎❄▶◀"

You can use:

do {
    textView.attributedText = try NSAttributedString(htmlEncodedString: str.escapingCharactersWithVariationSelector0E)
} catch {
    ()
}

Please share the other Unicode values that do this! And check out the attached Playground which demonstrates the effect.

StringPlayground.playground

Highlights from Theresa May’s address to Congressional Republicans

Theresa May’s address to Congressional Republicans:

“We must never cease”, Churchill said, “to proclaim in fearless tones the great principles of freedom and the rights of man which are the joint inheritance of the English-speaking world and which through Magna Carta, the Bill of Rights, the Habeas Corpus, trial by jury, and the English common law, find their most famous expression in the American Declaration of Independence”.

So it is my honour and my privilege to stand before you today in this great city of Philadelphia to proclaim them again, to join hands as we pick up that mantle of leadership once more, to renew our Special Relationship and to recommit ourselves to the responsibility of leadership in the modern world.

And it is my honour and privilege to do so at this time, as dawn breaks on a new era of American renewal.

For I speak to you not just as Prime Minister of the United Kingdom, but as a fellow Conservative who believes in the same principles that underpin the agenda of your Party. The value of liberty. The dignity of work. The principles of nationhood, family, economic prudence, patriotism – and putting power in the hands of the people.

[…]

New enemies of the West and our values – in particular in the form of Radical Islamists – have emerged.

And countries with little tradition of democracy, liberty and human rights – notably China and Russia – have grown more assertive in world affairs.

The rise of the Asian economies – China yes, but democratic allies like India too – is hugely welcome. Billions are being lifted out of poverty and new markets for our industries are opening up.

But these events – coming as they have at the same time as the financial crisis and its fall out, as well as a loss of confidence in the West following 9/11, the military interventions in Iraq and Afghanistan, and sporadic terrorist attacks – have led many to fear that, in this century, we will experience the eclipse of the West.

But there is nothing inevitable about that. Other countries may grow stronger. Big, populous countries may grow richer. And as they do so, they may start to embrace more fully our values of democracy and liberty.

But even if they do not, our interests will remain. Our values will endure. And the need to defend them and project them will be as important as ever.

So we – our two countries together – have a joint responsibility to lead. Because when others step up as we step back, it is bad for America, for Britain and the world.

It is in our interests – those of Britain and America together – to stand strong together to defend our values, our interests and the very ideas in which we believe.

[…]

Because of these strong economic and commercial links – and our shared history and the strength of our relationship – I look forward to pursuing talks with the new Administration about a new UK/US Free Trade Agreement in the coming months. It will take detailed work, but we welcome your openness to those discussions and hope we can make progress so that the new, Global Britain that emerges after Brexit is even better equipped to take its place confidently in the world.

Such an agreement would see us taking that next step in the special relationship that exists between us. Cementing and affirming one of the greatest forces for progress this world has ever known.

AP: “Equipment Didn’t Detect North Dakota Oil Leak”

The Associated Press via ABC:

Electronic monitoring equipment failed to detect a pipeline rupture that spewed more than 176,000 gallons of crude oil into a North Dakota creek, the pipeline’s operator said Monday.

It’s not yet clear why the monitoring equipment didn’t detect the leak, Wendy Owen, a spokeswoman for Casper, Wyoming-based True Cos., which operates the Belle Fourche Pipeline, said.

A landowner discovered the spill near Belfield on Dec. 5, according to Bill Suess, an environmental scientist with the North Dakota Health Department.

I can’t tell if this is unbelievable or completely believable, but either way this is terrible.

United Airlines will charge for overhead bins

Ben Brooks:

United has a new ticket fare, where no luggage is included in the price (except what fits at your feet). If you want overhead bin space, or to check, you pay. I actually love this, though I would much rather checked luggage be free and overhead charged for everyone.

I have no doubt this scheme is at least partly motivated by a desire for increased revenue on the side of the airlines, but I’m pleased that people will now be forced to more deliberate in the size and location of their bags when flying – a couple of times I’ve had pieces of luggage damaged by people cramming in overheads.

Shared interests of the populist right and the progressive left

Jeremy Corbyn via the BBC on the relationship between the progressive left and populist right:

“They are political parasites feeding on people’s concerns and worsening conditions, blaming the most vulnerable for society’s ills instead of offering a way for taking back real control of our lives from the elites who serve their own interests.

“But unless progressive parties and movements break with a failed economic and political establishment, it is the siren voices of the populist far right who will fill that gap.”

The Labour leader said economic conditions had been exploited by the populist right.

“We know the gap between rich and poor is widening; we know living standards are stagnating or falling and insecurity is growing; we know that many people rightly feel left behind by the forces unleashed by globalisation, powerless in the face of deregulated corporate power,” he said.

Bernie Sanders via CBS This Morning:

“We will hold Mr. Trump accountable. We have all of the things he has said and we are going to say to Mr. Trump, if you have the courage to actually stand up to the big money and trust of the billionaire class, if you have the courage, in fact, to develop policies to improve lives for working people count us in,” Sanders said. “You want for increase the infrastructure and way equity for women, we are on your side.”
Two different countries, politicians, and messages, but same cautious view of the populist right.

 

WSJ: “China’s Dalian Wanda Group Faces Renewed U.S. Regulatory Scrutiny”

The Wall Street Journal reports of Chuck Schumer, New York Senator and House Minority Leader:

Mr. Schumer said the ability for Chinese companies to take a majority stake in U.S. assets, often backed by state officials and China’s sovereign-wealth funds, is unfair considering stateside companies are handicapped from doing similar deals in China. U.S. companies hoping to do business in China usually have to form a joint venture that often includes the sharing of intellectual property—an arrangement that Mr. Schumer called a “pay to play system.”

I was critical of the decision to go with Schumer as minority leader, but if he continues to take action like this, I would gladly retract that.

Send as text message in iOS 10

Michael Tsai:

I found several forum posts, but the only solution seems to be to temporarily turn off iMessage, which seems like a terrible solution because it means that you won’t be able to receive iMessages from anyone else in the interim. Worse, the iMessages will look to the sender like they got delivered because they’ll still go to your Mac or iPad.

Ideally, there would be a way to simply start a new conversation using SMS even though there is an iMessage account associated with that phone number.

I absolutely agree. A text message is preferred when reception is spotty, and this whole thing gets very confusing when your talking to someone who has an iMessage account separate from their phone number and a phone number with SMS.

Mike Pence went to see Hamilton

From the New York Times:

As the play ended, the actor who played Aaron Burr, Brandon Victor Dixon, acknowledged that Mr. Pence was in the audience, thanked him for attending and added, “We hope you will hear us out.”

I don’t support this – Mike Pence is a paying customer to a see a play, and he should be treated by the establishment as equally as possible. Even if the message is fairly innocuous, I don’t think this was a classy move to do without Mike Pence’s approval. However, with regards to:

When Mr. Pence entered the Richard Rodgers Theater in Manhattan, he was greeted with a mix of clapping and booing, according to theatergoers who posted on Twitter.

While I don’t support this treatment of the vice-president elect, I think this is a fair expression of the theater-goers First Amendment rights – if Mike Pence is free to express his anti-gay beliefs, which he is and he should be, he also must face the public, especially metropolitan, opposition to these views.

Donald Trump and the Paris Accord

Donald Trump has appeared to or has been characterized as pulling back on his promises to “build a wall”, “drain the swamp”, “lock her up”, and more. But if there’s any campaign promise I want him to pull back on, it’s not implementing the Paris Accord. From Democracy Now!:

As Democracy Now! broadcasts from the U.N. climate talks in Marrakech, Morocco, we report that nearly 200 nations have agreed on a proclamation that declares implementation of the Paris climate accord to be an “urgent duty.” This comes just over a week after the election of Donald Trump, who has vowed to pull the United states out of the Paris Agreement and has called climate change a Chinese-created hoax. Meanwhile, climate activists staged protests targeting corporate sponsors of the climate talks.

Even if there were a plausible case for skepticism in man-made global climate change, the gamble of potentially making large swaths of land uninhabitable and unarable is not worth the risk.

iPhones send call history to Apple if you’ve enabled iCloud

The Intercept reported via a digital forensics firm that iPhones with iCloud enabled send user’s call history to Apple servers:

Russian digital forensics firm Elcomsoft has found that Apple’s mobile devices automatically send a user’s call history to the company’s servers if iCloud is enabled — but the data gets uploaded in many instances without user choice or notification.

“You only need to have iCloud itself enabled” for the data to be sent, said Vladimir Katalov, CEO of Elcomsoft.

This can be justified. Apple do a number of things with your phone call: they allow you to answer calls on any of your devices, they allow third parties to make VoIP calls that look and feel like normal phone calls, for instance. Apple’s response:

“We offer call history syncing as a convenience to our customers so that they can return calls from any of their devices,” an Apple spokesperson said in an email. “Device data is encrypted with a user’s passcode, and access to iCloud data including backups requires the user’s Apple ID and password. Apple recommends all customers select strong passwords and use two-factor authentication.”

It is still technically accessible to law enforcement via a subpoena, but granted, I believe this is true anyway given that carriers would happily provide call logs too. The mistake Apple made here is not in the actual behavior of the phone, but in the disclosure to users. This should have been made clear to the user, or at least found in their famously long agreements.

ProPublica exposes professors being hired by corporations to justify their mergers.

The most straightforward example of corporate purchase of academic economic research in their favor that ProPublica found was Dennis Carlton:

Dennis Carlton, a self-effacing economist at the University of Chicago’s Booth School of Business and one of Compass Lexecon’s experts on the AT&T-Time Warner merger, charges at least $1,350 an hour. In his career, he has made about $100 million, including equity stakes and non-compete payments, ProPublica estimates. Carlton has written reports or testified in favor of dozens of mergers, including those between AT&T-SBC Communications and Comcast-Time Warner, and three airline deals: United-Continental, Southwest-Airtran, and American-US Airways.

This is the elitism that is the source of America’s growing populism, with academic class gorging themselves on corporate-funded and government subsidized hit-peice publications that justify decisions that benefit that same academic, political, banker, and corporate class. The politicians making the most noise about this are hugely popular: Bernie Sanders, Elizabeth Warren, Ron Paul, and Donald Trump come immediately to mind. ProPublica continue:

In addition, politicians such as U.S. Senator Elizabeth Warren have criticized big mergers for giving a handful of companies too much clout. President-elect Trump said in October that his administration would not approve the AT&T-Time Warner merger “because it’s too much concentration of power in the hands of too few.”

The merge has the same affect as trade deals: while it’s true that a broad view of the economy shows that there’s more capital in the system, it disproportionally benefits the rich and punishes the poor. Democrats and Republicans alike have been increasingly cozy with ex-corporate interest “independent” lobbyists which later become politicians themselves before getting hired by a corporation again. Obama in 2008 had a populist message, and moving to 2016 he’s become everything people didn’t vote for: bigger trade deals and bigger mergers and acquisitions:

A late Obama administration push to scrutinize major deals notwithstanding, the government over the past several decades has pulled back on merger enforcement.

The rest of the article explores how Apple’s iBooks price fixing scandal and the AT&T/Time Warner deal are examples of being technically advantageous to the United States on grounds that while the customers face a bigger burden, the corporation can take advantage of efficiencies to deliver more value to shareholders. And if this difference is net positive, they argue, it is a good merger. But this is false because empowering the people at the base of the economy with competition for cost and features is better for more people and has broader positive economic effects. When consumers have more money, they can afford more, take a chance at starting a business, have a kid, and many more positive outcomes. But when a very narrow group of executives, politicians, and academics funnel more money into their accounts by taking advantage of efficiencies in economics of scale, they’re actually delivering capital to where it is least needed. ProPublica conclude:

Today, AT&T’s much grander takeover of Time Warner will be an early test case for president-elect Trump, who feuded during the campaign with CNN, a Time Warner property.

If Trump blocks the deal, I hope it’s the first in a series of good decisions; if he allows the deal, he’ll have completely repudiated his claim that he’ll “drain the swamp.” Ideally, the populist liberals and conservatives in all the branches of government can unify to fight this establishment corporatism.

Facebook promises its users more censorship

Facebook via TechCrunch:

We take misinformation on Facebook very seriously. We value authentic communication, and hear consistently from those who use Facebook that they prefer not to see misinformation. In Newsfeed we use various signals based on community feedback to determine which posts are likely to contain inaccurate information, and reduce their distribution. In Trending we look at a variety of signals to help make sure the topics being shown are reflective of real-world events, and take additional steps to prevent false or misleading content from appearing. Despite these efforts we understand there’s so much more we need to do, and that is why it’s important that we keep improving our ability to detect misinformation. We’re committed to continuing to work on this issue and improve the experiences on our platform.

It’s amazing how straightfacedly and unironically this VP admits to and endorses censorship, as though they have some unique access to the truth, like the solution to Trump getting elected is even more media control. But to their point, it’s their platform, and they can control the flow of information all they want, to me it’s another reason not to use Facebook.

It should’ve been President Sanders

While the result of the presidential election is upsetting to me on grounds of many of my personal beliefs – namely, that anthropogenic climate change is an existential threat to humanity, that everyone should be allowed to live the life they want with whoever they love, that a country as wealthy as the United States should guarantee its citizens healthcare as a human right, among others – I’m pleased because it was a triumph for democracy.

The reason the Republicans won is that even though almost every establishment figure was wary of Trump, when the results of their primary came in, Republicans did the right thing for democracy and accepted it, however reluctantly or reservedly. Contrastingly, the Democrats impeded Sanders at every step of the way, preemptively blaming him for Clinton’s loss, threatening him, slandering him, and otherwise fudging their primary to the favor of Clinton. Is it any surprise then that it resulted in a candidate that no one wanted. Before you demonize me and profess your passion for Clinton, consider that Trump didn’t win so much as Clinton lost. Look at the voter turnout of 2008, 2012, and 2016, and you’ll see that it shows that Republicans had a typical showing, and that no Democrats came to the polls. Even if some people are passionate about Clinton, the Democratic primary still failed to pick a popular candidate because establishment politicians forced their candidate through with super delegates, manipulation of the media, and threats, and these people are the ones responsible for letting Trump win.

If Democrats continue to blame third-party candidates, “Bernie-bros”, the FBI, Russians, WikiLeaks, whoever, for the failing of their top-down chosen candidate to garner popular support, they’ll continue to lose elections. If Democrats continue to retort to Republicans concerns about terrorism and immigration with “that’s racist”, they’re not going to convince voters as much as they’re going to silence them, because even if it’s true it’s an unpersuasive argument. This will only distort the polls, fail to convince people, and the Democrats will continue to lose election. If the Democrats continue to garner “right side of history” support using identity politics, they’ll alienate rural and suburban people who vote on economic and foreign policy issues, and they’ll continue to lose elections. Before you label me or any Trump voter a racist, which is the type of moralizing blame-shifting that’s losing Democrats elections, consider that the Rust Belt and Bible Belt voters chose Obama, an anti-establishment populist Democratic, twice over a white conservative establishment figure. Those people aren’t white supremacists, they’re the backbone of our country, and if Democrats continue to treat democracy with contempt, it won’t matter that the Democrats automatically get 55 delegates from California, they’ll continue to lose elections.

I’m pleased with the result of the election despite being upset with the winner because Democrats deserved to lose for their blatant disregard for the will of the people, the only legitimate source of power.

Self-hosted content versus centralized third-party services

Andy Baio via Ben Brooks

Here, I control my words. Nobody can shut this site down, run annoying ads on it, or sell it to a phone company. Nobody can tell me what I can or can’t say, and I have complete control over the way it’s displayed. Nobody except me can change the URL structure, breaking 14 years of links to content on the web.

While I may cross-post some content to Apple News, Medium, and other services as they spring up — I won’t cross post everything and I certainly don’t trust those sites to ever be more than a passing fad. Having my own site gives me complete control to do whatever I want, whenever I want, however I want. I don’t understand why people ever want it any other way.

This is right on the money: I haven’t been on the Internet as a browser or producer for even a fraction of its total life, and I’ve still seen the rise and fall of many websites. MySpace, Digg, Friendster … there is no reason to believe that the trendy publishing platforms of today will be around tomorrow, in fact quite the contrary. While I take this to be an argument against using these services and have no desire to change, I do suspect that this is a somewhat selfish and hermetic Internet existence, where many people would argue Internet introverts have a lot more to gain from centralized platforms than they’re giving up. Specifically, because it’s centralized, the audience is centralized, discovery is easier, and the value of the interactions that happen while the site is live far outweigh the risks of losing that data or ability once the service invariable tanks, either by shutting down or with some insipid monetization scheme.

Perhaps, perhaps not.

More Samsung recalls

NBC News via John Gruber:

Samsung has one more fire to put out: The South Korean company announced on Friday that it was recalling 2.8 million top-load washing machines, following reports of “impact injuries” that included a broken jaw.

The problem stems from unbalanced drums, which can separate from the washer and generate enough internal force to cause other parts of the washer to detach — and, in some cases, be launched out of the machine.

Samsung is also the subject of an August lawsuit from owners who said their machines “explode during normal use.”

Investors.com via Macrumors via /r/apple

Apple was No. 1 by a mile in smartphone operating profit in Q3. Among major vendors, Samsung was No. 2 in smartphone profits with a tiny 0.9% share, he said. Money-losers in the smartphone business last quarter included LG and HTC […].

Perhaps Samsung should cut their losses, play to their strengths, and enter the very lucrative munitions industry. Snark aside, I’m amazed they turned any profit at all after their Note 7 debacle, and in the interest of healthy competition I hope they rebound quickly. I’d still argue their biggest problem isn’t their exploding phones, it’s their operating system, if they had an OS that could even shine a light on iOS in terms of battery efficiency, their batteries wouldn’t need to be nearly as big or would last twice as long.