Skip to main content
fix gramma
Source Link

3. @IBAction should call other methods instead executing a logic code. Example: One would trigger a game start method and an analytics event once a button tapped.

private var x: Int?
private var y: Int?

@IBAction func startButtonPressed(_ sender: UIButton) {
    gameStartButtonPressed()
    Analytics.logAction("startButtonPressed")
}

private func gameStartButtonPressed() {
    guard let numberOfRooms = selectedRooms.text, !numberOfRooms.isEmpty else {
        return selectedRooms.placeholder = "type it, dude"
    } //if user typed something
    let rooms = Int(numberOfRooms)
                   
    x = Int(ceil(sqrt(Double(rooms!))))
    y = x //grab some values from user input
    
    guard let x = x, y = y else {
        return
    }
    guard let maze = MazeGenerator(x, y) else { //generate a maze
        return
    }
    hp = 2 * (x * y) //get hp value depending on user input
    hpLabel.text = "hp: \(hp)"
    
    guard let currentX = getRandomX(x), let currentY = getRandomY(y) else {
        return
    }
    currentCell = maze.maze[currentX][currentY] //game starts in a random part of the maze
                            
    for item in items.indices { //create and show some imageViews
        items[item].location = (getRandomX(x!), getRandomX(y!))
        createItems(imageName: items[item].imageName)
        if items[item].location == (currentX!, currentY!) {
            reveal(index: item)
        } else {
            hide(index: item)
        }
    }
    refreshButtons() //refresh UI
    maze.display() //print maze scheme in debug console
}

4. Separate a model from a controller

struct Model {
    var x: Int
    var y: Int
}

private var position: Model = .init(x: 0, y: 0)

// instead of:

private var x: Int?
private var y: Int?

Additional insights:

Additional insights:

3. @IBAction should call other methods instead executing a logic code. Example: One would trigger a game start method and an analytics event once a button tapped.

private var x: Int?
private var y: Int?

@IBAction func startButtonPressed(_ sender: UIButton) {
    gameStartButtonPressed()
    Analytics.logAction("startButtonPressed")
}

private func gameStartButtonPressed() {
    guard let numberOfRooms = selectedRooms.text, !numberOfRooms.isEmpty else {
        return selectedRooms.placeholder = "type it, dude"
    } //if user typed something
    let rooms = Int(numberOfRooms)
                   
    x = Int(ceil(sqrt(Double(rooms!))))
    y = x //grab some values from user input
    
    guard let x = x, y = y else {
        return
    }
    guard let maze = MazeGenerator(x, y) else { //generate a maze
        return
    }
    hp = 2 * (x * y) //get hp value depending on user input
    hpLabel.text = "hp: \(hp)"
    
    guard let currentX = getRandomX(x), let currentY = getRandomY(y) else {
        return
    }
    currentCell = maze.maze[currentX][currentY] //game starts in a random part of the maze
                            
    for item in items.indices { //create and show some imageViews
        items[item].location = (getRandomX(x!), getRandomX(y!))
        createItems(imageName: items[item].imageName)
        if items[item].location == (currentX!, currentY!) {
            reveal(index: item)
        } else {
            hide(index: item)
        }
    }
    refreshButtons() //refresh UI
    maze.display() //print maze scheme in debug console
}

4. Separate a model from a controller

struct Model {
    var x: Int
    var y: Int
}

private var position: Model = .init(x: 0, y: 0)

// instead of:

private var x: Int?
private var y: Int?

Additional insights:

Source Link

Code review:

1. use a guard statements to transform optional values to values.

private var x: Int?
private var y: Int?

@IBAction func startButtonPressed(_ sender: UIButton) {
    
    guard let numberOfRooms = selectedRooms.text, !numberOfRooms.isEmpty else {
        return selectedRooms.placeholder = "type it, dude"
    } //if user typed something
    let rooms = Int(numberOfRooms)
                   
    x = Int(ceil(sqrt(Double(rooms!))))
    y = x //grab some values from user input
    
    guard let x = x, y = y else {
        return
    }
    guard let maze = MazeGenerator(x, y) else { //generate a maze
        return
    }
    hp = 2 * (x * y) //get hp value depending on user input
    hpLabel.text = "hp: \(hp)"
    
    guard let currentX = getRandomX(x), let currentY = getRandomY(y) else {
        return
    }
    currentCell = maze.maze[currentX][currentY] //game starts in a random part of the maze
                            
    for item in items.indices { //create and show some imageViews
        items[item].location = (getRandomX(x!), getRandomX(y!))
        createItems(imageName: items[item].imageName)
        if items[item].location == (currentX!, currentY!) {
            reveal(index: item)
        } else {
            hide(index: item)
        }
    }
    refreshButtons() //refresh UI
    maze.display() //print maze scheme in debug console
}

2. If possible, define a properties as non optional

private var x: Int = 0
private var y: Int = 0

@IBAction func startButtonPressed(_ sender: UIButton) {
    
    guard let numberOfRooms = selectedRooms.text, !numberOfRooms.isEmpty else {
        return selectedRooms.placeholder = "type it, dude"
    } //if user typed something
    let rooms = Int(numberOfRooms)
                   
    x = Int(ceil(sqrt(Double(rooms!))))
    y = x //grab some values from user input
    
    guard let maze = MazeGenerator(x, y) else { //generate a maze
        return
    }
    hp = 2 * (x * y) //get hp value depending on user input
    hpLabel.text = "hp: \(hp)"
    
    guard let currentX = getRandomX(x), let currentY = getRandomY(y) else {
        return
    }
    currentCell = maze.maze[currentX][currentY] //game starts in a random part of the maze
                            
    for item in items.indices { //create and show some imageViews
        items[item].location = (getRandomX(x!), getRandomX(y!))
        createItems(imageName: items[item].imageName)
        if items[item].location == (currentX!, currentY!) {
            reveal(index: item)
        } else {
            hide(index: item)
        }
    }
    refreshButtons() //refresh UI
    maze.display() //print maze scheme in debug console
}

Additional insights:

Force unwrapping is useful in following cases (this list is not exhaustive):

  • failable initializers
  • functions or methods returning optional type instead throwing an error
  • IBOutlet attribute

Example of a failable initializers:

URL type has a failable initialiser init?(string:) which return optional URL object. In case of a string "https://www.google.pl" one can be sure that the string results in correct url object and not nil. In that case force unwrap is the way to express this having confidence that instead obtaining optional URL, one expects an URL object.

//failable initializer creates an optional URL object
let url: URL? = URL(string: "https://www.google.pl")

//force unwrapping leads to a non optional URL object
let url: URL = URL(string: "https://www.google.pl")!