SwiftUI가 나온 지 3년 정도 되었고,
최근 WWDC2022에서는 MacOS에서도 자연스럽게 쓰이며 모든 애플 플랫폼을 커버할 수 있을 만큼 발전해왔습니다.
최근에는 SwiftUI전용 Charts프레임워크도 발표했고, 점차 실무 앱 개발에서도 도입해도 될 만큼 변화해가고 있는데요.
아직은 SwiftUI보다는 스토리보드를 많이 사용하고 있고,
스토리보드에서도 SwiftUI처럼 실시간(?)으로 코드 구현부를 스토리보드에 반영할 수 있는 방법이 있어
이를 정리해보는 포스팅을 작성해봅니다(스토리보드야 파이팅).
바로 @IBInspectable, @IBDesignable인데요.
이 Attribute들을 사용하지 않고 스토리보드를 작성했을 때 문제점이 발생합니다.
스토리보드에서는 View들의 디테일한 부분까지 수정까지는 지원하지 않고,
이를 위해서는 어쩔 수 없이 코드로 작성하는 수밖에 없어서 이렇게 작성하고 나면
나중에(훗날) 화면 수정할 때 소스와 스토리보드를 왔다리갔다리 하면서 구현부를 읽게 되어 빠른 파악이 어려워집니다.
간단한 예제입니다.

계산기를 만드는 중인 스토리보드인데요.
아시다시피 스토리보드에서 View를 누르면 오른쪽의 Attributes Inspector에서 해당 View의 Attribute들을 수정할 수 있습니다.
이 상태에서 계산기 버튼들에 cornerRadius를 주어 둥글게 만들고 싶은데, 이럴 경우 코드를 작성해야 합니다.
@IBInspectable
이름에서도 느껴지듯이 이 Attribute를 사용하면 스토리보드의 Inspector에서 값을 바로 수정할 수 있게 해 줍니다.
UIButton을 상속받은 RoundButton을 작성해봅니다.
// RoundButton.swift
class RoundButton: UIButton {
@IBInspectable var isRound: Bool = true {
didSet {
if isRound {
self.layer.cornerRadius = self.frame.height / 2
}
}
}
}
isRound값을 IBInspectable로 선언해주고,
해당 값이 true일 때, cornerRadius를 설정해주도록 했습니다.
그리고 RoundButton을 Custom Class로 설정해주면,

다음과 같이 Inspector에서 해당 값을 수정할 수 있게 되었습니다.

하지만 값을 바꾼다고 스토리보드에서 바로 값이 적용이 되지는 않습니다.
이제 @IBDesignable을 사용할 때입니다.
@IBDesignable
바로 작성해봅니다. 아까 작성한 코드에 @IBDesignable만 선언해주면 됩니다.
// RoundButton.swift
@IBDesignable // 추가
class RoundButton: UIButton {
@IBInspectable var isRound: Bool = true {
didSet {
if isRound {
self.layer.cornerRadius = self.frame.height / 2
}
}
}
}
그리고 스토리보드로 돌아가면 cornerRadius가 반영되어 있는 걸 확인해볼 수 있습니다.
Inspector에는 Designables가 적용이 되었는지 표시가 됩니다.
표시가 바로 안된다면 cmd+B를 눌러 빌드를 진행하고 나면 바로 반영이 됩니다)

아무래도 코드를 스토리보드에 반영하는 것이다 보니, 빌드로 인한 시간이 걸릴 수 있습니다.
큰 프로젝트에서는 SwiftUI처럼 빠릿빠릿하게 반영되는 맛은 없을 수도 있지만,
소스로 수정한 것을 바로 반영할 수 있는 데에 큰 의미가 있습니다.
그리고 SwiftUI의 Preview와 마찬가지로
시뮬레이터 빌드를 할 수 없는 모듈을 포함한 프로젝트의 경우 아래와 같이 에러를 발생시키며 @IBDesignable가 반영이 되지 않을 수 있습니다.
ld: building for iOS Simulator, but linking in dylib built for iOS, file '(시뮬레이터 지원을 하지 않는 모듈경로 및 모듈명)' for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
SwiftUI가 나온 지 3년 정도 되었고,
최근 WWDC2022에서는 MacOS에서도 자연스럽게 쓰이며 모든 애플 플랫폼을 커버할 수 있을 만큼 발전해왔습니다.
최근에는 SwiftUI전용 Charts프레임워크도 발표했고, 점차 실무 앱 개발에서도 도입해도 될 만큼 변화해가고 있는데요.
아직은 SwiftUI보다는 스토리보드를 많이 사용하고 있고,
스토리보드에서도 SwiftUI처럼 실시간(?)으로 코드 구현부를 스토리보드에 반영할 수 있는 방법이 있어
이를 정리해보는 포스팅을 작성해봅니다(스토리보드야 파이팅).
바로 @IBInspectable, @IBDesignable인데요.
이 Attribute들을 사용하지 않고 스토리보드를 작성했을 때 문제점이 발생합니다.
스토리보드에서는 View들의 디테일한 부분까지 수정까지는 지원하지 않고,
이를 위해서는 어쩔 수 없이 코드로 작성하는 수밖에 없어서 이렇게 작성하고 나면
나중에(훗날) 화면 수정할 때 소스와 스토리보드를 왔다리갔다리 하면서 구현부를 읽게 되어 빠른 파악이 어려워집니다.
간단한 예제입니다.

계산기를 만드는 중인 스토리보드인데요.
아시다시피 스토리보드에서 View를 누르면 오른쪽의 Attributes Inspector에서 해당 View의 Attribute들을 수정할 수 있습니다.
이 상태에서 계산기 버튼들에 cornerRadius를 주어 둥글게 만들고 싶은데, 이럴 경우 코드를 작성해야 합니다.
@IBInspectable
이름에서도 느껴지듯이 이 Attribute를 사용하면 스토리보드의 Inspector에서 값을 바로 수정할 수 있게 해 줍니다.
UIButton을 상속받은 RoundButton을 작성해봅니다.
// RoundButton.swift
class RoundButton: UIButton {
@IBInspectable var isRound: Bool = true {
didSet {
if isRound {
self.layer.cornerRadius = self.frame.height / 2
}
}
}
}
isRound값을 IBInspectable로 선언해주고,
해당 값이 true일 때, cornerRadius를 설정해주도록 했습니다.
그리고 RoundButton을 Custom Class로 설정해주면,

다음과 같이 Inspector에서 해당 값을 수정할 수 있게 되었습니다.

하지만 값을 바꾼다고 스토리보드에서 바로 값이 적용이 되지는 않습니다.
이제 @IBDesignable을 사용할 때입니다.
@IBDesignable
바로 작성해봅니다. 아까 작성한 코드에 @IBDesignable만 선언해주면 됩니다.
// RoundButton.swift
@IBDesignable // 추가
class RoundButton: UIButton {
@IBInspectable var isRound: Bool = true {
didSet {
if isRound {
self.layer.cornerRadius = self.frame.height / 2
}
}
}
}
그리고 스토리보드로 돌아가면 cornerRadius가 반영되어 있는 걸 확인해볼 수 있습니다.
Inspector에는 Designables가 적용이 되었는지 표시가 됩니다.
표시가 바로 안된다면 cmd+B를 눌러 빌드를 진행하고 나면 바로 반영이 됩니다)

아무래도 코드를 스토리보드에 반영하는 것이다 보니, 빌드로 인한 시간이 걸릴 수 있습니다.
큰 프로젝트에서는 SwiftUI처럼 빠릿빠릿하게 반영되는 맛은 없을 수도 있지만,
소스로 수정한 것을 바로 반영할 수 있는 데에 큰 의미가 있습니다.
그리고 SwiftUI의 Preview와 마찬가지로
시뮬레이터 빌드를 할 수 없는 모듈을 포함한 프로젝트의 경우 아래와 같이 에러를 발생시키며 @IBDesignable가 반영이 되지 않을 수 있습니다.
ld: building for iOS Simulator, but linking in dylib built for iOS, file '(시뮬레이터 지원을 하지 않는 모듈경로 및 모듈명)' for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)