• assert ,guard
  • Bindable
  • UIImagePickerController
  • protocols for UIImagePickerController

assert, guard

야곰의 assert & guard

어플리케이션 동작 도중에 생성하는 다양한 결과값을 동적으로 확인하고 안전하게 처리할 수 있도록 확인하고 빠르게 처리할 수 있다.

assert

assert(_: _:file:line:) 함수를 사용합니다. assert 함수는 디버깅 모드에서만 동작하고 배포하는 앱에서는 제외된다. 주로 디버깅 중 조건의 검증을 위하여 사용한다.

var someInt : Int = 0
assert(someInt == 0, "someInt != 0")

첫번 째 인자가 true면 지나친다.

message(second argument)를 써주지 않으면 동작을 멈춘다.

함수 전달인자 검사할 때 많이 사용한다.

func functionWithAssert(age: Int?) {
  assert(age != nil, "age == nil")
  
  assert((age! >= 0) && (age! <= 130), "나이값이 잘못 입력 되었습니다.")
  print("당신의 나이는 \(age)입니다.)
}

guard

guard를 사용하여 잘못된 값의 전달 시 특정 실행구문빠르게 종료합니다. 디버깅 모드 뿐만 아니라 어떤 조건에서도 동작합니다. guard의 else 블럭 내부에서는 특정 코드블럭을 종료하는 지시어 (return, break 등)가 꼭 있어야 합니다. type casting, optional과도 자주 사용됩니다. 그 외 단순 조건 판단 후 빠르게 종료 할 때에도 용이합니다.

func functionWithGuard(age: Int?) {
  guard let unwrappedAge = age,
		unwrappedAge < 130,
		unwrappedAge >= 0 else {
      print print("나이값 입력이 잘못되었습니다.")
      return
		}
  print("당신의 나이는 \(unwrappedAge)세 입니다.")
}

이 부분에서 먼저 optional binding을 실행한다. 여기서 nil값이면 바로 return 된다.

  guard let unwrappedAge = age,

Dictionary와 굉장히 활용이 많이 된다.

func someFunction(info: [String: Any]) {
  guard let name = info["name"] as? String else {
    return
  }
  
  guard let age = info["age"] as? Int, age >= 0 else {
    return
  }
  
  print("\(name): \(age)")
}
someFunction(info: ["name": "Jenny", "age": "10"])
someFunction(info: ["name": "Mike"])
someFunction(info: ["name: "Yagom", "age": 10])

Shortcuts For Xcode

My Favorite Xcode 8 Shorcuts by Bob Lee

Hide Panels

Command 0(Left)
Command Option 0(Right)
Command Shift Y(Bottom)

Bindable

RxSwift, RxJava, RxCocoa

Assist View State Observation

imagePicker

    @objc fileprivate func handleSelectPhoto() {
        let imagePickerController = UIImagePickerController()
        imagePickerController.delegate = self
        present(imagePickerController, animated: true)
    }
        imagePickerController.delegate = self

delegate에 self(registrationController)를 할당하기 위해서는 protocol을 사용해야한다.

Cannot assign value of type ‘RegistrationController’ to type ‘(UIImagePickerControllerDelegate & UINavigationControllerDelegate)?’ Insert ‘ as! UIImagePickerControllerDelegate & UINavigationControllerDelegate’

extension RegistrationController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
}
extension RegistrationController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        let image = info[.originalImage] as? UIImage
        self.selectPhotoButton.setImage(image?.withRenderingMode(.alwaysOriginal), for: .normal)
        dismiss(animated: true, completion: nil)
    }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        dismiss(animated: true)
    }
}
	self.selectPhotoButton.setImage(image?.withRenderingMode(.alwaysOriginal), for: .normal)

if you miss the withRederingMode(.alwaysOriginal) the image will be seen as just blue box

// in SelectPhotoButton
button.imageView?.contentMode = .scaleAspectFill
button.clipsToBounds = true

perfect


RegistrationViewModel

there are 3 properties now. but this ViewModel is supposed to reflect what’s going on inside our registrationController.

It is not enable to keep tracking the image (3 properties are enable)

So make a new property

    var image: UIImage?

in RegistrationController.swift

func imagePickerController(~~) {
 	...
  registrationViewModel.image = image 
  ...
}
    var image: UIImage? {
        didSet {
            imageObserver?(image)
        }
    }
    
    var imageObserver: ((UIImage?) -> ())?

이전에 isFormValidObserver와 같이 didSetobserver를 만들어준다.

func imagePickerController에 있던 SelectPhotoButton의 실질적인 image를 바꿔주는 코드를 setupRegistrationViewModelObserver로 옮겨준다.

registrationViewModel.imageObserver = { [unowned self] img in
            self.selectPhotoButton.setImage(img?.withRenderingMode(.alwaysOriginal), for: .normal)
        }

bindable

in ViewModel, we have two observers

didSet과 Observer를 사용하는 이러한 방식의 concept는 bindable이라고 한다.

class Bindable<T> {
    var value: T? {
        didSet {
            observer?(value)
        }
    }
    
    var observer: ((T?)->())?
    
    func bind(observer: @escaping (T?) -> ()) {
        self.observer = observer
    }
}

Bind?!

    var bindableImage = Bindable<UIImage>()

//    var image: UIImage? {
//        didSet {
//            imageObserver?(image)
//        }
//    }
//
//    var imageObserver: ((UIImage?) -> ())?

Bindable을 사용하여 이러한 컨셉들의 코드들을 단축시킬 수 있다. for reactive programming

registrationController.swift

// func imagePickerController(~~)
        registrationViewModel.bindableImage.value = image
//        registrationViewModel.image = image
// setupRegistrationViewModelObserver()
        registrationViewModel.bindableImage.bind { (img) in
            self.selectPhotoButton.setImage(img?.withRenderingMode(.alwaysOriginal), for: .normal)
        }

using bindable for isFormValid in ViewModel

	var bindableIsFormValid = Bindable<Bool>()
// 		func checkFormValidity()
        bindableIsFormValid.value = isFormValid

bindable value를 바꿔주면 didSet에서 observer를 실행한다는 점을 잊지말자!

registrationViewModel.bindableIsFormValid.bind { [unowned self] (isFormValid) in
            guard let isFormValid = isFormValid else { return }
            self.registerButton.isEnabled = isFormValid
            self.registerButton.backgroundColor = isFormValid ? #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1) : .lightGray
            self.registerButton.setTitleColor(isFormValid ? .white : .darkGray, for: .normal)
        }

guard를 활용한 optional binding

some refactoring

self.registerButton.backgroundColor = isFormValid ? #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1) : .lightGray
            self.registerButton.setTitleColor(isFormValid ? .white : .darkGray, for: .normal)

After running

when keyboard shows up transforming doesn’t work.! Why?

it was because of removeObserver() in viewWillDisappear so, I moved setupNotificationObservers() to viewWillAppear(), It works perfectly

ViewController Life-Cycle

The App Life Cycle

I need to make an issue list on github!

태그: ,

카테고리:

업데이트:

댓글남기기