관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] @autoclosure 개념, 활용 (orThrow, nil인 경우 throw 발생) 본문

iOS 응용 (swift)

[iOS - swift] @autoclosure 개념, 활용 (orThrow, nil인 경우 throw 발생)

jake-kim 2022. 2. 21. 23:20

@autoclosure

  • 함수에 argument가 전달될 때 closure가 자동으로 생성되게끔 하는 키워드
  • 함수의 argument에 closure를 넘길 때, block으로 감싸지 않고 그냥 넘겨도 되게끔하는 키워드

https://docs.swift.org/swift-book/LanguageGuide/Closures.html

ex) @autoclosure 사용

class ViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    
    self.someFunction(print("this is closure"))
  }
  
  func someFunction(_ someArgument: @autoclosure () -> ()) {
    print("start")
    someArgument()
    print("end")
  }
}

/*
start
this is closure
end
*/
@autoclosure 사용 x @autoclosure 사용 o
self.someFunction({ print("this is closure") }) self.someFunction(print("this is closure"))
  • autoclosure를 사용하는 케이스는, 위와같이 closure에 들어가는 코드의 길이가 한 줄일 때 사용
    • 한줄인 경우는 대부분 따로 함수를 정의하여 그 함수를 넘기는 경우가 가장 많이 사용 (아래 예제 코드 확인)

활용 - orThrow

  • Optional 타입을 받는 곳에서 nil을 체크하여, nil값이면 throw를 발생시키게끔 하는 orThrow 구현
  • 사용하는 쪽) getUserID()는 nil을 받을 수 있으므로, nil을 가져오게 되면 throw를 발생시켜 에러처리 하도록 설계
    class ViewController: UIViewController {
      override func viewDidLoad() {
        super.viewDidLoad()
        
        do {
          let userID = try self.getUserID().orThrow(handleError()) // <-- 여기
          print("userID = \(userID)")
        } catch {
          print("handle error ... \(error)")
        }
      }
      
      private func getUserID() -> String? {
        let number = Int.random(in: (0...123))
        return number % 2 == 0 ? nil : "pass"
      }
      
      func handleError() -> MyError {
        return Bool.random() ? MyError.someError : MyError.unknown
      }
    }​
  • orThrow 구현 방법
    • Optional은 enum타입의 none과 some으로 되어있고, none케이스인 경우 nil이고 some케이스인 경우 optional이 해제된 값
    • Wrapped라는 generic 타입을 따르고 있는 형태

  • extension Optional을 통해 아래처럼 구현
    •  error 처리하는 인수를 autoclosure로 받아서 처리하도록 구현
      // https://twitter.com/johnsundell/status/1047232852113412098
      extension Optional {
        func orThrow(_ errorExpression: @autoclosure () -> Error) throws -> Wrapped {
          switch self {
          case .some(let value):
            return value
          case .none:
            throw errorExpression()
          }
        }
      }​
@autoclosure 사용 x @autoclosure 사용 o 
let userID = try self.getUserID().orThrow({ handleError() }) let userID = try self.getUserID().orThrow(handleError())

 

정리) 인수로 closure를 넘겨야 할 때, 함수를 넘기는 경우 (== 클로저 부분의 코드가 한 줄인 경우), autoclosure를 사용하면 가독성 향상되므로 함수를 넘기는 경우에 autoclosure 사용

 

* 참고

https://twitter.com/johnsundell/status/1047232852113412098

https://docs.swift.org/swift-book/LanguageGuide/Closures.html

Comments