-Today's Learning Content-

  • UIKit의 사용방법
  • TabBarView
  • NavigationView
  • TableView
  • CollectionView
  • PickerView
  • ScrollView

1. UIKit으로 앱개발하기

개념 정리

UIkit이란 Apple에서 제공하는 iOS를 개발할 수 있도록 제공해주는 프레임워크이다. 코드베이스 혹은 스토리보드를 활용하여 앱을 개발할 수 있다.

1) UIButton과 @objc

UIKit에서 코드베이스로 버튼을 화면에 구성하고 동작하는 방법을 배우는 중 한가지 의문이 생겼다.

let button: UIButton!

button.setTitle("Push", for: .normal)
// 뷰에 버튼을 생성
view.addSubview(button)
button.addTarget(self, action: #selector(pushViewController), for: .touchUpInside)

// 버튼 클릭시 발생하는 동작
@objc func pushViewController() {
	print("Button Clicked!!")
}

위의 코드를 보면 버튼은 동작을 발생시킬 때 action이라는 매개변수로 #selector를 통해 @objc 함수 즉, Objective-C 의 함수를 받아온다. 강의에서 이렇게 하길래 따라했지만 일반 함수로는 안되는걸까? 궁금해서 실험해봤다.

button.addTarget(self, action: pushViewController(), for: .touchUpInside)

@objc func pushViewController() {
	print("Button Clicked!!")
}

이렇게 작성했더니 오류가 발생한다.
Cannot convert value of type '()' to expected argument type 'Selector'
함수를 Selector로 변환할 수 없다는 에러이다.
그래서 버튼의 addTarget 메소드를 살펴봤다.

애플의 공식 문서를 살펴보면 매개변수 action에 대해 이렇게 정의되어 있다.
액션은 호출할 작업 방법을 식별하는 선택기이고 이 매개변수는 비워두면 안되고... 너무 어렵고 무슨 뜻인지 모르겠다.

그래서 그냥 코드를 하나하나 찾아보기로 했다.

먼저 #selector에 대해 찾아보았다.
#selector는 Swift에서 특정 메소드가 UI 이벤트에 의해 호출될 때 해당 메소드의 이름을 지정하는 방법이라고 한다. 그러니까 UI 이벤트를 통해 메소드를 호출할 때, 어떤 메소드를 호출할 것인지 정해주는 방법인 듯 하다.

그러나 Swift는 기본적으로 Objective-C 런타임을 사용하지 않기 때문에 #selector를 사용하여 메소드가 Objective-C 런타임에 호출되도록 알려줘야 한다고...

그래서 조금 더 자세히 살펴보았는데,
UIKit과 같은 iOS 프레임워크는 Objective-C 런타임을 사용한다고 한다. UIButton의 액션 메소드 역시 그 일부이고, 때문에 addTarget 메소드를 통해 메소드를 호출할 때는 Objective-C 런타임에 호출을 해야하는데, 위에서 말했 듯 Swift는 기본적으로 Objective-C 런타임을 사용하지 않기 때문에 #selector를 통해 Objective-C 런타임에서 해당 메소드를 동적으로 찾을 수 있도록 한다고 한다.

이제 조금 감이 잡히는 것도 같다(사실 아직 어렵다)
그렇다면 @objc는 왜 사용할까?

@objc는 Swift에서 정의된 메소드가 Objective-C 런타임에서 호출될 수 있도록 알려주는 어노테이션이라고 한다. 즉, 메소드가 Objective-C에서 동적으로 호출될 수 있도록 만드는 코드이다.

아하, 그러니까 일반 함수처럼 정의하면 Objective-C 런타임에서 호출될 수 없으니까 @objc 코드를 사용해서 Objective-C 런타임에 올라갈 수 있도록 하는거구나

정리하자면 #selector메소드의 이름을 나타내며 이 이름을 사용하여 이벤트가 발생했을 때 호출할 메소드를 지정하는 키워드이다. 이 때, Swift는 기본적으로 메소드의 이름을 컴파일 타임에만 확인하기 때문에 메소드가 Objective-C 런타임에 호출될 수 있도록 메소드를 @objc로 설정하는 것이다.

생각보다 어려운 이유였기에 이해하는데 조금 어려움이 있었지만, #seletor의 역할과 @objc를 사용하는 이유를 이해할 수 있었기에 유익한 시간이었던 것 같다.

2) UIkit으로 화면 구현해보기

사용기술

  • NavigationView
  • PickerView
  • TabBarView
  • TableView
  • CollectionView

오늘은 강의에서 제공해준 예제들을 보며 배운 기술들로 화면에 뷰 요소를 배치하고 연결해보는 실습을 진행해 보았다.

실습 예제에서는 전부 frame = CGRect(x:y:width:height:)를 사용하여 뷰 요소의 위치를 결정하였는데, 나는 지금부터 오토레이아웃에 대해 연습하고 싶다고 생각하여 예제대로 작성한 뒤 오토레이아웃을 적용하여 코드를 변형하여 진행했다.

// 오토레이아웃 적용 예시
func setButton() {
	view.addSubview(button)
	button.addTarget(self, action: #selector(pushViewController), for: .touchUpInside)
        
	NSLayoutConstraint.activate([
		button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
		button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
	])
}

아직은 어색했지만, 조금씩 사용법을 알것도 같았다.
오토레이아웃을 지금부터 조금씩 연습해서 나중에는 더욱 잘 활용할 수 있도록 되고싶다.

강의를 들으면서 delegatedataSource 등에 대한 내용도 나왔는데, 어떻게 쓰는지 알겠으면서도 어려운 개념이었다. 아무래도 따로 내용을 찾아서 공부해보며 어떻게 활용할 수 있을지, 어떤 원리로 작동하는지 찾아봐야겠다고 생각했다.


2. 뷰의 크기를 조절하는 키워드들

학습 내용

UIKit에서는 frame, size, bounds 등 뷰 요소에 대한 크기를 정할 때 다양한 키워드를 사용할 수 있는데, 이 키워드들의 차이는 무엇이고 어떤 상황에 적절히 사용해야 하는걸까?

1) frame

frame은 뷰의 부모 좌표 시스템에서의 위치와 크기를 정의한다. 즉, 부모 뷰를 기준으로 x, y 좌표와 width, height를 포함한다.

frame은 뷰의 위치와 크기를 한 번에 설정할 때 유용하다. 특히 뷰가 부모 뷰 안에서 특정 위치에 있어야 할 때 frame을 직접 지정하여 배치할 수 있다. 오토레이아웃을 사용하지 않는 상황에서 주로 사용된다.

// frame 사용 예시
let view = UIView()

// 부모 뷰 좌표계 기준
view.frame = CGRect(x: 50, y: 100, width: 200, height: 150) 
view.backgroundColor = .blue
self.view.addSubview(view)

2) bounds

bounds는 뷰 자신의 좌표 시스템에서의 위치와 크기를 정의한다. boundsxy는 기본적으로 (0, 0) 이며, 뷰 내부에서 콘텐츠를 스크롤하거나 일부만 표시할 때 조정할 수 있다.

bounds는 뷰의 크기는 유지하면서 콘텐츠의 표시 영역을 조정하고 싶을 때 xy의 좌표를 조정하여 사용한다. 스크롤 영역이나 줌 효과를 구현할 때 유용하다.

// bounds 사용 예시
let innerView = UIView()

// 자기 자신의 좌표계 기준
innerView.bounds = CGRect(x: 20, y: 20, width: 200, height: 150) 
innerView.backgroundColor = .red
self.view.addSubview(innerView)

3) center

center는 부모 뷰 좌표 시스템에서의 뷰 중심 위치를 나타낸다. frame과 달리, 뷰의 중심을 기준으로 위치를 설정한다.

center는 뷰를 부모 뷰의 중심에 위치시키거나, 특정 기준을 중심으로 배치해야할 때 사용한다. frame보다 직관적으로 위치를 설정할 수 있는 경우가 많다.

// center 사용 예시
let view = UIView()

// 부모 뷰의 중심에 배치
view.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
view.center = self.view.center 
view.backgroundColor = .green
self.view.addSubview(view)

4) size

size는 뷰의 widthheight를 지정하는 속성으로, 주로 frame이나 bounds 안에 포함되어 있는 크기 정보를 다룬다.

size는 뷰의 크기만 조정하고 위치는 따로 지정하고 싶을 때 유용하다. frame이나 bounds에서 크기만 필요할 때 활용할 수 있다.

// size 사용 예시
var view = UIView()

// 크기만 설정
view.size = CGSize(width: 150, height: 150) 
view.center = self.view.center
view.backgroundColor = .yellow
self.view.addSubview(view)

5) Auto Layout(constraints)

Auto Layout을 사용하면 frame 대신 제약 조건을 활용해 뷰의 크기와 위치를 설정한다. 제약 조건은 다른 뷰와의 관계에 기반해 크기와 위치를 유동적으로 조정할 수 있게 한다.

다양한 화면 크기와 해상도에 맞게 뷰를 배치할 때, 즉 반응형 레이아웃이 필요할 때 유용하다. 특히 iOS 개발에서는 오토 레이아웃의 사용을 권장하고 있다.

// Auto Layout 사용 예시
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .purple
self.view.addSubview(view)

NSLayoutConstraint.activate([
    view.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
    view.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
    view.widthAnchor.constraint(equalToConstant: 200),
    view.heightAnchor.constraint(equalToConstant: 100)
])

6) intrinsicContentSize

intrinsicContentSize는 뷰가 본래의 콘텐츠에 맞게 스스로 정의하는 크기이다. 예로 UILabel, UIButton 등의 UI 요소는 본문 콘텐츠에 맞춰 크기가 결정된다.

intrinsicContentSize는 콘텐츠 크기에 맞춰 뷰를 조정해야 할 때, 특히 오토 레이아웃 제약을 사용할 때 사용한다. UILabel이나 UIImageView 같은 뷰에 유용하다.

// intrinsicContentSize 사용 예시
let label = UILabel()

label.text = "Hello World"
label.backgroundColor = .cyan
// 텍스트에 맞게 크기 조정
label.sizeToFit() 
self.view.addSubview(label)

-Today's Lesson Review-

오늘은 UIKit을 활용하여 화면에 뷰 요소를 배치하는 법을 배우고,
코드베이스, 스토리보드 활용을 하는 개발에 대해 학습했다.
강의가 중간에 바뀌는 사고도 있었지만... UIKit에 대해 알 수 있는 유익한 시간이었다고 생각한다.
모르는게 아직도 너무 많아서 천천히 하나씩 공부해봐야겠다.
profile
이유있는 코드를 쓰자!!

2개의 댓글

comment-user-thumbnail
2024년 11월 11일

내용 스압 주의네요ㅋㅋㅋㅋㅋ
#selector랑 @objc 는 저도 궁금했던건데 상세히 다뤄주셔서 이해도 하고 재밌게 보고 갑니다 !!!!

1개의 답글