Repository navigation
Releases: ohlulu/Apple-Dev-Skill
Releases · ohlulu/Apple-Dev-Skill
Release list
0.11.0
- Cut ~640 lines of redundant content across 39 references (9,720 → 9,080) after a line-by-line audit against the writing-skills standard. Three findings drove it.
swift-stylewas 46% baseline Swift — Apple's own API Design Guidelines, protocol-oriented design, the Optional/throws/Result/precondition severity ladder,somevsany, newtype, exhaustive switch — all content a model already applies without being told; it now carries only the codebase's own conventions and the traps (struct memberwise-init exclusion, phantom types, typed-throws default, private-member placement, MARK rules, error type placement). Second, most files closed with aChecklist/Summary/Common Pitfalls/Warning Signstable that reformatted the body as a symptom lookup — the same rule at double cost, drifting the moment one copy is edited; those are gone or trimmed to the items appearing nowhere else, while genuine pre-ship gates (makefile's Adaptation Checklist,file-structure's Generation Checklist) survive. Third, several files repeated a rule three to five times across Overview, bullets, Hard Rules, and checklist —composeralone stated "build the UI hierarchy in the screen type" five times; each rule now lives once, in the section carrying its mechanism, with pointers elsewhere. - Removed duplicate code examples that differed only in type names —
file-structure's UIView and cell examples repeated the ProfileViewController constraint block verbatim when the lesson is section ordering,list-compositionre-printed the whole Swift 6CellControllerinstead of its diff,uibutton-configuration's dynamic-font block was a ternary away from the block above it (and its replacement prose now states the mechanism the code never explained: patching a live Configuration leaks stale attributes from the previous state). - Trimmed incident retelling to design rules —
zoomable-image-preview's TOCropViewController fact reproduced a third-party library's ObjC internals and a GitHub issue number for a one-sentence rule;ios-26-behavior-changesframed its "What Did NOT Change" list as "assumed to be iOS 26 changes during this session's debugging";implicit-animationsmerged a 7-step diagnostic ladder and a 3-rule investigation list that each stated the community-fix caveat separately. - Added three authoring rules to
AGENTS.mdso the pattern does not return: say each rule once (closing sections may only hold items appearing nowhere else, or a gate that sequences body rules into an order the body does not impose), assume baseline competence (the test is "would the output differ if this line were deleted?", not "is this true?"), and a second code block differing only in type names is the first one paid for twice. - Cut the skill
descriptionfrom 1,037 to 930 characters, back under the 1,024 budget. It is always-on cost — every session pays for it whether the skill loads or not — and the trigger list carried four platform names the opening sentence already states, plus Chinese synonyms (畫面/頁面, 模組化/拆模組) that route identically. - Added
modular-architecturereference — an operational guide (not a pattern catalog) for modularizing an app: a gate against premature splitting (single-module is correct until team growth or concrete symptoms), the five-layer target blueprint (App→Features→Workflows→Services→Core) with two compiler-enforceable iron rules (same-layer modules never import each other; constructor injection wired at the App root makes cycles uncompilable), a four-question placement procedure whose no-instant-hit outcome is "stop and re-examine the taxonomy" rather than shoehorn, and recipes for the two canonical feature-module failures — shared business logic (extract a Services module, lift cross-service flows into Workflows; never a Shared grab-bag) and cross-feature screen reuse (thin API module with a screen factory protocol; the one-off shim protocol +AnyViewbridge is the anti-pattern it replaces). Also covers leaf-first monolith migration order, an anti-pattern recognition table, a module physical-form decision (generated projects: one module = one Project, multi-target projects reserved for facets of the same module — targets are compiler boundaries, projects are ownership boundaries; plain projects: local SPM packages for merge-friendliness; hand-maintained framework targets only for what SPM can't express), and the static/dynamic/mergeable linkage decision with the profile-don't-dogma rule (dynamic maps wholesale in pre-main and skips dead-code stripping, so it can be bigger than static — observed 200 kB dynamic vs 15 kB static for the same dependency). Distilled from Jacob Bartlett's modular-architecture series, the RevenueCat SDK's layering, and project-owner conventions.
0.10.0
- Documented the background-tap dismisser rule in
keyboard-avoidance— a root-view tap-to-dismiss recognizer needs a second guard beyondcancelsTouchesInView = false: it must refuse touches landing on aUIControl. The gesture's action runs before the delayedtouchesEndedreaches the control, soendEditing's layout pass writes the control's new frame to the model layer andUIControl.endTrackingthen resolves the touch-up as.touchUpOutside— the tap is silently swallowed and the user has to tap the button twice, more reliably the bigger the keyboard-driven shift. Includes theshouldReceivepredicate walking the superview chain, why deferring the dismissal couples correctness to run-loop ordering, and why the predicate belongs in a testable static function. - Documented the animated-reconfigure trap in
diffable-data-source— an animatedapplycarries structural changes only;reconfigureItemsrides a second, non-animated apply, because a cellProvider running inside the animation transaction can leave aUIStackViewarranged subview's hide / unhide half-applied (view.isHidden == true→ out of layout atx = -widthand out of the accessibility tree, whilelayer.isHidden == falsekeeps painting). Includes the pixels-present / AX-element-absent diagnostic, the lldb flag comparison, why the cell-sideperformWithoutAnimation"fix" is wrong, and why the pin belongs in UI automation rather than a unit test. Corrected the Common Mistakes row that previously prescribed foldingreconfigureItemsinto the same apply;list-composition→ "First-Apply Animation Gate" now points at it. - Fixed Crashlytics dSYM guidance in
build-phasesthat taught the single-dSYM trap — the section recommendedupload-symbols --build-phaseand explicitly said not to pass dSYM paths manually, but that mode resolves only${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}and ignores every other dSYM in the folder (verified empirically against upload-symbols 3.21). Every dynamic dependency produces its own dSYM, and in a Composition-Root layout those frameworks hold nearly all real code — so a project following the guide uploaded almost nothing and earned guaranteed missing-dSYM console warnings once real crashes arrived. Pass the wholeDWARF_DSYM_FOLDER_PATHdirectory instead: directory arguments are searched recursively, covering app + framework dSYMs in one call. The sample now fails the archive when the tool is missing rather than warning (the old fallback contradicted the file's own principle #3), and gates collection off in Debug viaFirebaseCrashlyticsCollectionEnabled, since Debug builds produce no dSYM at all and their crashes are permanently unsymbolicatable console noise. - Added
animated-image-playbackreference — traps for aUIImageViewsubclass that drives its own frame engine (SDWebImage'sSDAnimatedImagePlayer, or CADisplayLink + frame buffer). OverridingisAnimatingfreezes the subclass's own rendering: UIKit's image-display path consults it first and early-returns before_setImageViewContents:, so everysuper.image = frameupdates the model value only and the screen holds the first frame forever.SDAnimatedImageViewgets away with the override solely because it renders throughdisplayLayer:— the override and the rendering path are a load-bearing pair, and copying the API surface without the rendering half ships the freeze. Also covers the visibility-pause freeze (UICollectionView pools offscreen cells by settinghiddenin place, so no descendant hook fires on scroll-back) with a.common-mode watchdog resume, and a four-step probe ladder whose layer-property toggle is the discriminator that turns "frames delivered but screen frozen" into one specific UIKit code path. - Rewrote
makefilearound the decisions a Makefile author actually faces, not just a target list. New: recipe-vs-script split with a concrete threshold (~10 lines, loops, AppleScript, CI reuse) and the reason it matters ($$escaping, no shellcheck, nosh -x, no standalone run); simulator-vs-physical-device targeting; DerivedData strategy as an explicit trade-off table, including that sharing the IDE cache forbids-skipMacroValidationandCODE_SIGNING_ALLOWED=NObecause they change the build-settings fingerprint and force full rebuilds; streaming output viatee+grep --line-bufferedunderset -o pipefail, and whyxcbeautify --quieterswallows errors that share a task with a warning; parameterised targets (ONLY=,CONFIG=) instead of a target per scope. - Hardened build-result verification across
makefileandxcodebuild-error-detection— green now requires exit 0 and the success marker present and no crash marker. Checking only forBUILD FAILEDpasses a build that died before compiling anything (missing scheme, locked DerivedData), since such a log carries no failure line either. Dropped barecrashedfrom the crash pattern: the host app's own runtime logging shares the stream and reddens every noisy run. Logs are now named after the working directory so sibling git worktrees stop clobbering each other's results. - Replaced
simctl install bootedinmakefilewith explicit UDID resolution —bootedpicks whichever simulator happens to be up, so an iPhone sim from another project makes an iPad-only app fail to install with an error naming the app rather than the device.SIM_NAME/SIM_OSnow feed both the destination string and a runtime-scoped awk lookup, so a same-named device under another runtime cannot win. Boot viasimctl bootstatus -b, which waits for readiness; plainbootreturns early and installs in that window fail intermittently. - Documented physical-device workflows in
makefile— sourceable selection script withDEVICE_UDID=override, gitignored cache treating a disconnected device as a miss, and livexctraceprobe. A selection script must neverreadwithout a TTY: agents and CI have none, so gate prompts on[ -t 0 ], auto-select when unambiguous, and otherwise fail with the candidate list and the command to pick one. Also coversdevicectlinstall/launch,-allowProvisioningUpdates, and stating a project's no-simulator constraint (device-only binary slices) in the Makefile header. - Added
xcode-close.applescript— closes only this repo's Xcode workspace windows beforetuist generate. Matches by file path, not window title: a title prefix also closesMyAppTweakwhen regeneratingMyApp, and cannot tell two checkouts of one repo apart. Carries the two Xcode-scripting constraints:repeat with d in (get documents)yields a nested specifier Xcode resolves wrongly (distinct workspaces all report the samefile), anddocumentsis z-ordered so closing shifts later indices — index explicitly and iterate backwards. - Rewrote
Makefile.templateto match: verification-carryingxcmacro, UDID-resolvingrun, parameterisedtest, DerivedData strategy switch documented inline, and both version sources (xcconfig / Project.swift) kept as alternatives. - Fixed IDE DerivedData resolution in
makefile,Makefile.template, andxcode-project-setup— thewarningstarget matched-name '<project>-*' | head -1, but the directory suffix hashes the workspace's absolute path, so a stale entry accumulates for every location the project has occupied (git worktrees, a/tmpclone for a baseline comparison, a moved repo). A real machine had fourDingPOS-*directories, two pointing at/tmpcheckouts;head -1returns whichever the filesystem lists first, so the target could silently clean-build a different checkout and report its warnings. Now matches each candidate's recordedWorkspacePathfrominfo.plist, which is deterministic and degrades to empty for the existing guard. - Resolved a contradiction in
xcode-project-setup's DerivedData gotcha row, which prescribed pointing-derivedDataPathat "the same location Xcode GUI uses (e.g. project-local.derivedData/)" — two different locations. The actual failure is CLI and IDE disagreeing; the fix is to apply one strategy consistently, so the row now points at the new trade-off section.xcode-project-setup§ Warning Detection also notes that shared-cache projects need nowarningstarget at all. - Corrected the
CODE_SIGNING_ALLOWED=NOmechanism inmakefile,Makefile.template, andxcodebuild-error-detection. The previous text said the flag "strips theapplication-identifierentitlement". Measured across three separate apps: simulator builds carry an empty entitlements dictionary either way, so that was never the distinguishing factor. What the flag actually does is skip theCodeSignbuild phase, leaving only the linker's ad-hoc signature —codesign -dvvvreportsflags=0x20002(adhoc,linker-signed)with it versusflags=0x2(adhoc)without — and simulator securityd rejects Keychain calls from a linker-signed-only binary with-34018. The conclusion (never on an installable build) was right; the stated mechanism was wrong, and it pointed anyone diagnosing the bug at an entitlement that is legitimately absent. Also extended the rule to test targets, whose bundle is installed too, and added that the flag must be consistent across every script sharing one DerivedData path. - Fixed a live bug in the shipped
Makefile.templatehelptarget — the awk's final clause!/^##/{d=""}cleared the pending description on any non-##line, so the ordinary shape of a##doc line, then a#comment explaining the why, then the target, dropped that target from the menu. The template's owncleantarget was invisible inmake helpbecause of it. Added/^#/{next}and documented it as the third awk trap alongside the colon strip and the multi-target regex. Failure mode is nasty because the target still works — it is only missing from the menu. - Sharpened the crash pattern in
makefileandxcodebuild-error-detection— a bareSIGABRTis not safe e...
0.9.0
- Added
label-wrappingreference — multiline label wrapping in stack views: icon-row rule (hugging alone lets the icon be crushed to zero; require horizontal compression resistance too), stale wrap height under width churn fixed by a self-syncingpreferredMaxLayoutWidthlabel with placement rationale, symptom→cause table; Topic Router row carries NOT-for boundaries againstoverflow-detectionandself-sizing. - Documented layer border z-order in
shadow-and-clipping—layer.borderWidthcomposites above every sublayer, striking through overlapping subviews (floating badge, corner close button); fix is a dedicated border subview ordered below the overlapping subview. - Documented frame-level layout tests in
testing— host views in a realUIWindow(bare containers silently keep stale frames after constraint changes); harness fidelity does not reproduce production multi-pass width-churn bugs, so treat such tests as smoke-level invariants and always test-the-test against pre-fix code.
0.8.0
- Added
photo-pickerreference —PHPickerViewControllervs deprecatedUIImagePickerControllerlibrary mode (~2× slower to present, every time, and requires photo permission PHPicker doesn't need), camera-mode exception, background-queue delegate callback trap, load-failure vs remove-image contract. - Disambiguated overlapping Topic Router row families — animation (
animation/implicit-animations/compound-cell-row-animation), testing (testing-principles/testing), sizing (self-sizing/step-transition-sizing/popover-tooltip): each row now carries a scope discriminator and NOT-for cross-pointers; added a family rule requiring boundary declarations on both parent and child rows. - Expanded
cloud-backup-providers— remote-status display (list authority, stale-while-revalidate, display cache), advisory contents manifest, cache invalidation and manifest stale-drop honoring list authority and upload failure. - Documented
composeridempotent bootstrap rule for recreated detail controllers. - Documented signing rules for installable builds —
makefilerun-installed builds must stay signed (keychain-34018), andxcodebuild-error-detectionCODE_SIGNING_ALLOWED=NOmust never touch installable builds.
0.7.0
- Added
diffable-data-sourcereference — diffable as the default data source,Hashable-not-Identifiableconstraint, two Apple-blessed identifier patterns,reconfigureItemsvsreloadItemsvsapply, iOS 15animatingDifferencessemantic change, Swift 6Sendablesection/item identifier patterns, iPadOS cell focus-halo migration trap. - Added
cloud-backup-providersreference — provider-agnostic backup architecture for Google Drive / Dropbox / iCloud: user-visible storage as the iron law, OAuth scope-expansion 403 re-consent, atomic pointer publish with millisecond version ids, pointer namespaces for breaking bundle formats, storage-location migration hook, restore-integrity hardening, dedicated ephemeral transfer session with URLCache disabled, bounded POST retry, upload stall detection. - Rewrote the skill as a forward-looking guidance manual:
- Fixed factual error —
UITableView.CellRegistrationdoes not exist; documented the UITableView generic-helper alternative. - Resolved internal contradictions — animation tier table legitimizes spring for choreography; MARK rules aligned between
swift-styleandfile-structure;AnyHashableinline conformance verified compiling on Swift 6.3 and the old warning demoted to an older-toolchain fallback. - Converted war-story narratives to design rules with mechanisms; genericized private project symbols and dead links.
- Slimmed Topic Router rows to ≤2 sentences; deduplicated the iOS 26 version table and bind-before-load trap to canonical homes.
- Added generation checklists to
animation,swift-style,composer,file-structure,split-view-controller. - Expanded the mockup loop into a universal UI Verification Definition of Done; added a precedence conflict table; replaced Instruments steps with agent-executable diagnostics.
- Rewrote
diffable-data-sourcein English.
- Fixed factual error —
- Documented iOS 26
UISearchControllerprescription — custom search-field tint requires hosting a custom search pill in the root view. - Documented Tuist
.recommendeddefaultSettingsinjecting target-levelSWIFT_VERSION = 5.0that silently shadows project-xcconfig Swift 6, with therecommended(excluding:)fix. - Added
systematic-debuggingcross-trigger and screenshot-evidence verification loop to SKILL.md.
0.6.0
- Breaking: Renamed skill from
uikit-expert-skilltoapple-dev-skill. - Breaking: Renamed GitHub repo from
UIKit-Expert-SkilltoApple-Dev-Skill. - Merged
xcode-skill(Xcode/Tuist project setup, xcconfig, build phases, Makefile, shared schemes, gotchas) into this skill. - Merged
swift-coding-style(type design, protocols, error handling, API design, file organization) into this skill. - Added Topic Router sections for Xcode/Project Setup and Swift Coding Style.
- Added 8 new reference files: xcode-project-setup, xcconfig, build-phases, makefile, Makefile.template, tuist-spm-integration, xcodebuild-error-detection, swift-style.
- Added
zoomable-image-previewreference — tap-to-enlarge avatar / image viewer (IG / Photos.app / Telegram style):.overFullScreennot.customfor blur backdrop; UIScrollView zoom-target centring viabounds.size =+ symmetriccontentInset+ explicitcontentOffsetsnap;frame =under non-identity transform inflatesbounds; circularcornerRadiusscales with zoom; hero snapshot intransitionContext.containerViewcoords withalpha = 0source hiding; manual pan-to-dismiss (notUIPercentDrivenInteractiveTransition) for multi-axis follow-finger feel;shouldRecognizeSimultaneouslyWith+ lenientshouldBeginfor scroll-view coexistence; panSnapshot identity re-entry guard; third-party VC self-settransitioningDelegatetrap (TOCropViewController #486); JPEG storage of circular crops produces white corners that the preview must re-mask. - Added
Contracts + Wiringsection tozoomable-image-preview— piece contracts (HeroSource alpha semantics + 3-place restore, PreviewVC strong-holds delegate, snapshot lives in view not window), ownership graph (UIKit weak → delegate trap), pan handler state-by-state contract (must do / must not do), 7-point acceptance checklist (initial centring, pinch round-trip, cancel pan, commit drag, commit flick, close button, source restoration after 5×). - Added
step-transition-sizingreference. - Added
cli-distribution-signingreference. - Added
localization-bundle-discoveryandlocalizable-strings-escapesreferences. - Documented iOS 26 implicit-animation traps across
split-view-controller(push-transition + secondary-swap suppression, three-layer audit, bind-before-load sync-fire) andapple-dev-skillTopic Router; nav-bar split appearance + UISearchBar background + sticky header bleed notes. - Documented
shadow-and-clippingUILabelbackgroundColor+cornerRadiustrap;popover-tooltipsystemLayoutSizeFittingwarning;self-sizingauto-resize-on-layout-pass trap. - Documented
icloud-ubiquity.currentvs.downloadedrule. - Documented testing async XCTest + task allocator trap and test crash detection.
- Documented
makefileBUILD FAILED trap, trash-based clean, tuist companions;build-phasesCrashlytics-gsp+-p iosrequirement. - Documented
swift-stylestruct memberwise-init trap for let-with-default. - Skill routing description rewritten to trigger by project type, not phrasing.
0.4.0
- Added iCloud ubiquity container reference —
startDownloadingUbiquitousItem,NSMetadataQuerydiscovery,NSUbiquitousContainerseager-init gotcha. - Added popover-tooltip reference — safe-area centering trap.
- Fixed release skill flow to zero-gate after version confirmation.
0.3.0
- Added self-sizing reference —
systemLayoutSizeFitting,preferredContentSize, cell auto-dimension. - Added image-resizing reference — API decision matrix, export gotcha, template icon pattern.
- Added view-wrapping reference —
wrapped(insets:), section decoration, decision matrix. - Added alignment and UIButton.Configuration references.
- Added shadow-and-clipping reference with parent/child split and iOS 26 sheet gotcha.
- Added keyboard-avoidance reference.
- Added overflow detection and expand/collapse animation references.
- Added menu-vs-popover decision reference.
- Added UIButton icon badge reference.
- Added navigation-bar-appearance reference (iOS 26
backgroundColorbreaking change). - Added autolayout-spacing reference.
- Added staggered entrance animation pattern for collection view cells.
- Added CALayer frame ownership, transform-safe positioning, and custom layout animation pitfalls.
- Added associated-objects reference — eliminating
objc_setAssociatedObject. - Added callback shape rule — avoid closure-of-closures in navigation wiring.
- Added UIViewRepresentable bridge patterns reference.
- Expanded list-composition with dispatch contract, generation checklist, pitfalls, section-level dispatch, stateful sections, and supplementary delegation.
- Added CellRegistration reference — prefer over legacy register/dequeue.
- Added compound-cell-row-animation reference (UISwitch distortion,
performBatchUpdates,isHiddenpattern). - Added project-local release skill.
0.2.0
- Relaxed UI property guidance: use direct initialization for one-line setup; reserve
lazy varclosures for multi-statement inline configuration. - Expanded list composition guidance with a concrete
CellControlleridentity shape, a fullerListViewControllerforwarding skeleton, and prefetch forwarding. - Added visible load-more row guidance with
LoadMoreViewModel,LoadMoreCellController, and a minimalPaginated<Item>seam for UIKit pagination consumption. - Expanded UIKit testing guidance with semantic list helpers, load-more test helpers, pagination integration test flow, and a note on fake refresh controls for deterministic tests.
- Added composer guidance for programmatic screen factories, dependency wiring, navigation closures, and scene root composition.
0.1.0
- Added file structure patterns reference for ViewController / UIView organization (extension separation, access level ordering, lazy var UI properties, layout placement).
- Added animation patterns reference (0.1s linear fade default, case-dependent transition durations, no spring unless requested).
- Cleaned up
SKILL.mdfor AI-friendliness: operating rules with explicit trigger conditions, single topic router, removed empty placeholders. - Removed "No Code Formatting or Linting" restriction from
AGENTS.md.