[{"data":1,"prerenderedAt":1260},["ShallowReactive",2],{"navigation_docs":3,"-blog-create-uikit-ios-project":173,"-blog-create-uikit-ios-project-surround":1255},[4,22,29,36,107,138,145,161],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"博客","i-lucide-pen-line","\u002Fblog","0.blog",[10,12,17],{"title":5,"path":7,"stem":11,"icon":6},"0.blog\u002Findex",{"title":13,"path":14,"stem":15,"icon":16},"创建基于 UIKit 的原生 iOS 项目","\u002Fblog\u002Fcreate-uikit-ios-project","0.blog\u002F01.create-uikit-ios-project","i-lucide-app-window",{"title":18,"path":19,"stem":20,"icon":21},"Lockify：把账号和密码留在自己的手机里","\u002Fblog\u002Flockify","0.blog\u002F02.lockify","i-lucide-lock",{"title":23,"path":24,"stem":25,"children":26,"icon":28},"年度总结","\u002Fannual-review","1.annual-review\u002Findex",[27],{"title":23,"path":24,"stem":25,"icon":28},"i-lucide-git-commit",{"title":30,"path":31,"stem":32,"children":33,"icon":35},"故事","\u002Fstories","2.stories\u002Findex",[34],{"title":30,"path":31,"stem":32,"icon":35},"i-lucide-feather",{"title":37,"icon":38,"path":39,"stem":40,"children":41},"Android","i-simple-icons-android","\u002Fandroid","3.android",[42,44,49],{"title":37,"path":39,"stem":43,"icon":38},"3.android\u002Findex",{"title":45,"path":46,"stem":47,"icon":48},"初探Navigation","\u002Fandroid\u002Fcompose-navigation","3.android\u002F01.compose-navigation","i-lucide-route",{"title":50,"icon":51,"path":52,"stem":53,"children":54},"安卓代码加固","i-lucide-shield","\u002Fandroid\u002Fhidden-hardening","3.android\u002F02.hidden-hardening\u002Findex",[55,58,62,67,72,77,82,87,92,97,102],{"title":56,"path":52,"stem":53,"icon":57},"安卓代码加固：总览","i-lucide-map",{"title":59,"path":60,"stem":61,"icon":21},"安卓代码加固（1）：加密DEX","\u002Fandroid\u002Fhidden-hardening\u002Fencrypt-dex","3.android\u002F02.hidden-hardening\u002F01.encrypt-dex",{"title":63,"path":64,"stem":65,"icon":66},"安卓代码加固（2）：Native解密","\u002Fandroid\u002Fhidden-hardening\u002Fnative-decrypt","3.android\u002F02.hidden-hardening\u002F02.native-decrypt","i-lucide-cpu",{"title":68,"path":69,"stem":70,"icon":71},"安卓代码加固（3）：内存加载","\u002Fandroid\u002Fhidden-hardening\u002Fmemory-load","3.android\u002F02.hidden-hardening\u002F03.memory-load","i-lucide-memory-stick",{"title":73,"path":74,"stem":75,"icon":76},"安卓代码加固（4）：指令分发","\u002Fandroid\u002Fhidden-hardening\u002Fopcode-dispatch","3.android\u002F02.hidden-hardening\u002F04.opcode-dispatch","i-lucide-hash",{"title":78,"path":79,"stem":80,"icon":81},"安卓代码加固（5）：XOR混淆","\u002Fandroid\u002Fhidden-hardening\u002Fxor-obfuscate","3.android\u002F02.hidden-hardening\u002F05.xor-obfuscate","i-lucide-shuffle",{"title":83,"path":84,"stem":85,"icon":86},"安卓代码加固（6）：密钥外置","\u002Fandroid\u002Fhidden-hardening\u002Fkey-external","3.android\u002F02.hidden-hardening\u002F06.key-external","i-lucide-key",{"title":88,"path":89,"stem":90,"icon":91},"安卓代码加固（7）：依赖隔离","\u002Fandroid\u002Fhidden-hardening\u002Fdep-isolate","3.android\u002F02.hidden-hardening\u002F07.dep-isolate","i-lucide-layers",{"title":93,"path":94,"stem":95,"icon":96},"安卓代码加固（8）：构建校验","\u002Fandroid\u002Fhidden-hardening\u002Fbuild-verify","3.android\u002F02.hidden-hardening\u002F08.build-verify","i-lucide-shield-check",{"title":98,"path":99,"stem":100,"icon":101},"安卓代码加固（9）：防录屏","\u002Fandroid\u002Fhidden-hardening\u002Fflag-secure","3.android\u002F02.hidden-hardening\u002F09.flag-secure","i-lucide-eye-off",{"title":103,"path":104,"stem":105,"icon":106},"安卓代码加固（10）：ABI门禁","\u002Fandroid\u002Fhidden-hardening\u002Fabi-gate","3.android\u002F02.hidden-hardening\u002F10.abi-gate","i-lucide-git-compare",{"title":108,"icon":109,"path":110,"stem":111,"children":112},"iOS","i-simple-icons-apple","\u002Fios","4.ios",[113,115,120,125,129,133],{"title":108,"path":110,"stem":114,"icon":109},"4.ios\u002Findex",{"title":116,"path":117,"stem":118,"icon":119},"iOS面试题1","\u002Fios\u002Fios-interview1","4.ios\u002F01.ios-interview1","i-lucide-sparkles",{"title":121,"path":122,"stem":123,"icon":124},"设置启动图","\u002Fios\u002Fset-launch-screen","4.ios\u002F02.set-launch-screen","i-lucide-image",{"title":126,"path":127,"stem":128,"icon":48},"路由管理","\u002Fios\u002Frouting","4.ios\u002F03.routing",{"title":130,"path":131,"stem":132,"icon":91},"状态管理","\u002Fios\u002Fstate-management","4.ios\u002F04.state-management",{"title":134,"path":135,"stem":136,"icon":137},"事件传递","\u002Fios\u002Fevent-delivery","4.ios\u002F05.event-delivery","i-lucide-pointer",{"title":139,"path":140,"stem":141,"children":142,"icon":144},"Flutter","\u002Fflutter","5.flutter\u002Findex",[143],{"title":139,"path":140,"stem":141,"icon":144},"i-simple-icons-flutter",{"title":146,"icon":147,"path":148,"stem":149,"children":150,"page":160},"面试","i-lucide-graduation-cap","\u002Finterview","6.interview",[151,156],{"title":152,"path":153,"stem":154,"icon":155},"Flutter面试题1","\u002Finterview\u002Fflutter-interview1","6.interview\u002F01.flutter-interview1","i-lucide-boxes",{"title":157,"path":158,"stem":159,"icon":66},"Flutter面试题2","\u002Finterview\u002Fflutter-interview2","6.interview\u002F02.flutter-interview2",false,{"title":162,"icon":163,"path":164,"stem":165,"children":166},"算法学习","i-lucide-binary","\u002Falgorithm","7.algorithm",[167,169],{"title":162,"path":164,"stem":168,"icon":163},"7.algorithm\u002Findex",{"title":170,"path":171,"stem":172},"算法基础1：复杂度分析","\u002Falgorithm\u002Ftime-space-complexity","7.algorithm\u002F01.time-space-complexity",{"id":174,"title":13,"body":175,"description":1228,"extension":1229,"links":1230,"meta":1243,"navigation":1250,"path":14,"seo":1251,"stem":15,"__hash__":1254},"docs\u002F0.blog\u002F01.create-uikit-ios-project.md",{"type":176,"value":177,"toc":1217},"minimark",[178,182,190,194,204,207,297,303,306,315,321,327,333,337,340,388,395,405,411,417,423,426,441,685,688,694,866,873,876,885,891,898,907,911,918,927,942,951,963,971,1038,1043,1055,1068,1077,1085,1107,1113,1117,1120,1139,1145,1162,1173,1184,1187,1213],[179,180,181],"p",{},"现在用 Xcode 新建 App，默认已经是 SwiftUI。我还是更习惯手写 UIKit，所以把从建工程到跑起来的步骤记一下。",[179,183,184,185,189],{},"本文用的是 ",[186,187,188],"strong",{},"Xcode 16.5","。目标很简单：不要 Storyboard 拖控件，用纯代码把界面拉起来。",[191,192,193],"h2",{"id":193},"前置准备",[195,196,197,201],"ul",{},[198,199,200],"li",{},"一台 macOS 电脑",[198,202,203],{},"已经装好 Xcode，文章用的版本是 16.5",[191,205,206],{"id":206},"创建项目",[208,209,210,216,229],"ol",{},[198,211,212,213],{},"打开 Xcode，选择 ",[186,214,215],{},"Create New Project",[198,217,218,219,221,222,225,226],{},"模板界面先选 ",[186,220,108],{},"，再选 ",[186,223,224],{},"App","，然后点 ",[186,227,228],{},"Next",[198,230,231,232],{},"项目配置可以按下面填：\n",[195,233,234,244,253,262,276,285,291],{},[198,235,236,239,240],{},[186,237,238],{},"Product Name","：项目名称，例如 ",[241,242,243],"code",{},"TestApp",[198,245,246,249,250],{},[186,247,248],{},"Team","：没有开发者账号就选 ",[186,251,252],{},"None",[198,254,255,258,259],{},[186,256,257],{},"Organization Identifier","：唯一标识符，比如 ",[241,260,261],{},"com.example",[198,263,264,267,268,271,272,275],{},[186,265,266],{},"Interface","：选 ",[186,269,270],{},"Storyboard","。别直接选 SwiftUI，否则后面没有 ",[241,273,274],{},"SceneDelegate","，改成 UIKit 会更麻烦",[198,277,278,281,282],{},[186,279,280],{},"Language","：99% 的情况都选 ",[186,283,284],{},"Swift",[198,286,287,290],{},[186,288,289],{},"Testing System","：暂时不需要",[198,292,293,296],{},[186,294,295],{},"Storage","：可选可不选，先不选就行",[179,298,299,300,302],{},"点 ",[186,301,228],{},"，选个保存路径，创建项目。",[179,304,305],{},"图解步骤：",[179,307,308],{},[309,310],"img",{"alt":311,"className":312,"src":314},"创建新项目",[313],"max-w-md","https:\u002F\u002Ffilebed.chenyiren.top\u002Ffiles\u002F2026\u002F09\u002F2365b38349e606b9aa4a.png",[179,316,317],{},[309,318],{"alt":311,"className":319,"src":320},[313],"https:\u002F\u002Ffilebed.chenyiren.top\u002Ffiles\u002F2026\u002F09\u002F1f95fdae5e8b5a3ad9ee.jpg",[179,322,323],{},[309,324],{"alt":311,"className":325,"src":326},[313],"https:\u002F\u002Ffilebed.chenyiren.top\u002Ffiles\u002F2026\u002F09\u002F2018323cc549b5ea9db6.jpg",[179,328,329],{},[309,330],{"alt":311,"className":331,"src":332},[313],"https:\u002F\u002Ffilebed.chenyiren.top\u002Ffiles\u002F2026\u002F09\u002Fa16bbbf27a7374171202.jpg",[191,334,336],{"id":335},"删除-storyboard","删除 Storyboard",[179,338,339],{},"新建出来的项目默认还是走 Storyboard。要纯代码开发，相关文件和配置都得清掉。",[208,341,342,349,359,370],{},[198,343,344,345,348],{},"删除项目里的 ",[241,346,347],{},"Main.storyboard","（没有这个文件就跳过）",[198,350,351,352,355,356],{},"点项目根目录，切到 ",[186,353,354],{},"TARGETS"," 下的 ",[186,357,358],{},"Info",[198,360,361,362,365,366,369],{},"找到 ",[186,363,364],{},"Main storyboard file base name","，删掉这一条（对应 ",[241,367,368],{},"UIMainStoryboardFile","）",[198,371,372,373,376,377,380,381,384,385,369],{},"再展开 ",[186,374,375],{},"Application Scene Manifest"," → ",[186,378,379],{},"Scene Configuration","，把里面的 ",[186,382,383],{},"Storyboard Name"," 也删掉（对应 ",[241,386,387],{},"UISceneStoryboardFile",[179,389,390,391,394],{},"两处都要删。只删文件、或者只清其中一处，启动时还会去加载已经不存在的 ",[241,392,393],{},"Main","，直接崩溃。",[179,396,397,400,401,404],{},[186,398,399],{},"Launch Screen"," 那一项不要动，那是启动图，不是主界面。怎么换成自己的图，写在 ",[402,403,121],"a",{"href":122},"。",[179,406,407,408,410],{},"Build Settings 里如果还能搜到 ",[241,409,368],{},"，一并清空就行。",[179,412,413],{},[309,414],{"alt":336,"className":415,"src":416},[313],"https:\u002F\u002Ffilebed.chenyiren.top\u002Ffiles\u002F2026\u002F09\u002F2852957387bb294fee81.jpg",[179,418,419],{},[309,420],{"alt":336,"className":421,"src":422},[313],"https:\u002F\u002Ffilebed.chenyiren.top\u002Ffiles\u002F2026\u002F09\u002F022b2485c41f805a6229.jpg",[191,424,425],{"id":425},"设置根控制器",[179,427,428,429,432,433,436,437,440],{},"打开 ",[241,430,431],{},"SceneDelegate.swift","，用代码手动把窗口和根控制器挂上。Xcode 16 的 App 模板走的是 Scene 生命周期，窗口要挂在 ",[241,434,435],{},"UIWindowScene"," 上，不用再写回以前那种只给 ",[241,438,439],{},"AppDelegate.window"," 赋值的老办法。",[442,443,448],"pre",{"className":444,"code":445,"filename":431,"language":446,"meta":447,"style":447},"language-swift shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import UIKit\n\nclass SceneDelegate: UIResponder, UIWindowSceneDelegate {\n\n    var window: UIWindow?\n\n    \u002F\u002F 核心代码\n    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {\n        guard let windowScene = (scene as? UIWindowScene) else { return }\n        window = UIWindow(windowScene: windowScene)\n        window?.rootViewController = ViewController()\n        window?.makeKeyAndVisible()\n    }\n}\n","swift","",[241,449,450,463,470,497,502,515,520,527,573,614,638,658,673,679],{"__ignoreMap":447},[451,452,455,459],"span",{"class":453,"line":454},"line",1,[451,456,458],{"class":457},"s7zQu","import",[451,460,462],{"class":461},"sBMFI"," UIKit\n",[451,464,466],{"class":453,"line":465},2,[451,467,469],{"emptyLinePlaceholder":468},true,"\n",[451,471,473,477,480,484,487,491,494],{"class":453,"line":472},3,[451,474,476],{"class":475},"spNyl","class",[451,478,479],{"class":461}," SceneDelegate",[451,481,483],{"class":482},"sMK4o",":",[451,485,486],{"class":461}," UIResponder",[451,488,490],{"class":489},"sTEyZ",", ",[451,492,493],{"class":461},"UIWindowSceneDelegate ",[451,495,496],{"class":482},"{\n",[451,498,500],{"class":453,"line":499},4,[451,501,469],{"emptyLinePlaceholder":468},[451,503,505,509,512],{"class":453,"line":504},5,[451,506,508],{"class":507},"sbssI","    var",[451,510,511],{"class":489}," window: UIWindow",[451,513,514],{"class":482},"?\n",[451,516,518],{"class":453,"line":517},6,[451,519,469],{"emptyLinePlaceholder":468},[451,521,523],{"class":453,"line":522},7,[451,524,526],{"class":525},"sHwdD","    \u002F\u002F 核心代码\n",[451,528,530,533,537,540,543,546,549,552,555,558,561,564,567,570],{"class":453,"line":529},8,[451,531,532],{"class":475},"    func",[451,534,536],{"class":535},"s2Zo4"," scene",[451,538,539],{"class":482},"(",[451,541,542],{"class":535},"_",[451,544,536],{"class":545},"sHdIc",[451,547,548],{"class":489},": UIScene, ",[451,550,551],{"class":535},"willConnectTo",[451,553,554],{"class":545}," session",[451,556,557],{"class":489},": UISceneSession, ",[451,559,560],{"class":535},"options",[451,562,563],{"class":545}," connectionOptions",[451,565,566],{"class":489},": UIScene.ConnectionOptions",[451,568,569],{"class":482},")",[451,571,572],{"class":482}," {\n",[451,574,576,579,582,585,588,591,594,597,600,602,605,608,611],{"class":453,"line":575},9,[451,577,578],{"class":457},"        guard",[451,580,581],{"class":507}," let",[451,583,584],{"class":489}," windowScene ",[451,586,587],{"class":482},"=",[451,589,590],{"class":482}," (",[451,592,593],{"class":489},"scene ",[451,595,596],{"class":482},"as?",[451,598,599],{"class":489}," UIWindowScene",[451,601,569],{"class":482},[451,603,604],{"class":457}," else",[451,606,607],{"class":482}," {",[451,609,610],{"class":457}," return",[451,612,613],{"class":482}," }\n",[451,615,617,620,622,625,627,630,632,635],{"class":453,"line":616},10,[451,618,619],{"class":489},"        window ",[451,621,587],{"class":482},[451,623,624],{"class":535}," UIWindow",[451,626,539],{"class":482},[451,628,629],{"class":535},"windowScene",[451,631,483],{"class":482},[451,633,634],{"class":489}," windowScene",[451,636,637],{"class":482},")\n",[451,639,641,644,647,650,652,655],{"class":453,"line":640},11,[451,642,643],{"class":489},"        window",[451,645,646],{"class":482},"?",[451,648,649],{"class":489},".rootViewController ",[451,651,587],{"class":482},[451,653,654],{"class":535}," ViewController",[451,656,657],{"class":482},"()\n",[451,659,661,663,665,668,671],{"class":453,"line":660},12,[451,662,643],{"class":489},[451,664,646],{"class":482},[451,666,667],{"class":489},".",[451,669,670],{"class":535},"makeKeyAndVisible",[451,672,657],{"class":482},[451,674,676],{"class":453,"line":675},13,[451,677,678],{"class":482},"    }\n",[451,680,682],{"class":453,"line":681},14,[451,683,684],{"class":482},"}\n",[191,686,687],{"id":687},"自定义控制器",[179,689,428,690,693],{},[241,691,692],{},"ViewController.swift","，先铺一层背景，再加一行居中文本，用来确认窗口已经接到你的控制器。",[442,695,697],{"className":444,"code":696,"filename":692,"language":446,"meta":447,"style":447},"import UIKit\n\nclass ViewController: UIViewController {\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \u002F\u002F 设置窗口背景颜色\n        view.backgroundColor = .systemPink\n        \u002F\u002F 添加文本\n        let label = UILabel()\n        label.text = \"Hello world!\"\n        label.textColor = .white\n        label.textAlignment = .center\n        label.frame = view.bounds\n        \u002F\u002F 添加到视图\n        view.addSubview(label)\n    }\n}\n",[241,698,699,705,709,722,726,742,752,757,767,772,787,804,814,824,834,840,856,861],{"__ignoreMap":447},[451,700,701,703],{"class":453,"line":454},[451,702,458],{"class":457},[451,704,462],{"class":461},[451,706,707],{"class":453,"line":465},[451,708,469],{"emptyLinePlaceholder":468},[451,710,711,713,715,717,720],{"class":453,"line":472},[451,712,476],{"class":475},[451,714,654],{"class":461},[451,716,483],{"class":482},[451,718,719],{"class":461}," UIViewController ",[451,721,496],{"class":482},[451,723,724],{"class":453,"line":499},[451,725,469],{"emptyLinePlaceholder":468},[451,727,728,731,734,737,740],{"class":453,"line":504},[451,729,730],{"class":475},"    override",[451,732,733],{"class":475}," func",[451,735,736],{"class":535}," viewDidLoad",[451,738,739],{"class":482},"()",[451,741,572],{"class":482},[451,743,744,747,750],{"class":453,"line":517},[451,745,746],{"class":489},"        super.",[451,748,749],{"class":535},"viewDidLoad",[451,751,657],{"class":482},[451,753,754],{"class":453,"line":522},[451,755,756],{"class":525},"        \u002F\u002F 设置窗口背景颜色\n",[451,758,759,762,764],{"class":453,"line":529},[451,760,761],{"class":489},"        view.backgroundColor ",[451,763,587],{"class":482},[451,765,766],{"class":489}," .systemPink\n",[451,768,769],{"class":453,"line":575},[451,770,771],{"class":525},"        \u002F\u002F 添加文本\n",[451,773,774,777,780,782,785],{"class":453,"line":616},[451,775,776],{"class":507},"        let",[451,778,779],{"class":489}," label ",[451,781,587],{"class":482},[451,783,784],{"class":535}," UILabel",[451,786,657],{"class":482},[451,788,789,792,794,797,801],{"class":453,"line":640},[451,790,791],{"class":489},"        label.text ",[451,793,587],{"class":482},[451,795,796],{"class":482}," \"",[451,798,800],{"class":799},"sfazB","Hello world!",[451,802,803],{"class":482},"\"\n",[451,805,806,809,811],{"class":453,"line":660},[451,807,808],{"class":489},"        label.textColor ",[451,810,587],{"class":482},[451,812,813],{"class":489}," .white\n",[451,815,816,819,821],{"class":453,"line":675},[451,817,818],{"class":489},"        label.textAlignment ",[451,820,587],{"class":482},[451,822,823],{"class":489}," .center\n",[451,825,826,829,831],{"class":453,"line":681},[451,827,828],{"class":489},"        label.frame ",[451,830,587],{"class":482},[451,832,833],{"class":489}," view.bounds\n",[451,835,837],{"class":453,"line":836},15,[451,838,839],{"class":525},"        \u002F\u002F 添加到视图\n",[451,841,843,846,849,851,854],{"class":453,"line":842},16,[451,844,845],{"class":489},"        view.",[451,847,848],{"class":535},"addSubview",[451,850,539],{"class":482},[451,852,853],{"class":489},"label",[451,855,637],{"class":482},[451,857,859],{"class":453,"line":858},17,[451,860,678],{"class":482},[451,862,864],{"class":453,"line":863},18,[451,865,684],{"class":482},[179,867,868,869,872],{},"后面如果要加约束，把 ",[241,870,871],{},"label.frame = view.bounds"," 换成 Auto Layout 或 SnapKit 就行。这一步只是验证启动链路通了。",[191,874,875],{"id":875},"运行项目",[179,877,878,879,882,883,404],{},"点 Xcode 左上角的运行按钮，或者按 ",[241,880,881],{},"Cmd + R","，模拟器就会起来。正常的话，你会看到粉色背景和白色的 ",[241,884,800],{},[179,886,887],{},[309,888],{"alt":875,"className":889,"src":890},[313],"https:\u002F\u002Ffilebed.chenyiren.top\u002Ffiles\u002F2026\u002F09\u002F5da85eb726a73981719c.jpg",[179,892,893],{},[309,894],{"alt":875,"className":895,"src":897},[896],"max-w-xs","https:\u002F\u002Ffilebed.chenyiren.top\u002Ffiles\u002F2026\u002F09\u002F407419ba6907a13a3964.jpg",[179,899,900,901,903,904,906],{},"至此，你已经成功创建了一个基于 UIKit 的 Swift 项目：没有 ",[241,902,347],{},"，窗口和根控制器都在 ",[241,905,274],{}," 里创建。",[191,908,910],{"id":909},"安装-cocoapods","安装 CocoaPods",[179,912,913,914,917],{},"如果你想用 CocoaPods 当包管理器，项目里其实就 4 步。注意：这里不教怎么装 ",[241,915,916],{},"pod"," 环境。",[208,919,920],{},[198,921,922,923,926],{},"打开终端，切到 iOS 项目根目录（也就是包含 ",[241,924,925],{},".xcodeproj"," 的那个文件夹）：",[442,928,932],{"className":929,"code":930,"language":931,"meta":447,"style":447},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","cd \u002F你的项目路径\u002F\n","bash",[241,933,934],{"__ignoreMap":447},[451,935,936,939],{"class":453,"line":454},[451,937,938],{"class":535},"cd",[451,940,941],{"class":799}," \u002F你的项目路径\u002F\n",[208,943,944],{"start":465},[198,945,946,947,950],{},"生成 ",[241,948,949],{},"Podfile","：",[442,952,954],{"className":929,"code":953,"language":931,"meta":447,"style":447},"pod init\n",[241,955,956],{"__ignoreMap":447},[451,957,958,960],{"class":453,"line":454},[451,959,916],{"class":461},[451,961,962],{"class":799}," init\n",[208,964,965],{"start":472},[198,966,967,968,970],{},"编辑 ",[241,969,949],{},"，按需引入第三方库：",[442,972,976],{"className":973,"code":974,"filename":949,"language":975,"meta":447,"style":447},"language-ruby shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","target 'YourProjectName' do\n  # 禁用自动包含框架，一般默认即可\n  use_frameworks!\n  # 引入你需要的第三方库，版本号按需改\n  pod 'SnapKit', '~> 5.7'\nend\n","ruby",[241,977,978,994,999,1004,1009,1033],{"__ignoreMap":447},[451,979,980,983,986,989,991],{"class":453,"line":454},[451,981,982],{"class":489},"target ",[451,984,985],{"class":482},"'",[451,987,988],{"class":799},"YourProjectName",[451,990,985],{"class":482},[451,992,993],{"class":457}," do\n",[451,995,996],{"class":453,"line":465},[451,997,998],{"class":525},"  # 禁用自动包含框架，一般默认即可\n",[451,1000,1001],{"class":453,"line":472},[451,1002,1003],{"class":489},"  use_frameworks!\n",[451,1005,1006],{"class":453,"line":499},[451,1007,1008],{"class":525},"  # 引入你需要的第三方库，版本号按需改\n",[451,1010,1011,1014,1016,1019,1021,1024,1027,1030],{"class":453,"line":504},[451,1012,1013],{"class":489},"  pod ",[451,1015,985],{"class":482},[451,1017,1018],{"class":799},"SnapKit",[451,1020,985],{"class":482},[451,1022,1023],{"class":482},",",[451,1025,1026],{"class":482}," '",[451,1028,1029],{"class":799},"~> 5.7",[451,1031,1032],{"class":482},"'\n",[451,1034,1035],{"class":453,"line":517},[451,1036,1037],{"class":457},"end\n",[208,1039,1040],{"start":499},[198,1041,1042],{},"保存后，在终端安装依赖：",[442,1044,1046],{"className":929,"code":1045,"language":931,"meta":447,"style":447},"pod install\n",[241,1047,1048],{"__ignoreMap":447},[451,1049,1050,1052],{"class":453,"line":454},[451,1051,916],{"class":461},[451,1053,1054],{"class":799}," install\n",[179,1056,1057,1058,1061,1062,1065,1066,404],{},"安装完成后，根目录会多出一个 ",[241,1059,1060],{},".xcworkspace","。切记：以后请双击打开 ",[241,1063,1064],{},"你的项目名称.xcworkspace"," 来开发，不要再打开原来的 ",[241,1067,925],{},[179,1069,1070,1071,1073,1074,950],{},"这一步并不难，但在 Xcode 16 里跑 ",[241,1072,916],{}," 脚本，经常会碰到沙盒拦截 ",[241,1075,1076],{},"rsync",[442,1078,1083],{"className":1079,"code":1081,"language":1082,"meta":447},[1080],"language-text","Sandbox: rsync deny(1) file-write-create\n...\u002FBuild\u002FProducts\u002FDebug-iphoneos\u002FYourApp.app\u002FFrameworks\u002FSome.framework\n","text",[241,1084,1081],{"__ignoreMap":447},[179,1086,1087,1088,1091,1092,1095,1096,1099,1100,1103,1104,404],{},"解决办法：打开 ",[186,1089,1090],{},"Build Settings","，搜索 ",[241,1093,1094],{},"sandbox","，把 ",[186,1097,1098],{},"Build Options"," 里的 ",[186,1101,1102],{},"User Script Sandboxing"," 改成 ",[186,1105,1106],{},"NO",[179,1108,1109],{},[309,1110],{"alt":910,"className":1111,"src":1112},[313],"https:\u002F\u002Ffilebed.chenyiren.top\u002Ffiles\u002F2026\u002F09\u002Ff62a0694ff46d99e1a82.jpg",[191,1114,1116],{"id":1115},"安装-swift-package","安装 Swift Package",[179,1118,1119],{},"不想折腾 CocoaPods，用 Xcode 自带的 Swift Package 就行。还是以 SnapKit 为例。同一个库不要两边各加一次。",[208,1121,1122,1127,1136],{},[198,1123,428,1124,1126],{},[241,1125,925],{},"（不用 workspace）",[198,1128,1129,1130,376,1133],{},"菜单栏选 ",[186,1131,1132],{},"File",[186,1134,1135],{},"Add Package Dependencies...",[198,1137,1138],{},"右上角贴仓库地址，例如：",[442,1140,1143],{"className":1141,"code":1142,"language":1082,"meta":447},[1080],"https:\u002F\u002Fgithub.com\u002FSnapKit\u002FSnapKit.git\n",[241,1144,1142],{"__ignoreMap":447},[208,1146,1147,1157],{"start":499},[198,1148,1149,1150,1153,1154],{},"依赖规则一般选 ",[186,1151,1152],{},"Up to Next Major Version","，点 ",[186,1155,1156],{},"Add Package",[198,1158,1159,1160],{},"确认加到当前 App target，再点 ",[186,1161,1156],{},[179,1163,1164,1165,1168,1169,1172],{},"加完之后，代码里 ",[241,1166,1167],{},"import SnapKit"," 就能用。根目录会多一个 ",[241,1170,1171],{},"Package.resolved","，用来锁定版本，建议一并提交。",[179,1174,1175,1176,1179,1180,1183],{},"也可以点项目根目录，切到 ",[186,1177,1178],{},"PACKAGE DEPENDENCIES","，点左下角 ",[186,1181,1182],{},"+","，效果一样。",[191,1185,1186],{"id":1186},"下一步",[195,1188,1189,1194,1201,1206],{},[198,1190,1191,1193],{},[402,1192,121],{"href":122},"：居中 Logo 或铺满屏幕",[198,1195,1196,1197,1200],{},"回到 ",[402,1198,1199],{"href":110},"iOS 分类"," 看同栏目其他笔记",[198,1202,1203,1205],{},[402,1204,126],{"href":127},"：根控制器换成导航控制器之后，用 Router 管 push、弹层和深层链接",[198,1207,1208,1209,1212],{},"用 Auto Layout 或 SnapKit 替换 ",[241,1210,1211],{},"frame","，避免旋转和不同屏宽时布局乱掉",[1214,1215,1216],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":447,"searchDepth":465,"depth":465,"links":1218},[1219,1220,1221,1222,1223,1224,1225,1226,1227],{"id":193,"depth":465,"text":193},{"id":206,"depth":465,"text":206},{"id":335,"depth":465,"text":336},{"id":425,"depth":465,"text":425},{"id":687,"depth":465,"text":687},{"id":875,"depth":465,"text":875},{"id":909,"depth":465,"text":910},{"id":1115,"depth":465,"text":1116},{"id":1186,"depth":465,"text":1186},"现在新建项目默认已经是 SwiftUI，但我还是习惯用 UIKit，所以把步骤记在这里。","md",[1231,1235,1239],{"label":1232,"icon":109,"to":1233,"target":1234},"UIKit 文档","https:\u002F\u002Fdeveloper.apple.com\u002Fdocumentation\u002Fuikit","_blank",{"label":1236,"icon":1237,"to":1238,"target":1234},"CocoaPods Guides","i-lucide-package","https:\u002F\u002Fguides.cocoapods.org",{"label":1240,"icon":1241,"to":1242,"target":1234},"Swift Package","i-simple-icons-swift","https:\u002F\u002Fdeveloper.apple.com\u002Fdocumentation\u002Fxcode\u002Fadding-package-dependencies-to-your-app",{"date":1244,"categories":1245,"tags":1247},"2026-06-03",[1246],"ios",[108,1248,284,1249],"UIKit","Xcode",{"icon":16},{"title":1252,"description":1253},"用 Xcode 创建纯代码 UIKit 项目","Xcode 16 默认 SwiftUI。把 Interface 设为 Storyboard，删除 Main.storyboard，在 SceneDelegate 里设置根控制器，得到纯代码 UIKit 工程。","o038Y--b0SlyVik6UYyftTTm-WfRWSfPmT6XiEWMaPI",[1256,1258],{"title":5,"path":7,"stem":11,"description":1257,"icon":6,"children":-1},"开发笔记、教程与随笔。",{"title":18,"path":19,"stem":20,"description":1259,"icon":21,"children":-1},"一款纯本地的密码保存应用。数据只写在当前设备上，不设账号、不上云、不收集使用数据。",1790767045638]