Notice
Recent Posts
Recent Comments
Link
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Tags
more
Archives
Today
Total
관리 메뉴

iOS 개발일지

0817 새싹 32회차 정리 - CodeBase AutoLayout 본문

SeSAC iOS 데뷔과정 2기

0817 새싹 32회차 정리 - CodeBase AutoLayout

Lia's iOS 2022. 8. 17. 22:07
iOS 앱 개발자 데뷔 과정 32회차

 

 

 

 

#1. Checklist

- iOS Layout

 

- 코드로 뷰 객체 생성 / Layout 설정 -
 1. 뷰객체 프로퍼티 선언. 클래스의 인스턴스를 생성
 2. 명시적으로 루트뷰에 추가
 3. 크기와 위치 및 속성 정의

 

iOS Layout은 Frame Based Layout ➡️ Auto Layout ➡️ Adaptive Layout 순으로 확장되어 왔다.

 

- Frame Based Layout

왼쪽 맨 위를 (0,0) 으로 해서, x좌표와 y좌표 그리고 크기를 설정해 레이아웃을 설정한다.

 

낡은 방식이라는 느낌이 확 든다

 

 

- Auto Layout

특정 제약조건을 걸어 뷰끼리의 관계를 통해 View를 표현한다.

NSConstaistsLayout, Visual Format Language, NSAnchorLayout 등이 사용된다.

 

 

- Adaptive Layout

https://developer.apple.com/documentation/uikit/uitraitcollection 참고

Size Class, Trait Collection, Universal Storyboard 등을 통해 iOS, iPadOS를 구분하지 않고 스토리보드에서 UI를 구성할 수 있다.

 

 

 

- addSubView

https://developer.apple.com/documentation/uikit/uiview/1622616-addsubview 참고

뷰객체를 코드로 구현하기 위해서는 반드시 addSubView를 통해 명시적으로 루트뷰에 추가해야 한다.

이 때 추가한 순서에 따라 객체끼리의 높낮이가 달라지게 된다.

만약 위와 같은 코드가 있다면, redView 위에 blackView가 겹쳐서 올라가있는 형태가 될 것이다.

그리고 그 아래의 yellowView는 view가 아닌 blackView라는 객체의 SubView이기 때문에, 내부에 포함되어있는 모양이 된다.

 

 

 

- translatesAutoresizingMaskIntoConstraints

- Autoresizing Mask

https://developer.apple.com/documentation/uikit/uiview/1622559-autoresizingmask 참고

https://developer.apple.com/documentation/uikit/uiview/1622572-translatesautoresizingmaskintoco 참고

이 속성의 값이 true면 시스템은 지정된 레이아웃으로 제약 조건을 생성한다.

Autoresizing Mask로 결정된 레이아웃은 Auto Layout Constraints로 변환되기 떄문에, Autoresizing Mask 이후 뷰의 크기나 위치를 수정하기 위해서 코드로 제약 조건을 설정 (추가, 삭제, 수정 등) 을 하는 것이 불가능하다.

따라서 Autoresizing과 Auto Layout을 동시에 적용할 경우 레이아웃 충돌이 발생할 수 있고, 충돌을 방지하기 위해서 코드로 Auto Layout Constraints를 적용하고자 할 때는 translatesAutoresizingMaskIntoConstraints 속성을 false로 설정해야 한다.

 

 

- NSLayoutConstraints

- isActive

https://developer.apple.com/documentation/uikit/nslayoutconstraint/1527000-isactive 참고

Default 속성이 false이기 때문에 제약조건을 활성화 하기 위해서 isActive를 true로 설정해야 한다.

위에서의 translatesAutoresizingMaskIntoConstraints와 isActive 둘 중 하나는 false여야 충돌이 나지 않는다.

매우 불편하다...

 

 

- addConstraints

https://developer.apple.com/documentation/uikit/uiview/1622523-addconstraint 참고

위보단 낫지만 매우 불편하다...

 

 

- activate

https://developer.apple.com/documentation/uikit/nslayoutconstraint/1526955-activate 참고

isActive로 개별적인 제약 조건을 설정하는 것보다 효율적이다.

 

 

 

- NSLayoutAnchor

NSLayoutAnchor 클래스를 통해 NSLayoutConstraints보다 간편하게 레이아웃을 설정할 수 있다.

 

 

 

 

- Snapkit

스토리보드를 사용하지 않고 소스 코드로 레이아웃을 설정할 때, 간략하게 사용할 수 있는 라이브러리

SafeArea를 고려해 레이아웃을 설정해야 하며, 클로저의 매개 변수를 생략하여 구현하는 것도 가능하다.

translatesAutoresizingMaskIntoConstraints도 내부적으로 호출이 되어있기 때문에 따로 작성할 필요가 없다.

 

- makeConstraints vs updateConstraints

makeConstraints는 레이아웃 제약 조건을 설정할 때 사용하며, updateConstraints는 기존에 지정한 제약 조건의 값 (constant의 value) 만 업데이트 할 경우에 사용한다.

 

 

- left/right vs leading/trailing

https://developer.apple.com/design/human-interface-guidelines/foundations/right-to-left 참고

leading/trailing으로 레이아웃을 설정하는 이유는 Localization 때문으로, leading/trailing으로 레이아웃을 설정하면 RTL(right-to-left) 지역에서는 화면이 뒤집힌 형태로 표시가 된다.

반대로 left/right로 설정한다면 Localization과 상관없이 같은 방향으로 나오게 된다.

 

 

- offset vs inset

다른 뷰객체와의 거리에 대한 제약조건을 설정할 수 있는데, 간단하게 offset은 밖으로 이동 / inset은 안으로 이동하는 형태이다.

offset(좌), inset(우) // yellowView는 무시해도 된다

 

 

 

 

#2. Assignment

- forEach vs for-in

forEach는 Collection을 순회하며, 클로저 상수를 통해 클로저 내의 작업을 반복하는 구문이다.

Collection Type을 순회하는 기능 자체는 for-in과 동일하지만, 구현 원리나 동작 구조가 다르기 때문에 차이점이 발생한다.

 

1. 반복문이 아니기 때문에 continue와 break를 사용할 경우 오류가 발생한다.

2. for-in의 경우 반복 도중 return을 만나면 함수 자체가 실행 종료되지만, forEach의 경우 클로저의 실행만 종료된다.

for-in(좌), forEach(우)

 

하지만 굳이 말하자면 클로저의 실행이 종료된다기 보다, 그냥 무시하는 쪽에 가까운 것 같다.

아래를 보면 for-in과 forEach 모두 return을 만났다고 반복이 종료되는 것이 아니다.

for-in(좌), forEach(우)

for-in이 return을 만나면 함수가 종료되는 것은 맞지만 (반복문 밖의 코드조차 실행되지 않는다) 수행중인 반복은 끝까지 실행한다.

마찬가지로 forEach도 return을 만난다고 해서 바로 종료되는게 아니고 끝까지 반복을 실행한 다음 클로저가 종료된다.

하지만 클로저를 종료해도 함수 자체가 종료되는 것은 아니기 때문에 Collection에 요소가 남아있다면 다음 반복을 실행한다.

즉, 그냥 무시하고 지나가는 것과 같기 때문에 forEach에서 return은 정말 아~무런 영향을 주지 못한다.

 

 

 

- 코드로 오토레이아웃 및 UI 구성하기

참고 자료(좌), 결과물(우)

전에 오토 레이아웃 처음 공부할때도 정말 오래 걸렸지만, 코드로 처음 구현하는것도 꽤 오래 걸렸다.

반복되지 않는 예쁜 코드를 쓰고 싶었는데 도저히 모르겠어서 어떻게든 구현해보자는 생각에 마구잡이로 적다보니 200줄을 넘겼다.

그래도 조금 감은 잡은 것 같다.

 

구현하며 가장 헤매는 원인이 된 코드는, 밑의 forEach의 코드이다.

코드가 너무 길어지고 정신 없으니까 ButtonUI와 LabelUI를 나눠서 조금이라도 정리한다는게...

이렇게 작성하면 다른 계층으로 인식이 되는지, 레이아웃을 잡을 때 서로의 위치를 참조하지 못한다ㅠㅠ

똑같이 루트뷰의 서브뷰라서 괜찮을 것 같았는데 그렇지 않나보다.

 

두번째로 헤맨 부분은, center이다.

view.center 같은 경우엔 다 생략하고 간략하게 사용할 수 있지만, 서브뷰의 센터는 snp.centerXY로 접근해야 한다.

 

 

 

 

# 그 외

- 오류 : which is already presenting

코드로 레이아웃을 구현하고, 루트뷰로 설정되어있는 VC에서 화면을 present 했는데 아래와 같은 오류가 발생했다.

 

2022-08-17 11:28:49.862051+0900 SeSACWeek7Diary[39423:13406360] [Presentation] Attempt to present <SeSAC2UIFramework.WebViewController: 0x15f7119e0> on <SeSACWeek7Diary.ViewController: 0x15f508860> (from <SeSACWeek7Diary.ViewController: 0x15f508860>) which is already presenting <SeSACWeek7Diary.CodeSnapViewController: 0x161b042f0>.

 

"너 의미 뷰 띄우고 있는데 왜 또 띄워?" 라는 뜻으로, 천천히 코드를 다시 읽어보니 아래와 같이 작성했었다.

전에 OpenWebView를 Present한 것을 까먹고 위에서 VC를 또 띄워버려서, 둘 중 하나를 주석처리하니 해결되었다. 

 

 

 

 

# 유용한 오픈소스

lottie-ios : https://github.com/airbnb/lottie-ios.git

여러 애니메이션 기능

 

SnapKit : https://github.com/SnapKit/SnapKit

코드로 레이아웃을 설정할 때, 간략하게 사용할 수 있다.

 

Then : https://github.com/devxoul/Then.git

코드로 뷰객체의 속성을 설정할 때, 간략하게 사용할 수 있다.