Programer/iOS

[Swift] 옵셔널(Optional) 정리

아즈샤 2016. 10. 24. 15:43
반응형

저번주 토요일 iOS개발자 비정상토크가 있었습니다.

토크 주제중 keyWindow님의 옵셔널 강의가 굉장히 유용하여 제 스타일대로 정리해보고자 합니다.


1. 옵셔널이란 무엇인가?


- 스위프트의 특징 중 Safe에 해당 된다!

[Safe] : 옵셔널을 통해 안전한 코드 작성이 가능하다!

Powerful

Morden


- 간단히 말해 값이 있을수도 있고 없을수도 있다!


- ?

?가 붙었을 경우 메모리 공간 안에 상자가 하나 더 있다고 생각하면 쉽다. 

즉, 옵셔널은 상자안에 값이 들어가게되는 것, 만약 값이 없는경우는 상자 안이 비어 있다 할 수 있다. (nil을 할당할 경우)


만약 ? 붙으면 옵션널이 없다는 상수, 즉 ? 붙어 있으면 값이 없으면 절대 안된다!



2. 그럼 ????????? 옵셔널을 사용하는가?


파라미터에 nil 들어가면 안된다!

코딩하다가 '아 이 api에  파라미터를 무엇을 넣어할지 모르겠다' -> '그냥 nil넣자' -> '크래쉬 꽝'

옵셔널이 없다면 nil이 절대로 들어오면 안돼 -> 따로 코맨트가 필요 없음 -> 함수의 정의만 봐도 nil 들어올수 없구나 알수 있음


fun somefunction(someOptionalParam: Int?) {

//이경우에는 nil이 가능하다.

} 


결론: ? 유무에 따라 안전한 코딩이 가능함



- 이니셜라이징할때 리턴 타입 Int, Int? 도 동일함

?이 있다면 ->  실패하면 nil 반환해 주겠다!

그러나 ?가 없다면 -> 반드시 성공하는 값은 Int 반환해 주겠다!


- 사용 용도 : 테그로 뷰를 찾을 뷰를 찾을수 없을수 있기때문에 그때 옵셔널로 리턴 타입으로 만들면 된다!



3. 옵셔널의 핵심은 ?, !


- ? 

옵셔널의 상황 - 값이 있다, 없다. (만약, 메모리 공간안에 무조건 값이 들어있어야 한다 - 옵셔널X)

메모리 공간안에 있는 상자 = 옵셔널


- Optional의 구현

enum으로 구현되어 있고, 열거형으로 제너럴하게 사용 가능

none some (데이터가 없다, 있다)

즉, 옵셔널는 열거형 인스턴스로 사용



- 옵셔널을 바인딩 하는 2가지 방법

             Objective C에서는 다음과 같이 검증을 하였다.

if (someObject != nil) {

//someObject  가 nil이 아닌 경우 실행!

}


그럼 Swift에서 옵셔널은 어떻게 안전하게 꺼내서 쓸수 있을까?

let optionalValue:Int? = 100


switch optionalValue {


case .none:


case .some(let value):


}


이런식으로 바인딩 하는 것이 정석이다! - 하지만 너무 불편해 쉬운 방법 없을까?



A. Optional Bining


nil 체크를 , 안전하게 추출  -> 옵셔널이 아닌 타입으로 가져올 있음

옵셔너 상자안에서 메모리 공간에 하나를 만들어 준다 - 즉, 안전하게 사용할수있다.


메모리 공간에 있는 옵셔널 상자 안에 값이 있냐 노크를 해서 물어본다.


func printNAme(_ name:String) {


}        


var myName: String? = nil


if let name = myName, (추가로 검증가능) {

//nil일 경우 실행하지 않음

//여러개 들어  경우 모두 만족해야 실행

}



B.optional chanining (변수 하나 안에 프로퍼티가 옵셔널)


(옵셔널로 해야함)

let addressNumer: Int? = paul.residence?.address?.buildingNumer //nil

1 2 3


1,2,3 nil 가능성이 있음 - nil 반환



if let addresssNumber = paul.residence?.address?.buildingNumber

{

//residence, address. buildingNumber가 다 바인드 성공시 실행!

}



- ! (강제 추출!)


Force Unwrapping -> 상자를 부셔서 강제로 추출 (노크같은 신사적인 방법이 아닌)

주의! 근데 빈상자에 다가 강제 뜯으면 크래시가 발생!!!


func printName(_name: String) {

print(name)

}


var myNAme:String? = “name”


printName(myName) //error

printName(myName!) //값이 없으면 크래쉬



- Implicitly Unwrapped Optional (암시적 추출 옵셔널)


이 로직에는 무조건 값이 들어 있을거야! -> ! 쓸수 있음

이게 쓰여야 이유가 있음 - 주로 클래스에서 이니셜라이징 될때 프로퍼티 값이 nil 가질수 있으나 할당하려고


또한 ! -> ?와 동일하게 바인딩을 있음

       그럼 도래체 왜????  ! ? 있는대 만들었지?



@IBOutlet weak var nameLabel: UILabel <— ! ? 필요


클래스에서 주로 사용함 - 클래스는 안전을 위해 프로퍼티가 세팅되기 전까지는 사용할 없음

이니셜라이징시 프로퍼티에 초기 값이 없으면 이니셜라이징 되지 않음 그래서 클래스의 프로퍼티에 nil 입력이됨

즉, ! 붙혀놓으면 nil 상태지만 런이 되면서 스토리보드와 연결이 되는 것임


나중에 옵셔널으로 사용하기 귀찮기 때문에 ! 사용하게 되는 것임 -> 편의성을 위해 탄생 -> 반드시 값이 있을거야!


, 일반적인 옵셔널, 강제 추출 옵셔널 두개가 있는 것임

? 젠틀한 옵셔널 ! 강제적인 옵셔널


*근데 Xcode에서는 바인딩 방법을 가이드하지 않고 !로 변환하라고 가이드를 줌

경험이 적은 개발자는 아 그냥 이렇게 하는가보다~ 하고 변환함 -> 그러다가 nil들어오는 경우 크래시 나는 것임

(나 역시 이것때문에 크래쉬 보고서 폭탄을 받아야했음, 안일하게 기계를 믿는 나를 깊이 반성함.)



4. 옵셔널의 친구들 guard (옵셔널을 위해 태어난 것은 아님)


빠른종료 구문


if i==2 {


} else {


}


guard i == 2 else {


}



func someFunction(_ param:Int?) {

guard let value = param, value > 10 {

return

}

//소스

}


guard 함수 안에서 사용 가능함 - if 스코프가 다름



5. 옵셔널의 친구들 as


타입 캐스팅 - 타입이냐 확인하는 것이 타입캐스팅


as? - 이게 맞냐라고 물어보는 것임  - 맞으면 바인딩 - 아니면 nil


as! - 강제로 타입 변환을 시도 - 변환이 안되면 크래쉬가 발생



6. 옵셔널의 친구들 try


try?

에러가 발생 있다 - 핸들링을 해라

트라이 해봐서 괜찮으면 바인딩하고 안되면 닐이니까 포기해라라는 뜻


try!

강제로 트라이 해라


try의 원래 목적은 에러가 발생할 핸들링해주는 것을 기회를 주겠다

정식으로 사용하기 위해서는 try 무조건  두에catch 가 붙음 (정식적인 문법은 - do try catch)

근데 난 귀찮고 오류 체크도 안한다 - 오류는 알바 아니고 nil이 나오는지 안나오는지만 체크 하겠다 싶은면 try?  사용해주면 된다.



7. 저같이 맨땅에 헤딩하시는 분들이 겪는 옵셔널 이슈들..


- Xcode에서 가이드 해주는대로 ! 사용 남용 -> 바인딩 처리를 해줘야 합니다! (nil이 들어가는 경우 크래쉬 발생!)

- 뷰 태그를 찾을 때 -> 없는 경우가 있을테니 옵셔널로 처리해줘야 함 (그렇지 않으면 뷰를 못찾았을 때 크래쉬 발생!)

- 가급적 모든 변수는 ? 처리하고, ! 사용을 최소화 하면 많은 크래시를 없앨수 있습니다!



반응형