Do the right way with Swift part 2

Michael Tran (mytee)
7 min readApr 21, 2018

Dummy screen, Comments, templates, naming, static Table…

The previous part is here

Using dummy data

FB dummy

You might notice in slow connection, your facebook app screen is filled with the dummy like the above pic. It looks weird, but less irritating than the spinning loading sign. Tumblr app, store and load your last cards -stored in local storage -. This is much smarter than the weird screen above.

Why? in lazy cancer syndrome, people can do thing like this

func getUserData( callback: @escaping (_ result: String) -> ()) {

let myUrl = URL(string: “https://www.google.com”);
var request = URLRequest(url: myUrl!)
let session = URLSession.shared;
request.httpMethod = “GET”
request.addValue(“application/json”, forHTTPHeaderField: “Content-Type”)
request.addValue(“application/json”, forHTTPHeaderField: “Accept”)
request.httpBody = jsonData

DispatchQueue.global().async() {
let task = session.dataTask(with: request) { data, response, error in
guard let result = data, error == nil else {
print(“\(error?.localizedDescription ?? “Unknown error”)”); return; }
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print(“statusCode should be 200, but is \(httpStatus.statusCode)”)
print(“response = \(response)”); }
let responseString = String(data: result, encoding: .utf8)
// print(“responseString = \(responseString)”)

DispatchQueue.main.async {
callback(responseString!) // update data here
}
} }
task.resume(); }

getUserData { text in
do { updateData() … }catch {…}}

You will find this works perfectly if 1-connection is fast. 2-data is small. Any of the above conditions doesnt match, then you got a blank screen for a while. A sinning cursor helps, but it is a wrong way to do.

Dont do like this approach

1-showing loading cursor.

2-load data from server.

3-display data only when data downloaded and processed.

4-hide loading cursor.

You know why. You will keep looking at the loading cursor for a while.

Do like this

1-showing loading cursor.

2-background loading data from server with dispatchQuere. ref here https://developer.apple.com/documentation/dispatch/dispatchqueue. In simplest way, the code is like this

DispatchQueue.global(qos: .background).async {
// do your job here

DispatchQueue.main.async {
// update ui here
}
}

This will do the loading in the background, and then update the UI when the data is ready.

3-foreground loading dummy screen, with either default -like FB- or last saved data — like Tumblr -.

4-hide loading cursor.

There is another issue here. Have you noticed, tumblr only send 10 posts per query? it is server side, however, this approach helps in case you deal with graphic files. From client side, knowing the buffer per query, you will keep track of data for appending to your array.

Dont use Generic function

Why people want to use generic? only when they believe the same function can be used in various cases. Question is: Would you be able to solve the problem without using generic? Yes. You would.

Look at the code after 6 months. You will wonder why you did that way and what you meant when you did this way. The generic function will take you hours to figure out why you did it and will take someone else days to figure out how to rewrite it.

Stay close to type function. If it returns an Integer, let it be an Integer. If the param type is a String, pass in it a String. Dont make it Any or AnyClass then type casting it. The bug for this mess is classified as misery because you might find it if user happens to input something far too wrong from typecasting, or you never find it as you and your QA would never expect to pass to the param such thing.

Dont pass more than 3 parameters in function

Use semi colon at end of statement for a good habit

If you live with Swift only, then it might not be necessary. Often, people work in several languages Java for Android; JavaScript for Nodejs … The semi colon indicates clearly that you already end the statement. It works with all languages, including Swift even it is not strictly required.

Use Comments

We have to do comments for several vital reasons

1- for ourselves when we read the code a few months later.

2- for people, as our ethnic and professional. The one who change your codes when you left wont cry on your work.

3-for your employers. They need the document that we can do with the document generator. The tool will generate the document from your comments.

Dont do like this

//name

//purpose

//param

//output

//usage

why? ”//” is line comment, it is for variable and logic comment, used only for If Else, define variables …

Do like this

if (thisCondition < thatCondition) {} // we use line comment here

let maxCount = 10 // line comment here

and, on top of the file

/* Name: GetPinViewController

*Purpose: validate the Pin and user input.

*Param: numeric string

*Output: True/false

*Usage: using weak var localData for Pin

*/

Also, on top of the func

/* Name: Alert

*Purpose: simple alert box.

*Param: title: string, message: string

*Output: none

*Usage: alert(“this is title”, “this is message”);

*/

func Alert(_ title: String, _ message: String) {…}

Note that the same template used for both header and the function.

Why? The module itself is called as a function in blackbox style. Furthermore, the document generator will do the layout of the whole structure. It shows from main/root to all modules and their internal functions in a clear diagram, if the comments are done properly. What? You dont know the document generator of PHP can do document for Swift?

Using template panel

In Xcode, you should use the template panel. It is the 2 curly brackets tab on the bottom right panel that looks like this {} as in the picture below.

tab on it, you will see many code templates.

Do like this

Copy this comment into your editor, then drag and drop it into the template panel. It will create a comment template for you. You might like to use a short cut code. Next time, you just drag and drop this template from the panel back into the editor, to the top of the file and func. You just fill the spaces, save the typing.

/* Name:

*Purpose:

*Param:

*Output:

*Usage:

*/

Why? from observation for last … decade, coder is lazy to do the comment because of its bore some. Using the template is more or less help. In my practice, it is a must anyway.

Using the right name for the module

Say if you have a class name LoginViewController, then the file must be save with the same name of the class. The swift file LoginViewController is for the class LoginViewController. The storyboard of this view controller should name LoginViewController.storyboard as well. Also, the storyboard ID of the view will be LoginViewController.

In summary, you will find in the login module folder

  • a swift file name LoginViewController.swift that is for the class LoginViewController
  • a storyboard file name LoginViewController.storyboard, in which the viewcontroller ID will be LoginViewController.

Why? later in the code, anything refers to LoginViewController, you know the definition of this class is in the file LoginViewController.swift and the UI of it will be in LoginViewController.storyboard.

With this practice, your team, your next coder wont spend hours to dig in the folders to find out what is what. The “goto definition” would be more efficient with this naming approach.

Also, the root module can call other sub module dynamically using a func like this:

func loadViewControllers(_ named: String) {
let storyboard = UIStoryboard.init(name: named, bundle: nil)
let targetViewController = storyboard.instantiateViewController(withIdentifier: named)
self.navigationController?.pushViewController(targetViewController, animated: true)
}

This is not ideal yet, as we will need to call the module as blackbox with param. However, we must apply this naming approach to enable the blackbox in the first place. We will discuss this soon enough.

Using static table

Static or Dynamic table?

Why on earth everytime I asked people, the answer always is that have to do dynamic table view with custom cell for image and 2 label views.

For the cell, the image and 2 labels are actually predefined. We dont need custom cell, we dont need to add them, they are already there even they are invisible on storyboard.

If you already bind the cell -say cell1 -, you can just call the image like this cell1.imageView.image = …

Here from apple document in https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html

“The UITableViewCell class defines three properties for this cell content:

The subviews in the cell have been predefined and formatted. We just use them, no need for custom cells and dynamic table.

You can still add your own image and labels in the cell, in case you prefer different presentation, like this

profile with static table

In summary, for the views that dont require dynamic table, dont use it.

Why? simply because static table loads much much faster than dynamic table. My test result is up to 10 times faster.

--

--