• Breadth-First Search
  • RegistrationViewModel

두 노드 사이의 최단 경로 혹은 임의의 경로를 찾고 싶을 때 사용

너비 우선 탐색의 특징

  • Non-recursive
  • 노드의 방문 여부를 검사한다.
    • 무한루프에 방지
  • 방문한 노드들을 차례로 저장한 후 사용할 수 있는 Queue사용
    • FIFO 원칙으로 탐색
    • 큐를 이용해 반복적 형태로 구현하는 것이 잘 동작한다.
  • Prim, Dijkstra 알고리즘과 유사하다.

image-20190318161951459

시작 노드인 node A를 방문하기 위해 queue에 넣는다. animation에서 gray로 보인다.

queue.enqueue(A)

queue는 현재 [ A ] 가 되었고. node가 queue에 있는 한, queue의 가장 앞에 있는 node를 방문한다. 그리고 인접한 nodes 중 방문하지 않았다면 즉시 enqueue한다.

그래프를 순회하기 위해서 queue에서 A 를 dequeue한다. 그리고 검은색으로 바꾼다. 그리고 인접 nodes B,C를 enqueue한다.

queue.dequeue()		// A
queue.enqueue(B)
queue.enqueue(C)

이제 queue는 [ B, C ] 가 되고, B를 dequeue하고 B의 인접 노드 D와 E를 enqueue한다.

queue.dequeue()   // B
queue.enqueue(D)
queue.enqueue(E)

The queue is now [ C, D, E ] . c를 dequeue하고 C의 인접 노드 F와 G를 enqueue한다.

queue.dequeue()   // C
queue.enqueue(F)
queue.enqueue(G)

The queue is now [ D, E, F, G ]. Dequeue D, which has no neighbor nodes.

queue.dequeue() 	// D

The queue is now [ E, F, G ]. Dequeue E and enqueue its single neighbor node H. Note that B is aldo a neighbor for E but we’ve already visited B, so we’re not adding it to the queue again

queue.dequeue()		// E
queue.enqueue(H)

The queue is now [ F, G, H ]. Dequeue F, which has no unvisited neighbor nodes.

queue.dequeue()		// F

The queue is now [ G, H ]. Dequeue G, which has no unvisited neighbor nodes.

queue.dequeue()		// G

The queue is now [ H ]. Dequeue H, which has no unvisited neighbor nodes.

queue.dequeue()		// H

The queue is now empty, meaning that all nodes have been explored. The order in which the nodes were explored is A, B, C, D, E, F, G, H

func breadthFirstSearch(_ graph: Graph, source: Node) -> [String] {
  var queue = Queue<Node>()
  queue.enqueue(source)

  var nodesExplored = [source.label]
  source.visited = true

  while let node = queue.dequeue() {
    for edge in node.neighbors {
      let neighborNode = edge.neighbor
      if !neighborNode.visited {
        queue.enqueue(neighborNode)
        neighborNode.visited = true
        nodesExplored.append(neighborNode.label)
      }
    }
  }

  return nodesExplored
}

RegistrationViewModel

        button.backgroundColor = .lightGray
        button.setTitleColor(.gray, for: .disabled)
        button.isEnabled = false

set registerButton disabled as default state

    tf.addTarget(self, action: #selector(handleTextChange), for: .editingChanged)
    @objc fileprivate func handleTextChange(textField: UITextField) {
        print("TEXT CHANGING : ", textField.text ?? "")
    }

인자에 textField를 넣어준다.

    @objc fileprivate func handleTextChange(textField: UITextField) {
        if textField == fullNameTextField {
            print("Full name changing")
        } else if textField == emailTextField {
            print("email changing")
        } else {
            print("PW changing")
        }
    }

if 문을 사용하여 어떤 textField인지 확인할 수 있다.

        let isFormVaild = fullNameTextField.text?.isEmpty == false && emailTextField.text?.isEmpty == false && passwordTextField.text?.isEmpty == false
        
        registerButton.isEnabled = isFormVaild
        if isFormVaild {
            registerButton.backgroundColor = #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1)
            registerButton.setTitleColor(.white, for: .normal)
        }

Vaild flag를 사용하여 모든 textField를 입력했을 때 버튼을 활성화 시키게 한다.

ViewModel with Reactive Programming

위 코드들은 사실 상 controller에 어울리지 않는 코드들이다.

What is MVC, MVVM?

RegistrationViewModel.swift

import UIKit

class RegistrationViewModel {
    
    var fullName: String? {
        didSet {
            checkFormValidity()
        }
    }
    var email: String? { didSet {} }
    var password: String? { didSet {} }
    
    fileprivate func checkFormValidity() {
        let isFormValid = fullName?.isEmpty == false && email?.isEmpty == false && password?.isEmpty == false
        isFormValidObsever?(isFormValid)
    }
    
    // Reactive programming
    var isFormValidObsever: ((Bool) -> ())?
}

Controller.swift

    let registrationViewModel = RegistrationViewModel()
    
    fileprivate func setupRegistrationViewModelObserver() {
        registrationViewModel.isFormValidObsever = { [unowned self] (isFormValid) in
            
            self.registerButton.isEnabled = isFormValid
            if isFormValid {
                self.registerButton.backgroundColor = #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1)
                self.registerButton.setTitleColor(.white, for: .normal)
            } else {
                self.registerButton.backgroundColor = .lightGray
                self.registerButton.setTitleColor(.darkGray, for: .normal)
            }
        }
    }

[unowned self] avoids retian cycle

태그: ,

카테고리:

업데이트:

댓글남기기