본문 바로가기

iOS

0729 Q&A 정리

728x90

1. IBOutlet의 didSet이 한번만 호출되는 이유?

IBOutlet을 통해 연결한 UIComponent에 대해서 didSet으로 설정을 바꿀 수 있지 않을까?

@IBOutlet weak var button: UIButton! {
   didSet {
      button.backgroundColor = .red
   }
}

그렇다면, 위와 같이 코드를 작성하게 된다면 button의 속성이 바뀔 때마다 didSet이 호출되는 것이 아닌가?라는 생각을 할 수 있다.

 

그러나, 그렇지 않다.

프로퍼티라면 그렇게 동작할 수 있지만 IBOutlet은 클래스이므로 button 자체를 바꾸지 않는 이상 didSet이 호출되지 않는다.

 

클래스이므로 인스턴스 자체를 바꾸지 않는 이상 didSet이 호출되지 않는다.

코드를 통해서 살펴보면 아래와 같다.

class SoKyte {
    var age = 1
}

var test: SoKyte = SoKyte() {
    didSet {
        print("소깡이의 나이를 변경해볼까?!")
    }
}

test.age = 25 // 아무것도 출력되지 않는다.

프로퍼티에 접근해서 새로운 값을 넣었기 때문에 print()가 실행될 수 있지 않을까? 하지만 그렇지 않다.

 

didSet이 reference type (ex. class)에 달려있을 때

  • didSet observer가 달려있는 애(test)는 class 인스턴스로 reference type이다.
  • reference type의 instance는 제자리에서 변할 수 있다. (in place)
  • 즉, test자체를 바꾼게 아니라 test.age을 바꿨기 때문에 아무일도 일어나지 않는다.
  • test = SoKyte() 이렇게 하면 didSet 동작
    • 즉, 인스턴스 자체를 아예 갈아끼우면 가능

didSet이 value type (ex. struct)에 달려있을 때

  • value type은 비록 그렇게 보일지라도 실제로는 제자리에서 변할 수 없다. (not mutable in place)
  • value type의 instance를 변경했다고 하면, 다른 instance로 원래 instance를 변경하는 것이다.
  • test.age = 25 이어도 인스턴스가 변경되는 것이기 때문에 didSet 동작한다.

즉, IBOutlet은 class 라 reference type 이기 때문에 해당 인스턴스 자체를 바꾸지 않는 이상 didSet이 동작하지 않는다.

 

 

그렇다면, Outlet의 didSet은 언제 trigger가 될까?

  • Outlet의 프로퍼티는 class가 막 초기화 될 때는 nil 상태이다.
  • nib으로부터 object가 초기화 될 때 값을 갖게 된다.
  • 모든 Outlet이 nil이 아님을 확신할 수 있을 때는 viewDidLoad이다.
  • 따라서 Outlet에 있는 didSet 옵저버는 viewDidLoad 바로 전에 호출된다.
  • 그러므로 Outlet의 프로퍼티는 보다 주의해서 다뤄야 한다. 예를 들어서 prepareForeSegue 때 접근하려고 하면 nil을 받게 될 것이다.

 

2. Struct VS Class (간단하게)

1번 질문의 확장된 개념으로 구조체와 클래스에 대해서 다시 한번 정리하고 넘어가보자.

 

차이점에 대해서 정리하면 다음과 같다.

1. 초기화 구문의 유무

구조체는 모든 프로퍼티 값을 초기화하는 구문을 자동으로 제공한다.

(= 멤버와이즈 초기화 구문)

그러므로 클래스처럼 init을 작성할 필요가 없다. 그래서 구조체에서는 클래스처럼 이니셜라이저 오류가 발생하지 않는다.

 

struct Human {
    var name: String
    var age: Int
}

class Person {
    var name: String
    var age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

 

2. ValueType VS Reference Type

구조체는 값 타입이고, 클래스는 참조 타입이다.

 

간단하게 설명하면, (힙 .. 스택 이런거 제외하고) 구조체는 메모리 주소 영역과 프로퍼티들이 한 곳에 저장이 되고, 구조체는 하나의 영역에 프로퍼티들이 모여져 있고 해당 공간을 각 다른 메모리 주소 영역에서 가르키고 있다고 볼 수 있다.

 

그래서, 구조체 인스턴스를 또 다른 변수에 대입할 경우 기존 인스턴스와 독립적으로 동작한다.

인스턴스가 복사되어 새로운 값 형태로 존재하므로 기존 인스턴스가 변경되어도 서로 영향을 미치지 않는다.

var huree = Human(name: "후리스콜링스", age: 24)
var sokyte = huree
sokyte.name = "소깡"

print(huree.name, sokyte.name) // 후리스콜링스 소깡

 

그러나 클래스의 경우 참조 타입이므로 메모리 주소 정보가 전달되기 때문에 값이 저장되어 있는 곳을 공통으로 사용한다.

var hooni = Person(name: "", age: 25)
let jiwon = hooni

hooni.name = "후니아씨"
jiwon.name = "지원씨."

print(hooni.name, jiwon.name) // 지원씨. 지원씨.

 

3. UIWindow의 Background Color를 수정하면 전체가 다 수정될까?

만약 앱의 배경색이 모두 동일한 색이라면? 우리는 이것을 루트 뷰의 backgroundColor 프로퍼티에 접근하여 다음과 같이 설정할 수 있다.

view.backgroundColor = .systemPink

 

매번 이렇게 코드를 작성하는 것이 비효율적이라고 느껴 아래와 같이 코드를 작성할 수도 있다.

SceneDelegate에서 다음과 같이 작성하는 것이다.

guard let scene = (scene as? UIWindowScene) else { return }
self.window = UIWindow(windowScene: scene)
self.window?.backgroundColor = Asset.Colors.white.color

 

이렇게 작성하면 모든 루트뷰의 배경색을 바꾸는 것이므로 배경색이 한번에 지정이 될까?

 

결론부터 말하자면, 이렇게 변경하는 것은 허상이다.

UIWindow의 경우 모든 뷰의 가장 최상단 뷰이므로 그 위에 다시 뷰가 올라가게 된다면 다시 그 뷰의 색을 변경해야 하므로, 권장하지 않는 방식이다. 

 

차라리 UIViewController의 extension을 통해서 뷰의 배경색을 바꿔주는 것이 더 나은 방식이다.

 

4. Local Notification과 User Account의 연관성

때때로 앱에서 로그아웃을 했음에도 불구하고 계속해서 푸시 알림이 오는 경우가 있다.

나는 분명 앱에서 로그아웃을 했는데, 그렇다면 앱의 DB에 내 정보가 없음에도 왜 자꾸 푸시 알림이 오는 것일까?

 

이유는 해당 알림이 로컬 알림일 확률이 높다.

보통 앱의 경우 뒷단을 맡고 있는 서버가 있다. 그리고 그 서버의 DB에서 사용자에 대한 정보를 관리한다. 해당 유저가 가입이 되어서 알림 설정을 한 경우 알림을 보내다가, 그 유저가 알림을 끄게 되면 알림을 더 이상 보내지 않는다. 그리고 만약 그 유저가 탈퇴하게 된다면 유저에 대한 정보가 같이 사라지므로 알림도 오지 않게 되는 것이 일반적이다.

 

그러나, 만약 서버에서 알림을 관리하지 않고 로컬에서 관리하게 된다면 어떻게 될까?

Local Notification의 경우 유저 별로 대응되는 것이 아니라 디바이스 별로 대응이 된다. 그러므로 로컬에서 관리를 한다면, 디바이스에서 앱의 알림을 끄거나 앱 자체를 삭제 하지 않는한 알림은 켜져 있다.

 

결론 : Local Notification은 계정이 아닌 디바이스와 대응이 된다. 

 

'iOS' 카테고리의 다른 글

Network - 가볍게  (0) 2022.08.02
SSAC - 다마고치 프로젝트 피드백 정리  (0) 2022.08.02
Custom Font를 적용하고 싶다면?  (0) 2022.08.01
ATS(App Transport Security)  (0) 2022.07.28
UIResponder  (0) 2022.07.28