IBInspectable과 IBDesignable
IBInspectable
- Interface Builder에 해당 값의 정보를 보여줌
final class CustomButton: UIButton {
@IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
}
}
}
IBDesignable
- 컴파일 타임에 InterfaceBuilder에서 설정한 속성이 스토리보드에 반영
import UIKit
@IBDesignable
final class CustomButton: UIButton {
@IBInspectable
var cornerRadius: CGFloat {
get { return layer.cornerRadius }
set { layer.cornerRadius = newValue }
}
@IBInspectable var borderWidth: CGFloat {
get { return layer.borderWidth }
set { layer.borderWidth = newValue }
}
@IBInspectable var borderColor: UIColor {
get { return UIColor(cgColor: layer.borderColor!) }
set { layer.borderColor = newValue.cgColor }
}
}
CHCR(Content Hugging, Compression Resistance)
- 제약이 상충하는 상황에서 하나의 제약을 포기하기 위해 CHCR을 설정함.
- Content Hugging: Content의 크기가 늘어나지 않으려고 버티는 힘, 클수록 안늘어남!
- Content Hugging Priortity가 클 수록, 자기 자신의 크기를 유지함. 우선도가 낮으면 크기가 늘어남.
- Compression Resistance: Content의 크기가 줄어들지 않으려고 버티는 힘, 클수록 안줄어듬!
- Compresseion Resistance Priority가 클 수록, 자기 자신의 크기를 유지함. 우선도가 낮으면 크기가 줄어듬.
Code Base UI(Autolayout)
- AutoResizing은 컴파일시 자동으로 Constraints로 변환됨. → translatesAutoresizingMaskIntoConstraints
- 스토리보드에서 autoLayout을 잡으면, translatesAutoresizingMaskIntoConstraints 는 알아서 false로 처리됨.
- 하지만 code-base UI로 autoLayout을 설정하려면 반드시 직접 translatesAutoresizingMaskIntoConstraints를 false 처리해야 함.
func setLayoutAnchor() {
view.addSubview(signButton)
signButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
signButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
signButton.widthAnchor.constraint(equalToConstant: 300),
signButton.heightAnchor.constraint(equalToConstant: 50),
signButton.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
NSLayoutConstraint으로 설정하기
1. isActive
NSLayoutConstraint(
item: passwordTextField,
attribute: .leading,
relatedBy: .equal,
toItem: view.safeAreaLayoutGuide,
attribute: .leading,
multiplier: 1,
constant: 50
).isActive = true
2. addConstraints
let leading = NSLayoutConstraint(
item: passwordTextField,
attribute: .leading,
relatedBy: .equal,
toItem: view.safeAreaLayoutGuide,
attribute: .leading,
multiplier: 1,
constant: 50
)
view.addConstraints([leading])
NSLayoutAnchor로 설정하기
- NSLayoutConstraint.activate: isActive보다 효율적인 방식
func setLayoutAnchor() {
view.addSubview(signButton)
signButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
signButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
signButton.widthAnchor.constraint(equalToConstant: 300),
signButton.heightAnchor.constraint(equalToConstant: 50),
signButton.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
NSLayoutConstraint 방식으로 진행하는 것은 파라미터도 너무 많고 복잡하므로, NSLayoutAnchor를 주로 사용함.
❌ Visual Format Language는 스킵,,!
Snapkit
GitHub - SnapKit/SnapKit: A Swift Autolayout DSL for iOS & OS X
A Swift Autolayout DSL for iOS & OS X. Contribute to SnapKit/SnapKit development by creating an account on GitHub.
github.com
- SnapKit을 쓰면 translatesAutoresizingMaskIntoConstraints를 따로 설정할 필요 없음. snapkit에서 알아서 처리해줌.
import SnapKit
...
func setLayoutAnchor() {
view.addSubview(signButton)
signButton.snp.makeConstraints {
$0.centerX.equalToSuperView()
$0.width.equalTo(300)
$0.height.equalTo(50)
$0.bottom.equalToSuperView()
}
}
- SnapKit의 LayoutConstraintItem에서 내부적으로 호출중.
extension LayoutConstraintItem {
internal func prepare() {
if let view = self as? ConstraintView {
view.translatesAutoresizingMaskIntoConstraints = false
}
}
}
- addSubView를 하는 순서대로 레이아웃이 추가되고, 뷰 객체가 올라감
- makeConstraints vs updateConstraints
- updateConstraints는 기존에 지정한 제약 조건의 값만 업데이트 할 경우에 사용!
- 키보드 show/hide에 따른 레이아웃 값 변경 등
redView.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(100)
}
redView.snp.updateConstraints { make in
make.bottom.equalTo(-500)
}
- leading vs leadingMargin
- leadingMargin: leading 제약에 margin(여백)을 적용, 따라서 두 코드는 같은 의미
$0.leading.equalTo(view).inset(20)
$0.leadingMargin.equalTo(20)
UI Component 선언시 활용할 수 있는 방법
1. Static 메서드로 구현 후, 인스턴스 초기화 전에 사용
class TextViewController: UIViewController {
let photoImageView = setImageView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(photoImageView)
photoImageView.snp.makeConstraints {
$0.top.horizontalEdges.equalTo(view.safeAreaLayoutGuide)
$0.height.equalToSuperview().multipliedBy(0.3)
}
}
static func setImageView() -> UIImageView {
let imageView = UIImageView()
imageView.backgroundColor = .systemMint
imageView.contentMode = .scaleAspectFill
return imageView
}
}
2. lazy 키워드 활용
- 지연 저장 프로퍼티는 실제로 사용되기 전까지는 메모리에 로드되지 않음.
- 저장 프로퍼티나 메서드에 자유롭게 접근이 가능함-> 객체의 인스턴스화 이후에 실행됨!
class TextViewController: UIViewController {
lazy var photoImageView = setImageView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(photoImageView)
photoImageView.snp.makeConstraints {
$0.top.horizontalEdges.equalTo(view.safeAreaLayoutGuide)
$0.height.equalToSuperview().multipliedBy(0.3)
}
}
func setImageView() -> UIImageView {
let imageView = UIImageView()
imageView.backgroundColor = .systemMint
imageView.contentMode = .scaleAspectFill
return imageView
}
}
3. lazy + closure 활용
- 지연 저장 프로퍼티에 클로저를 활용하면, 해당 클로저는 지연 저장 프로퍼티를 사용할때만 실행됨.
- 만약 지연 저장 프로퍼티가 실행되지 않는다면, 클로저도 수행되지 않고 불필요한 할당을 방지할 수 있음.
- 지연 저장 프로퍼티의 클로저는 self를 통해 인스턴스에 접근할 수 있고, 이는 순환 참조를 일으키지 않음(캡쳐리스트 안써도 됨).
class TextViewController: UIViewController {
lazy var photoImageView = {
let imageView = UIImageView()
imageView.backgroundColor = .systemMint
imageView.contentMode = .scaleAspectFill
return imageView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(photoImageView)
photoImageView.snp.makeConstraints {
$0.top.horizontalEdges.equalTo(view.safeAreaLayoutGuide)
$0.height.equalToSuperview().multipliedBy(0.3)
}
}
}
연산프로퍼티가 아니고 클로저다!
클로저는 { } 중괄호 뒤에 함수 실행을 뜻하는 () 소괄호가 있음.이전까지 계속 연산프로퍼티라고 말하고 다녔다...
'SeSAC' 카테고리의 다른 글
8.23 TIL(SeSAC iOS 3기), MapKit + frozen Enumeration (1) | 2023.08.27 |
---|---|
8.23 TIL(SeSAC iOS 3기), CoreLocation (0) | 2023.08.27 |
8.14 ~ 8.18 TIL (1) | 2023.08.22 |
8.7 ~ 8.11 TIL (0) | 2023.08.15 |
7.31 ~ 8.4 TIL (0) | 2023.08.09 |