UIKit. TableViewCell에 UITextView 넣고 동적으로 높이 변경하기

UITableViewCell 안에 UITextView를 넣고, 입력되는 텍스트 길이에 따라 셀의 높이가 자동으로 늘어나도록 처리했다. 처음에는 그냥 UITextView를 셀에 넣으면 알아서 늘어날 줄 알았는데, UITextView 자체의 스크롤과 UITableView의 셀 높이 계산이 같이 걸려 있어서 생각보다 손이 조금 간다ㅏ. 핵심은 UITextView의 스크롤을 끄고, 텍스트가 변경될 때 UITableView에 높이를 다시 계산하라고 알려주는 것이다. 구현 순서 1. UITextView에서 다음 속성들 체크 해제 Show Horizontal Indicator: 텍스트가 가로 크기를 초과한 경우, 가로 스크롤 바 표시 Show Vertical Indicator: 텍스트가 세로 크기를 초과한 경우, 세로 스크롤 바 표시 Scrolling Enabled: 스크롤 가능 여부 설정 Bounce on Scroll: 스크롤이 끝에 도달했을 때, 가볍게 튕기는 애니메이션 설정 2. Nib 등록 tableView.register( UINib(nibName: "GrowingCell", bundle: nil), forCellReuseIdentifier: "GrowingCell" ) 3. 데이터 소스 추가 extension ViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return items.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell( withIdentifier: "GrowingCell", for: indexPath ) as? GrowingCell else { return UITableViewCell() } cell.textView.text = items[indexPath.row] cell.delegate = self return cell } } 4. 델리게이트 작성 protocol GrowingCellProtocol: class { func updateHeightOfRow(_ cell: GrowingCell, _ textView: UITextView) } 5. 뷰 컨트롤러가 델리게이트 채택하고 구현 extension ViewController: GrowingCellProtocol { func updateHeightOfRow(_ cell: GrowingCell, _ textView: UITextView) { let size = textView.bounds.size let newSize = tableView.sizeThatFits( CGSize( width: size.width, height: CGFloat.greatestFiniteMagnitude ) ) if size.height != newSize.height { UIView.setAnimationsEnabled(false) tableView?.beginUpdates() tableView?.endUpdates() UIView.setAnimationsEnabled(true) if let thisIndexPath = tableView.indexPath(for: cell) { tableView.scrollToRow(at: thisIndexPath, at: .bottom, animated: false) } } } } 추가. 공식 문서에서는 beginUpdates() 보다 performBatchUpdates(_:completion:) 의 사용을 권장하고 있음. ...

September 15, 2024

UIKit. Responder Chain

앱에서 터치 입력과 같은 유저 인터랙션을 처리할 때, UIKit은 UIResponder 객체를 통해 이벤트를 감지하고 적절히 처리한다. 그렇다면 이벤트가 발생했을 때, 어떻게 적절한 UIResponder 객체를 찾아서 처리할까? UIKit에서 이벤트가 어떻게 전달되고 처리되는지, 특히 UIResponder와 Responder chain의 흐름을 정리했다. UIResponder와 UIEvent 개발자 문서에서 UIResponder는 ‘이벤트에 응답하고 처리하기 위한 추상 인터페이스’로 소개한다. 여기서 이벤트란, UIKit에서 UIEvent라는 클래스로 표현되는 단일 유저 인터랙션(예: 터치)을 의미한다. UIEvent 역시 개발자 문서에서 ‘앱에서 단일 유저 인터랙션을 설명하기 위한 객체’라고 정의되어 있다. ...

September 4, 2024

UIKit. UIStackView 레이아웃

UIStackView는 여러 뷰를 한 방향으로 묶어 배치할 수 있는 컨테이너 뷰다. 직접 서브뷰마다 제약 조건을 하나씩 걸지 않아도, 스택 뷰에 arranged subview로 추가하면 스택 뷰가 내부 뷰들의 배치를 관리한다. 스택 뷰는 기기의 방향, 화면 크기, 그리고 axis, alignment, distribution, spacing 같은 프로퍼티를 바탕으로 내부 뷰의 레이아웃을 결정한다. 이 글에서는 스택 뷰의 주요 프로퍼티가 레이아웃에 어떤 영향을 주는지 정리한다. intrinsicContentSize 스택 뷰의 레이아웃을 이해하려면 먼저 intrinsicContentSize를 알아야 한다. intrinsicContentSize는 뷰가 자신의 내용만을 기준으로 자연스럽게 가지는 크기다. 대표적인 예시는 UILabel이다. ...

August 27, 2024

UIKit. 화면 전환 방식

UIKit에서는 화면을 전환하는 방법이 여러 가지 있지만, 실제로는 상황에 따라 적절한 방식을 선택하면 된다. 화면을 계층적으로 이동한다 → Show Split View의 Detail 화면을 변경한다 → Show Detail 현재 화면 위에 독립적인 화면을 띄운다 → Present Modally 큰 화면에서는 팝오버, 작은 화면에서는 모달로 표시한다 → Present as Popover 이번 글에서는 각각의 방식이 어떤 상황에서 사용되는지 간단히 정리해 보려고 한다. 화면 전환 방식 Show show(_:sender:) 내비게이션 컨트롤러를 사용하는 경우 새로운 뷰 컨트롤러를 Push하여 화면을 전환한다. 사용자가 계층 구조를 따라 이동하는 대부분의 화면 전환이 여기에 해당한다. ...

August 21, 2024

UIView와 UIViewController의 차이 + 뷰 생명주기 메소드

공식문서 먼저 UIView An object that manages the content for a rectangular area on the screen. 화면의 사각형 영역을 나타내며, 내부에 다른 뷰를 포함할 수 있다. 대부분의 UI 요소가 UIView를 상속받는다. 콘텐츠를 화면에 나타내고, 사용자의 터치나 제스처를 감지한다. UIViewController An object that manages a view hierarchy for your UIKit app. 하나 이상의 뷰를 관리하고, 이 뷰들이 사용자와 상호작용하는 방법을 제어한다. 뷰를 생성하고, 화면에 표시하며, 뷰의 생명 주기를 관리한다. 두 줄 요약 UIView는 화면의 직사각형 영역에 표시되는 콘텐츠를 관리하고, 사용자의 동작을 감지하는 역할을 한다. UIViewController는 이 UIView를 관리하는 역할을 한다. (사용자의 동작을 감지하면 이 뷰가 어떻게 상호 작용을 해야 할지, UIView 라이프 사이클 관리 등…) 뷰 라이프 사이클 + 뷰 컨트롤러 관련 메소드 순서대로 작성하면 ...

August 20, 2024

DevOps. Git 기초

깃 파일 라이프 사이클 Tracked: 관리 대상 파일, 이미 스냅샷에 포함되어 있는 파일 - 깃이 이미 알고 있는 파일들… Unmodified: 수정하지 않은 파일 Modified: 수정한 파일 Staged: 커밋으로 저장소에 기록할 파일 Untracked: 관리 대상이 아닌 파일, 스냅샷 Staging Area에도 포함되지 않은 파일 위 캡처에서 test2: (Staged) 현재 Staging Area에 포함된 파일, 커밋하면 저장소에 기록된다. test: (Untracked) 트래킹 되지 않은 파일, 스냅샷에도 Staging Area에도 존재하지 않고 워킹 디렉토리에만 존재한다. README: (Modified) 수정된 파일, 커밋을 하기 위해서는 Staged 상태로 만들어야 함. 파일 새로 추적하기 (git add) git add 명령은 파일을 새로 추적할 때도 사용하고, 수정한 파일을 Staged 상태로 만들 때도 사용한다. ...

August 20, 2024

SwiftUI Tutorials. Handling User Input

랜드마크 앱에서 사용자는 좋아하는 장소를 플래그하고, 그들이 좋아하는 장소만 필터해서 볼 수 있다. 이런 기능을 만들기 위해서, 리스트에 스위치를 추가하여 유저들이 그들이 좋아하는 장소에만 포커스를 맞출 수 있도록 해야한다. 그리고 별 모양 버튼을 추가하고, 탭하면 유저들이 랜드마크에 favorite 플래그를 할 수 있도록 한다. Section 1. Mark favorite landmarks 리스트를 개선해서 사람들이 한 눈에 favorite를 찾을 수 있도록 시작한다. Landmark 스트럭처에 프로퍼티를 하나 추가해서, 이 랜드마크가 favorite인지 초기 상태를 읽을 수 있도록 한다. 그리고 favorite 표시된 랜드마크에는 별 아이콘을 보여준다. ...

June 25, 2024

SwiftUI Tutorials. Creating and Combining Views

Section 1. Create a new project and explore the canvas SwiftUI를 사용하는 새로운 Xcode 프로젝트를 만든다. 캔버스, 미리보기 및 SwiftUI 템플릿 코드를 탐색한다. Step 1-3 프로젝트 생성 부분 Step 4 SwiftUI 앱 라이프 사이클을 사용하는 앱은 App 프로토콜을 컨펌하는 스트럭처를 가지고 있다. 스트럭처의 body 프로퍼티는 디스플레이에 보여줄 컨텐츠를 제공하는 하나 이상의 씬이 있다. @main 어트리뷰트는 앱의 엔트리 포인트를 지정한다. // // LandmarksApp.swift // Landmarks // // Created by Kelly Chui on 6/25/25. // import SwiftUI @main struct LandmarksApp: App { var body: some Scene { WindowGroup { ContentView() } } } Step 5-7 기본적으로, SwiftUI 뷰 파일은 스트럭처와 프리뷰를 선언한다. 구조체는 View 프로토콜을 컨펌하며, 뷰의 내용과 레이아웃을 정의한다. preview 선언은 해당 뷰의 미리보기를 생성한다. ...

June 25, 2024

SwiftUI Tutorials. Building Lists and Navigation

사용자가 전체 랜드마크 목록을 보고 각 위치에 대한 세부 정보를 볼 수 있는 방법을 제공해야 한다. 모든 랜드마크에 대한 정보를 표시할 수 있는 뷰를 생성하고 사용자가 탭하여 랜드마크에 대한 디테일 뷰를 볼 수 있는 스크롤 목록을 동적으로 생성한다. UI를 미세 조정하고 싶으면 Xcode를 사용하여 다양한 장치 크기에서 미리보기를 렌더링 하면 된다. Section 1. Create a landmark model 첫 번째 튜토리얼에선, 모든 정보들을 커스텀 뷰에 하드코딩했다. 이제는 뷰로 전달할 수 있는 데이터를 저장하는 모델을 만들 것이다. ...

June 25, 2024

Network. Physical & Data Link Layer

Physical & Data Link Layer Physical Layer: 전기, 광, 무선 등의 신호를 통해 데이터를 전송하는 계층 Data Link Layer: 같은 LAN에서 데이터를 올바르게 전달하기 위한 계층 주요 기술 Ethernet 같은 LAN 안에서 데이터를 주고받는 대표적인 기술이다. Ethernet Frame 이더넷 기반의 네트워크에서 주고받는 프레임, 프리앰블, 송 · 수신 MAC 주소, 타입/길이, 데이터, FCS로 구성 프리앰블(preamble) 8 Bytes 이더넷 프레임을 수신하고 있다는 것을 알려주는 부분 MAC 주소(MAC address) 12(6 + 6) Bytes 이더넷 프레임을 송 · 수신할 장치의 MAC 주소를 가지고 있음 타입/길이(type/length) 2 Bytes 1500 이상의 값일 경우에는 프로토콜의 타입을 뜻함 1500 이하의 경우엔 LLC라는 값으로 타입 판별한다. 하지만 요즘은 거의 대부분 Ethernet II를 사용하기 때문에 명확하게 타입으로 사용함. 데이터(data) 최대 1500Bytes 실제로 송수신할 데이터 FCS 프레임의 오류가 있는지 여부를 확인하기 위한 트레일러 CRC(Cyclic redundancy check)라는 오류 검출용 값이 명시됨. Wireless 유선이 아닌 전파로 통신하는 방법이다. 대표적으로 와이파이가 있다. 주파수 간섭 문제를 최소화 하기 위해 채널이라는 하위 주파수 대역으로 세분화한다. ...

April 30, 2024