← 홈으로 돌아가기

📝 Daily Learning Log (2026-07-13 ~ 07-19)

주간 학습일지 · 2026-07-13 ~ 07-19

2026-07-13 (일)

학습 주제 — 빌드·링킹·렌더링 내부 동작

오답노트

  • CAShapeLayer가 메인스레드에서 그린다고 착각: 속성 설정만 메인스레드, 실제 래스터라이즈는 Render Server
  • frame 바꾸면 항상 텍스처 재생성?: origin만 바꾸면 재사용, size 바꿔야 재생성
  • Lottie가 JSON을 직접 넣는다고 착각: 키프레임 보간 후 적용. JSON 값 그대로 넣는 게 아님

2026-07-14 (화)

학습 주제 — CA 렌더링 심화 + 링킹(two-level namespace)

오답노트

  • frame 변경=contents 변경 착각: 별개. frame(위치·크기)만 바뀌고 contents(그림)는 그대로
  • 이미지도 GPU 래스터화 착각: 이미지는 디코딩(CPU). 래스터화는 벡터(GPU)만
  • 회전하면 layoutSubviews 착각: transform 회전은 bounds 불변 → layout 안 됨
  • 맹글링 이름이 앱/B라 안 겹친다 착각: 맹글링 모듈명은 A(같음). 구분은 two-level 소속 이미지

2026-07-15 (화)

학습 주제 — Swift Concurrency Task Isolation 심화

오답노트

  • async let이 MainActor에서 실행된다고 착각: 자식 Task는 await 전에도 전역 executor에서 시작됨. MainActor 유지 안 됨
  • nonisolated async가 전역 executor라고 착각 (Swift 6.2): SE-0461 이후 caller 상속. @concurrent 써야 전역
  • @Sendable이 단순 타입 표시라고 착각: 캡처 값의 data race 방지가 핵심. non-Sendable 캡처 시 외부 수정 위험

2026-07-16 (목)

학습 주제 — GCD Barrier & Swift Concurrency 보강

오답노트

  • unowned면 항상 안전하다고 착각: 비동기 작업(네트워크, 타이머)이 끼면 생존 순서 보장 안 됨. URLSession이 클로저 retain → Player 생존 → VC 해제 후 접근 → 크래시
  • Task { }가 바로 병렬 실행된다고 착각: Actor 내에서는 isolation 상속해서 actor가 비어야 실행. Class면 global executor에서 진짜 병렬 → 순서 보장 없음
  • Responder Chain이 위에서 시작한다고 착각: Hit Testing(위→아래)으로 뷰 찾고, 그 뷰부터 Responder Chain(아래→위) 시작
  • opaque(some View)는 호출부가 "프로토콜 타입"만 안다고 착각: 아니다. 구체 타입은 하나로 고정돼 있고 컴파일러는 정확히 안다 — 이름만 가려진 것. "프로토콜 타입만 안다"는 any View(existential) 설명. some은 identity 보존 + 정적 디스패치라 SwiftUI diffing이 가능

📘 복습 정리: SwiftUI some View 심화 — §8 opaque vs any 구분 · §9 방향/타입정체성/컴파일러/diffing/existential 박싱 · §10 프로토콜≠타입/정적디스패치/body재실행2층/identity=타입+위치/AnyView

2026-07-17 (금)

학습 주제 — SwiftUI 렌더링 내부: identity vs type vs struct

오답노트

  • ❌ "identity는 내부 프로퍼티(값)가 바뀌면 바뀐다" → 아니다. identity는 위치로 정해지고, 값 변화는 body 재호출만 유발
  • ❌ "if/else의 두 CounterView는 결과가 같으니 같은 뷰" → 코드 구조상 분기 슬롯 2개라 identity A/B로 다름 → 토글 시 @State 리셋
  • ❌ "state lifting에서 ChildView·OtherView의 identity 노드가 같다" → 다르다(둘 다 파괴·생성). count 보존은 원본을 Parent 노드가 소유해서
  • ❌ "@State 아닌 일반 프로퍼티가 바뀌면 body 재호출 안 한다" → 값이 달라지면 @State든 일반이든 재호출
  • ❌ "노드 파괴·재생성 = struct 재생성과 같은 것" → struct는 늘 재생성(값), 노드는 identity/type 바뀔 때만 파괴
  • ❌ "ForEach는 인덱스를 id로 써도 됨" → 자리 바꾸면 상태가 항목이 아니라 자리에 눌러앉아 꼬임. 고유·안정 id(UUID) 써야 상태가 항목 따라감
  • ❌ "일반 변수도 사용(read)할 때만 body 재호출" → 부모 주입 프로퍼티는 값이 다르면 안 써도 재호출(.equatable()로만 최적화). "사용할 때만"은 @State 의존성 추적에만 해당
  • ❌ "@State 아닌 일반 프로퍼티도 런타임에 변경 가능" → View는 불변 값 타입, self 못 바꿈(컴파일 에러). 변경하려면 @State여야 함
  • ❌ "바인딩으로 받은 상태도 if/else면 사라진다" → 상태는 소유자(부모) 노드에 저장. 부모는 안 죽으니 유지. 자식은 참조(포인터)만이라 자식이 죽어도 원본 멀쩡 = state lifting 원리

📘 복습 정리: SwiftUI some View 심화 — §11 identity vs type vs struct / 훅킹 / 백킹스토어 / 소유 vs 참조 / 상태 끌어올리기 / private func·let 디스패치 · §12 ForEach id / State 박스 재연결 / body 재호출 트리거(의존성추적 vs 주입) / 모디파이어 래퍼타입 / state lifting 오해 교정

2026-07-18 (토)

학습 주제 — SwiftUI 렌더링 내부 정리·정정 (등록 타이밍/인과관계)

추가 학습 — 메모리·런타임·동시성 학습노트 정리(관련 기존 문서에 분산 반영)

오답노트

  • ❌ "의존성 등록은 identity 생성 때 or 쓰기 때 한다" → body 평가 중 getter 읽는 순간. 쓰기는 등록이 아니라 무효화 트리거
  • ❌ "body 재실행되면 자기 자신 struct도 재생성" → 자식만. 자기 struct는 부모 body가 만듦
  • ❌ "struct 재생성되면 항상 body 호출" → 값 같으면 diff로 스킵
  • ❌ "일반 프로퍼티가 참조타입이면 내부 바꿔서 UI 갱신 가능" → SwiftUI가 변화 모름. 상태 래퍼(@StateObject/@Observable) 필요
  • ❌ "ForEach는 인덱스를 id로 써도 됨" → 삽입/삭제/정렬 시 상태가 엉뚱한 항목에 달라붙음. Identifiable+UUID 써야
  • ❌ "자신의 @State가 변하면 자기 struct도 재생성" → 아니다. 부모가 다시 만들 때만 재construct. 자기 @State 변화는 기존 struct로 body만 재실행
  • ❌ "부모 @State가 변하면 부모 body가 돈다" → 아니다. 그 값을 읽은(wrappedValue) 뷰만 돈다. $count를 넘기는 것(projectedValue)은 읽기가 아님 → 아무도 count를 안 읽으면 박스 값만 갱신되고 화면 그대로

📘 복습 정리: SwiftUI some View 심화 — §13 등록 타이밍(body 평가 중 getter) / body↔struct 인과 / body 재호출 순서 / 일반 프로퍼티 참조타입 함정 / 의존성 그래프 저장 위치 · §14 인덱스 id 함정 / diff 순서 / 자기 @State와 struct / 바인딩 전달≠읽기 · §15 @State/@StateObject/@ObservedObject/@Observable 차이(소유 vs 관찰, 신형 정밀추적) · §16 후속(박스=힙 / 생명주기 소유 / coarse vs fine / @Bindable) · §17 확인(래퍼vs매크로vs프로토콜 분류 / @StateObject엔 @Observable 못넣음 / var·let 규칙 / iOS17 Observation 답변 프레이밍)

2026-07-18 (토) — iOS 웹뷰 학습 시작

학습 주제 — WKWebView 기본 & 아키텍처 (Tier 1 ①)

오답노트

  • ❌ "웹뷰 렌더링도 앱 프로세스에서 돈다" → WKWebView는 WebContent 별도 프로세스. 그래서 웹 크래시가 앱을 안 죽임
  • ❌ "웹뷰 만든 뒤 configuration 바꾸면 반영됨" → 생성 시점에만 적용. 설정은 생성 전에 끝내야 함
  • ❌ "evaluateJavaScript는 바로 값 반환" → 프로세스 경계 IPC라 비동기(completion/async)
  • ❌ "JIT는 어느 프로세스나 됨" → iOS W^X 정책상 앱 프로세스는 JIT 금지, WebContent만 특별 엔타이틀먼트로 허용
  • ❌ "allowsContentJavaScript는 브리지 스크립트 얘기" → 페이지 자체 JS 실행 허용 축. 브리지 주입/evaluateJavaScript와 별개

📘 §1 후속 Q&A 8문항 정리됨(멀티프로세스 담당/JIT 원리/Configuration 클래스/JS 허용/websiteDataStore/세션 공유/영구저장 예시/IPC 비동기) → 웹뷰 학습 문서 §1

2026-07-18 (토) — 이미지 메모리·디코딩·캐싱 학습노트 정리

학습 주제 — 이미지 디코딩·다운샘플·캐싱·네트워크 심화

오답노트

  • ❌ "뷰(frame) 작게 하면 이미지 메모리 줆" → UIImage→CGImage→디코딩버퍼 참조는 그대로. 표시만 축소. downsample 필요
  • ❌ "원본 픽셀 크기에 scale 곱함" → 중복. scale은 pt→px에서만
  • ❌ "ShouldCacheImmediately:true면 백그라운드 디코딩" → 시점만 제어, 스레드는 큐가 결정
  • ❌ "URLCache 있으면 디코딩도 아낌" → 네트워크만. 디코딩은 별도 메모리 캐시 필요(층 다름)
  • ❌ "네트워크 중 취소는 checkCancellation이 잡음" → session.data가 throw. checkCancellation은 완료~디코딩 전 틈 담당

2026-07-19 (일) — 웹뷰 Tier 1 ②

학습 주제 — WKNavigationDelegate (네비게이션 제어)

오답노트

  • ❌ "navigationAction과 navigationResponse는 같은 시점" → action=요청 나가기 전, response=응답 받은 후
  • ❌ "로딩 실패는 didFail" → 대부분 커밋 전 실패라 didFailProvisionalNavigation. didFail은 커밋 후(드묾)
  • ❌ "새 창 열기도 NavigationDelegate에서" → 새 창은 WKUIDelegate(§4). targetFrame nil로 감지만
  • ❌ "didCommit = 로드 완료" → 본문 도착 시작+표시 확정(옛 페이지 교체 시작). 완료는 didFinish
  • ❌ "decisionHandler 안 불러도 됨" → 반드시 1회 호출, 안 부르면 웹뷰 멈춤
  • ❌ "네비게이션은 사용자 클릭으로만" → JS가 location.href로 프로그램 이동 가능(.other). navigationType으로 구분

📘 §2 후속 Q&A 12문항 정리됨(앱 프로세스 판단·decisionHandler·navigationResponse·provisional/commit 의미·리다이렉트 조건·커밋 후 실패·JS 프로그램 이동·체크질문 답) → 웹뷰 §2

📘 §2 실전 후속: 리다이렉트 콜백 파라미터(WKNavigation만)·navigationResponse=헤더만·didCommit 역할·.download 전환(WKDownloadDelegate, iOS14.5+)·iOS14 blob 다운로드 우회(JS FileReader→base64→postMessage→네이티브 저장)웹뷰 §2

2026-07-19 (일) — 웹뷰 Tier 1 ③

학습 주제 — JS ↔ Native 브리지

오답노트

  • ❌ "add(self, name:)는 그냥 등록" → ContentController가 self를 강하게 잡아 retain cycle → VC deinit 안 됨. WeakScriptMessageHandler 래퍼 + deinit에서 removeScriptMessageHandler 필수
  • ❌ "evaluateJavaScript에 문자열 조합으로 값 넣기" → injection 위험. callAsyncJavaScript arguments로 안전 전달
  • ❌ "message.body로 커스텀 타입 전달" → JSON 직렬화 가능 타입만(NSDictionary 등)
  • ❌ "removeScriptMessageHandler 안 해도 됨" → 잔존/같은 이름 재등록 시 크래시(NSInvalidArgumentException)

2026-07-19 (일) — 웹뷰 Tier 1 ④

학습 주제 — WKUIDelegate (JS 대화상자·새 창·파일 선택)

오답노트

  • ❌ "JS alert은 자동으로 뜬다" → WKWebView는 안 띄움. WKUIDelegate 구현 안 하면 무시
  • ❌ "completionHandler 안 불러도 됨" → JS가 그 자리에서 영원히 멈춤(alert 동기 API)
  • ❌ "팝업 만들 때 새 configuration으로" → 넘어온 configuration 써야 세션·프로세스 유지. return popup만(내가 load하면 이중)
  • ❌ "새 창은 NavigationDelegate에서 연다" → 감지만 거기(targetFrame nil), 실제 생성은 createWebViewWith(UIDelegate)

2026-07-19 (일) — 웹뷰 Tier 2 ⑤

학습 주제 — 쿠키·세션 공유 (WKHTTPCookieStore)

오답노트

  • ❌ "네이티브 로그인하면 웹뷰도 자동 로그인" → 쿠키 저장소 분리. WKHTTPCookieStore로 주입 필요
  • ❌ "쿠키 주입하고 바로 load" → setCookie 비동기라 첫 요청에 쿠키 누락. completion에서 load
  • ❌ "document.cookie로 세션 쿠키 주입" → HttpOnly는 JS 접근 불가

2026-07-19 (일) — 웹뷰 Tier 3 ⑨

학습 주제 — 웹뷰 성능

오답노트

  • ❌ "웹뷰 느리면 그냥 캐시" → 병목이 cold start/네트워크/렌더 중 어디인지 측정 먼저. cold start면 프리워밍이 임팩트 최대
  • ❌ "프리워밍=미리 데이터 받기" → 웹뷰 미리 생성+about:blank로 WebContent 프로세스를 앞당겨 기동하는 것
  • ❌ "실측만 중요" → 체감(네이티브 셸/스켈레톤)도 실측만큼 중요

2026-07-19 (일) — 스크롤 hitch

학습 주제 — 스크롤 끊김(hitch) 원인과 해결

오답노트

  • ❌ "스크롤 끊김은 GPU 문제" → 주로 메인 스레드 작업이 프레임 예산 초과. 스크롤이 메인에서 돎
  • ❌ "cornerRadius는 공짜" → masksToBounds/콘텐츠와 함께면 오프스크린 렌더링 유발. shadow도 shadowPath 없으면 매 프레임 오프스크린
  • ❌ "이미지 늦게 뜨는 건 어쩔 수 없음" → 메인 동기 디코딩이 원인. 백그라운드 디코딩+다운샘플로 해결(이미지 노트 연결)