% recall-drill-named-facts.tex — every NAMED / enumerable fact the student has failed to recall.
% Sources (each answer checked against the qaa "Complete answer"):
%   docs/school/teacher/plan.md (Notes for next session, covered-question index)
%   docs/school/qaa/{ios-autolayout,ios-networking,ios-memory,swiftui,design-patterns,testing,ios-lifecycle}.md
%   docs/memos/testing-doubles.md (Q1, the five doubles)
% Build ONLY with: tools/print/print-sheet.py <this>.tex --dry-run
% @source: hiot monorepo, docs/school/sheets/recall/recall-drill-named-facts.tex — the SOURCE OF TRUTH; a copy anywhere else (e.g. artur.gurgul.pro) is regenerated from it, never edited
% @labels: area=recall kind=drill level=core platform=ios new=no round=round2-2026-09-23 topic=ui,memory,patterns
% @tags: layout-priorities, uistackview, codingkeys, urlerror, memory-graph-debugger, capture-list, copy-on-write, test-pyramid, test-doubles, solid, gof-patterns, responder-chain
\documentclass[8pt]{extarticle}
\usepackage{printup-sheet}

% Q → A drill line: question in black, answer in colour (cover the colour, say it aloud).
\newcommand\qa[2]{\par\noindent\hangindent=1.5mm\textbf{#1}\,\textcolor{sheetGrey}{→}\,\textcolor{sheetBlue}{#2}\par\vspace{1.1pt}}
% qm = a fact missed TWICE / flagged as the headline weakness
\newcommand\qm[2]{\par\noindent\hangindent=1.5mm\textcolor{sheetRed}{\textbf{!}}\ \textbf{#1}\,\textcolor{sheetGrey}{→}\,\textcolor{sheetBlue}{#2}\par\vspace{1.1pt}}
\newcommand\grp[1]{\par\vspace{2.5pt}\noindent\colorbox{sheetOrange!16}{\makebox[\dimexpr\linewidth-2\fboxsep][l]{\bfseries\footnotesize #1}}\par\vspace{1.5pt}}
\newcommand\ct[1]{\texttt{#1}}

\begin{document}

\sheettitle{Recall drill — the named facts you missed}{recall · drill}

\oneliner{Cover the \textcolor{sheetBlue}{blue}, say the answer \emph{aloud}, uncover. Every line
is a question you answered ``I don't know'', half-right, or backwards.
\textcolor{sheetRed}{\textbf{!}} = missed twice / headline gap. Exact names, numbers, lists — the
reasoning you already have.}

\begin{multicols}{3}
\footnotesize\setstretch{1.0}\raggedright

\grp{Auto Layout}
\qm{UIStackView — 4 properties}{\ct{axis} · \ct{distribution} (sizing \emph{along} axis) ·
    \ct{alignment} (\emph{across} axis) · \ct{spacing}}
\qa{distribution values}{\ct{.fill} (default) · \ct{.fillEqually} · \ct{.fillProportionally} ·
    \ct{.equalSpacing} · \ct{.equalCentering}}
\qm{Priority values}{\ct{.required} = \textbf{1000} · \ct{.defaultHigh} = \textbf{750} ·
    \ct{.defaultLow} = \textbf{250}}
\qa{Content hugging}{resists \emph{growing} past intrinsic size; default \textbf{250}}
\qa{Compression resistance}{resists \emph{shrinking} below intrinsic size (truncation); default \textbf{750}}
\qa{Who loses a tie?}{the \textbf{lower} priority stretches/shrinks; nudge ±1 (749, 251) to decide}
\qa{\#1 cause: code view at 0/wrong place}{forgot \ct{translatesAutoresizingMaskIntoConstraints = false}}
\qa{Facts per view}{x, y, width, height — size may come from \textbf{intrinsic content size}}
\qa{Unsatisfiable constraints}{≥2 contradictory \emph{required} (1000) → engine breaks one
    arbitrarily + log; optional (<1000) breaks silently}
\qa{Self-sizing cells}{\ct{rowHeight = .automaticDimension} + non-zero \ct{estimatedRowHeight} +
    unbroken top→bottom chain in \ct{contentView}}
\qa{Size classes}{horizontal/vertical × \ct{.compact}/\ct{.regular}; iPhone portrait = compact W,
    regular H; iPad = regular/regular}

\grp{Networking}
\qm{JSON \ct{user\_name} → \ct{userName}}{(1) \ct{enum CodingKeys: String, CodingKey \{ case
    userName = "user\_name" \}} (per key) (2) \ct{decoder.keyDecodingStrategy =
    .convertFromSnakeCase} (blanket) (3) custom \ct{init(from:)}}
\qm{3 error layers (Reach·Receive·Read)}{\ct{URLError} (transport) → HTTP \ct{statusCode} not in
    \ct{200..<300} (\emph{not thrown}) → \ct{DecodingError}
    (\ct{.keyNotFound}/\ct{.typeMismatch}/\ct{.dataCorrupted})}
\qm{\ct{dataTask} completion thread}{URLSession's \textbf{background} queue, never main →
    \ct{DispatchQueue.main.async}; call \ct{.resume()}}
\qa{async/await \ct{data(from:)}}{resumes on the caller's actor — \ct{@MainActor} caller needs no hop}
\qa{Pinning delegate}{\ct{urlSession(\_:didReceive:}\allowbreak\ct{completionHandler:)} with
    \ct{URLAuthenticationChallenge} → \ct{serverTrust} → \ct{SecTrustEvaluateWithError} → SPKI hash →
    \ct{.useCredential} / \ct{.cancelAuthenticationChallenge}. Default TLS validation: \textbf{yes}}

\grp{VC \& app lifecycle}
\qa{VC order}{\ct{loadView} → \ct{viewDidLoad} (once) → \ct{viewWillAppear} → \ct{viewDidAppear} →
    \ct{viewWillDisappear} → \ct{viewDidDisappear}}
\qa{Frame valid from}{\ct{viewWillLayoutSubviews} — \emph{not} \ct{viewDidLoad}}
\qa{App states}{Not Running → Inactive → Active ↔ Inactive → Background → Suspended}

\columnbreak

\grp{Memory \& value semantics}
\qm{3 memory tools}{\textbf{Memory Graph Debugger} (cycles: who retains whom) ·
    \textbf{Leaks} (unreachable blocks) · \textbf{Allocations} (growth; Mark Generation)}
\qa{\ct{weak} vs \ct{unowned}}{\ct{weak}: Optional, auto-nils, target may die first ·
    \ct{unowned}: non-optional, target outlives self, crash if touched after dealloc}
\qa{Does \ct{var x: C?} break a cycle?}{\textbf{No} — \ct{?} = nil-ability; \ct{weak}/\ct{unowned} = ownership}
\qa{\ct{weak var delegate: P?} needs}{\ct{protocol P: AnyObject}}
\qm{\ct{\{ [x] in print(x) \}}, then \ct{x = 20}}{prints \textbf{10}: capture list = \textbf{by-value
    snapshot} at creation. No list → captures the variable → 20. \ct{[obj]} copies the \emph{pointer}}
\qm{Copy-on-write}{\ct{Array} \ct{Dictionary} \ct{Set} \ct{String} (+\ct{Data}): struct wrapping
    class storage; \ct{isKnownUniquelyReferenced(\&storage)} — 1 → mutate in place, >1 → copy first.
    Your structs: \emph{no} COW for free}
\qm{\ct{mutating}}{lets a struct/enum method change \ct{self}; caller must be \ct{var};
    classes never need it; on a \ct{let} struct → compile error}
\qa{When must it be a class?}{identity/shared state · inheritance · ObjC interop · \ct{deinit}}
\qa{Unit-test a leak}{\ct{weak var ref}; create SUT in inner scope; after scope
    \ct{XCTAssertNil(ref)}}

\grp{SwiftUI}
\qa{\ct{some View}}{opaque type: compiler \emph{knows} the concrete type; hidden from the caller}
\qa{\ct{@StateObject} vs \ct{@ObservedObject}}{view creates \& owns (once) vs passed in;
    \ct{@ObservedObject var vm = VM()} resets on parent re-render}
\qa{\ct{@Binding}}{two-way ref to a parent's \ct{@State}, made with \ct{\$}; owns nothing}
\qa{iOS 17 \ct{@Observable}}{owned → \ct{@State}; injected → plain property}

\grp{Testing}
\qm{Test pyramid}{Unit \textbf{70\%} · Integration \textbf{20\%} · UI \textbf{10\%}; inverted =
    ``ice-cream cone''}
\qa{5 test doubles}{\textbf{Dummy} (fills a slot) · \textbf{Stub} (canned answers) · \textbf{Spy}
    (stub + records calls) · \textbf{Mock} (pre-set expectations, self-verifies) · \textbf{Fake}
    (working simplified impl, e.g. in-memory)}
\qa{\ct{\#expect} vs \ct{\#require}}{soft (continues) vs hard (throws, stops)}
\qa{XCTest per-test order}{new instance → \ct{setUpWithError} → \ct{setUp} → test → teardown
    blocks (LIFO) → \ct{tearDownWithError} → \ct{tearDown}}

\grp{Architecture}
\qa{Logic lives in (MVC / MVP / MVVM)}{Controller / Presenter (View behind a \textbf{protocol}, no
    UIKit) / ViewModel (View \textbf{binds}, VM has no View ref)}
\qa{Facade — what + risk}{one simple interface over a subsystem (\ct{URLSession}, Repository);
    risk: swells into a \textbf{god object} — delegate, don't implement}
\qa{Adapter — textbook iOS}{\ct{UIViewRepresentable} / \ct{UIHostingController} (UIKit ↔ SwiftUI)}
\qa{Coordinator solves}{a VC that pushes its next screen knows its siblings → not reusable; VC
    signals intent, Coordinator navigates}
\qa{Repository read}{cache → miss → API → write back → return; caller never knows the source}
\qa{DI vs DIP}{DI = technique (pass deps in); DIP = principle (depend on abstractions)}

\columnbreak

\grp{Design patterns}
\qm{Singleton downsides}{hidden dependencies · hard to test / state leaks · global mutable state ·
    tight coupling (breaks DIP). Impl: \ct{static let shared} (lazy, thread-safe) + \ct{private init}}
\qm{Strategy vs State}{Strategy: \textbf{client picks} the algorithm (\emph{stra}nger) ·
    State: object \textbf{transitions itself} (\emph{self})}
\qm{Observer's problem}{\textbf{leaks} / retain cycles if not unsubscribed → \ct{AnyCancellable},
    \ct{store(in:)}, \ct{removeObserver}}
\qm{Command → undo}{\ct{execute()} + \ct{undo()} (captures state); undo stack: undo = pop, \ct{undo()},
    push to redo}
\qm{Proxy variants}{\textbf{V}irtual · \textbf{P}rotection · \textbf{R}emote · \textbf{C}aching
    (``Very Private Rooms Cache''); \ct{lazy var} = virtual proxy}
\qa{Interface: Adapter / Decorator / Facade / Proxy}{changes it / keeps + adds behaviour /
    new simpler one / keeps + gates access}
\qm{Template Method}{\textbf{Hollywood principle}: ``don't call us, we'll call you'' — base calls
    your hooks; e.g. \ct{UIViewController} lifecycle}
\qm{Responder chain direction}{\textbf{up}: first responder → superview → VC → window →
    \ct{UIApplication} → app delegate. \textbf{Hit-testing} goes \textbf{down}}
\qa{Mediator}{peers talk via a hub: \textbf{N$^2$ → N} links (Coordinator, VM, \ct{UINavigationController})}
\qa{Factory Method vs Abstract Factory}{FM: subclass overrides to pick \textbf{one} product ·
    AF: one object makes a \textbf{family}. \ct{create(type:)} switch = Simple Factory}
\qm{Decorator vs subclass}{N features → \textbf{2$^N$} subclasses vs N stackable wrappers; Swift:
    \ct{ViewModifier}}
\qa{Builder}{fixes telescoping init; Swift: default params; recipe object = \textbf{Director}}
\qa{Iterator in Swift}{\ct{IteratorProtocol.next() -> Element?} (\ct{nil} = end) +
    \ct{Sequence.makeIterator()}}
\qa{Strategy serves}{\textbf{Open/Closed + Dependency Inversion} (not ISP)}

\grp{SOLID — exact one-liners}
\qa{S}{one, and only one, \textbf{reason to change}}
\qa{O}{open for extension, closed for modification}
\qa{L}{subtypes substitutable for their base types (Square:Rectangle breaks it)}
\qm{I}{\textbf{clients} should not be forced to depend on methods they do not use}
\qm{D}{high- \emph{and} low-level modules \textbf{both} depend on abstractions; abstractions don't
    depend on details}

\grp{Memory hooks — say them once a day}
\qa{Errors}{\textbf{Reach, Receive, Read}}
\qa{Tools}{\textbf{Graph} = cycles · \textbf{Leaks} = unreachable · \textbf{Allocations} = growing}
\qa{Priorities}{1000/750/250, spaced by 250 so ±1 breaks ties; 750 = ``don't shrink me'',
    250 = ``don't stretch me''}
\qa{Capture list}{a \textbf{photo}: values freeze; references freeze the \emph{pointer}}
\qa{Ownership}{\ct{weak}/\ct{unowned} change ownership; \ct{?} only changes nil-ability}
\qa{Stack view}{axis = direction · distribution = \emph{along} · alignment = \emph{across} · spacing = gaps}
\qa{Adapter · Decorator · Proxy}{\emph{changes} · \emph{adds} · \emph{gates} (a bouncer)}

\end{multicols}

\vspace{2pt}
\noindent{\footnotesize\color{sheetGrey}\textit{Related:} auto-layout · urlsession-networking ·
arc-ownership · value-vs-reference · app-and-vc-lifecycle · swiftui-state · gof-creational-structural ·
gof-behavioural · solid · testing-fundamentals}

\end{document}
