{
  "version": "https://jsonfeed.org/version/1", 
  "title": "Swift", 
  "description": "\u6765\u81ea Apple \u7684\u7c7b\u578b\u5b89\u5168\u7684\u7f16\u7a0b\u8bed\u8a00\u3002", 
  "home_page_url": "https://www.v2ex.com/go/swift", 
  "feed_url": "https://www.v2ex.com/feed/swift.json", 
  "icon": "https://cdn.v2ex.com/navatar/4c27/cea8/638_large.png?m=1661630260", 
  "favicon": "https://cdn.v2ex.com/navatar/4c27/cea8/638_normal.png?m=1661630260", 
  "items": [
    {
      "author": {
        "url": "https://www.v2ex.com/member/infyni", 
        "name": "infyni", 
        "avatar": "https://cdn.v2ex.com/gravatar/ab680cdf75f758f970bab3563a61625e?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/1164255", 
      "title": "\u5e94\u8be5\u600e\u4e48\u89e3\u8bfb swiftui \u7684\u5d29\u6e83\u62a5\u544a\uff1f", 
      "id": "https://www.v2ex.com/t/1164255", 
      "date_published": "2025-10-10T09:37:52+00:00", 
      "content_html": "<p>\u6211\u7684\u5e94\u7528\u4e2d\uff0c \u6709\u4e00\u4e2a\u7528\u6237\uff0c\u5b83\u6709\u4e09\u53f0\u7535\u8111\uff0c\u5728\u5176\u4e2d\u4e00\u53f0\u7535\u8111\u4e0a\uff0c\u8fd0\u884c\u6211\u7684\u5e94\u7528\uff0c\u603b\u662f\u5728\u5927\u6982 6 \u5206\u949f\u5de6\u53f3\u4e4b\u540e\uff0c\u5c31\u53d1\u751f\u5d29\u6e83\uff0c\u91cd\u542f\u3002\u5bf9\u65b9\u628a\u5d29\u6e83\u62a5\u544a\u53d1\u9001\u7ed9\u6211\u4e86\uff0c\u4f46\u662f\u6211\u5b9e\u5728\u770b\u4e0d\u51fa\u95ee\u9898\u5728\u54ea\u91cc\uff0c\u65e0\u6cd5\u5b9a\u4f4d\u5230\u4ee3\u7801\uff0c\u4e14\u5728\u6211\u7684\u7535\u8111\u4e0a\u4e5f\u65e0\u6cd5\u590d\u73b0\uff0c\u5b9e\u5728\u4e0d\u77e5\u9053\u600e\u4e48\u53bb\u4fee\u590d\u5b83\u3002</p>\n<p>\u8bf7\u5404\u4f4d\u5e2e\u5fd9\u770b\u770b\uff0c \u6709\u4ec0\u4e48\u529e\u6cd5\u53ef\u4ee5\u6765\u89e3\u51b3\u5e76\u5b9a\u4f4d bug \uff1f</p>\n<p><a href=\"https://gist.github.com/yeelone/d033d0857e5d974c03ae3043666e4b40\" rel=\"nofollow\">https://gist.github.com/yeelone/d033d0857e5d974c03ae3043666e4b40</a></p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/Lambert2022", 
        "name": "Lambert2022", 
        "avatar": "https://cdn.v2ex.com/avatar/94fe/77db/581924_large.png?m=1751208551"
      }, 
      "url": "https://www.v2ex.com/t/1141821", 
      "title": "FoundationModels \u6846\u67b6\u5b9e\u8df5", 
      "id": "https://www.v2ex.com/t/1141821", 
      "date_published": "2025-06-29T14:44:36+00:00", 
      "content_html": "<p>\u5468\u672b\u4f7f\u7528 TCA + SharingGRDB \u64b8\u4e86\u4e00\u4e2a\u7b80\u5355\u7684 FoundationModels \u804a\u5929\u5e94\u7528\uff1b\u76ee\u524d\u53ea\u5b8c\u6210\u4e86\u57fa\u672c\u529f\u80fd\n<a href=\"https://imgur.com/hBFb7BF\" rel=\"nofollow\">https://imgur.com/hBFb7BF</a>\n\u4ee3\u7801: <a href=\"https://github.com/Anderson-Hyl/FoundationModelsChat\" rel=\"nofollow\">https://github.com/Anderson-Hyl/FoundationModelsChat</a></p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/Lambert2022", 
        "name": "Lambert2022", 
        "avatar": "https://cdn.v2ex.com/avatar/94fe/77db/581924_large.png?m=1751208551"
      }, 
      "url": "https://www.v2ex.com/t/1138615", 
      "title": "Swift DocC \u6784\u5efa\u7684\u535a\u5ba2", 
      "id": "https://www.v2ex.com/t/1138615", 
      "date_published": "2025-06-14T13:28:09+00:00", 
      "content_html": "\u770b\u5230\u7f51\u7edc\u4e0a\u6709\u5f88\u591a DocC \u6784\u5efa\u7684\u7f51\u9875\uff0c\u60f3\u7740\u80fd\u4e0d\u80fd\u7528\u5b83\u641e\u4e2a\u7b80\u6613\u7684\u535a\u5ba2\u3002\u82f9\u679c\u6587\u6863\u98ce\u683c\u7684\u535a\u5ba2\uff0c\u8fd8\u633a\u597d\u770b<br /><a target=\"_blank\" href=\"https://anderson-hyl.github.io/Anderson-s-Blog/\" rel=\"nofollow noopener\">https://anderson-hyl.github.io/Anderson-s-Blog/</a>"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/wsseo", 
        "name": "wsseo", 
        "avatar": "https://cdn.v2ex.com/gravatar/76d2c2c844d4bfb2b4fbec4d2151b02f?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/1136602", 
      "title": "Swift server \u8981\u652f\u68f1\u8d77\u6765\u4e86", 
      "id": "https://www.v2ex.com/t/1136602", 
      "date_published": "2025-06-05T08:04:43+00:00", 
      "content_html": "\u82f9\u679c\u5185\u90e8\u56e2\u961f\u51b3\u5b9a\u653e\u5f03 java,\u4f7f\u7528\u66f4\u9ad8\u6548\u7684 swift \u91cd\u5199\u5173\u952e\u670d\u52a1\u3002\u51cf\u5c11\u5185\u5b58\u5360\u7528\uff0c\u964d\u4f4e\u8d1f\u8f7d\uff0c\u63d0\u9ad8\u541e\u5410\u91cf\u3002"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/webashe11", 
        "name": "webashe11", 
        "avatar": "https://cdn.v2ex.com/avatar/ed81/e867/546472_large.png?m=1761119679"
      }, 
      "url": "https://www.v2ex.com/t/1135989", 
      "date_modified": "2025-06-06T14:29:53+00:00", 
      "content_html": "\u5982\u9898<br /><br />1. arm \u3001intel \u5982\u4f55\u505a\u7cfb\u7edf\u533a\u5206<br />2. \u4e00\u5b9a\u9700\u8981\u672c\u5730 brew install mysql \u4e48", 
      "date_published": "2025-06-03T03:51:15+00:00", 
      "title": "\u6c42\u95ee\u8d34\uff0c\u5982\u679c\u5728 swiftUI \u4e2d\u63a5\u5165 MySQL C client", 
      "id": "https://www.v2ex.com/t/1135989"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/main1234", 
        "name": "main1234", 
        "avatar": "https://cdn.v2ex.com/avatar/46cb/5f2c/665345_large.png?m=1747500638"
      }, 
      "url": "https://www.v2ex.com/t/1132529", 
      "date_modified": "2025-05-20T00:53:32+00:00", 
      "content_html": "<p>\u4f7f\u7528\u7684 Xcode 16.2 \u3001swift 6.0.3</p>\n<p>\u4ee3\u7801\u5982\u4e0b</p>\n<pre><code class=\"language-swift\">import Foundation\n\nDispatchQueue.global().async {\n    // \u8017\u65f6\u64cd\u4f5c\uff08\u5982\u7f51\u7edc\u8bf7\u6c42\u3001\u6587\u4ef6\u5904\u7406\uff09\n    let data = downloadData()\n    \n    DispatchQueue.main.async {\n        updateUI(with: data)\n    }\n}\n\nfunc downloadData() -&gt; String{\n    sleep(2)\n    return \"a\"\n}\n\nfunc updateUI(with: Any) {\n    print(\"updateUI\")\n}\n\nsleep(10)\n\n</code></pre>\n<p>\u4e3a\u4ec0\u4e48\u6211\u65e0\u6cd5\u8f93\u51fa updateUI</p>\n<p>\u6211\u5e94\u8be5\u5982\u4f55\u5728\u5207\u6362\u5230\u4e3b\u7ebf\u7a0b\u65f6\u5019\uff0c\u8ba9\u4e3b\u7ebf\u7a0b\u8f93\u51fa updateUI</p>\n", 
      "date_published": "2025-05-18T05:45:38+00:00", 
      "title": "Swift \u840c\u65b0\uff0c DispatchQueue \u7684\u4e00\u4e2a\u95ee\u9898", 
      "id": "https://www.v2ex.com/t/1132529"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/Xheldon", 
        "name": "Xheldon", 
        "avatar": "https://cdn.v2ex.com/avatar/9d56/9ce5/164398_large.png?m=1767594364"
      }, 
      "url": "https://www.v2ex.com/t/1123864", 
      "title": "\u5206\u4eab\u4e00\u4e0b\u4e00\u4e2a Web \u524d\u7aef\u521a\u5b66\u4e60 Swift \u65f6\u5019\u7684\u5fc3\u5f97\u535a\u6587", 
      "id": "https://www.v2ex.com/t/1123864", 
      "date_published": "2025-04-08T01:38:57+00:00", 
      "content_html": "\u5730\u5740\u662f\uff1a<br /><br /><a target=\"_blank\" href=\"https://www.xheldon.com/tech/app-dev-journey-swift\" rel=\"nofollow noopener\">https://www.xheldon.com/tech/app-dev-journey-swift</a><br /><br />\u662f\u6211\u7684\u4e2a\u4eba\u535a\u5ba2\uff0c\u6ca1\u5174\u8da3\u7684\u4e0d\u7528\u70b9\u8fdb\u53bb\u4e86\uff0c\u514d\u5f97\u8bf4\u6211\u6302\u5916\u94fe\u5f15\u6d41\u3002<br /><br />\u4e3b\u8981\u5185\u5bb9\u662f\u672c\u4eba\u4f5c\u4e3a 9 \u5e74 Web \u524d\u7aef\u521a\u63a5\u89e6 Swift \u7684\u65f6\u5019\u8ddf TS \u5bf9\u6bd4\u7684\u5dee\u5f02\u70b9\u603b\u7ed3\uff0c\u5f53\u7136\u53f8\u7a7a\u89c1\u60ef\u7684\u5dee\u5f02\u5c31\u6ca1\u5199\uff0c\u6bd4\u5982 TS \u4e2d\u6ca1\u6709\u6570\u5b57\u7c7b\u578b Int \u548c Double \u8fd9\u79cd\u7684\u3002"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/MrKrabs", 
        "name": "MrKrabs", 
        "avatar": "https://cdn.v2ex.com/gravatar/4922cbf6f0433c2c9150acf029f8ef74?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/1120436", 
      "title": "5 \u5206\u949f\u7528 Swift \u5199\u4e2a ripripgrep", 
      "id": "https://www.v2ex.com/t/1120436", 
      "date_published": "2025-03-23T05:58:53+00:00", 
      "content_html": "<p>\u4f60\u522b\u7ba1\u4ec0\u4e48 NFC \uff0cNFD \uff0c\u54b1\u53ea\u662f\u60f3\u641c\u51fa\u65e5\u8bed\u5462</p>\n<pre><code class=\"language-swift\">import Foundation\nimport ArgumentParser\n\n@main\nstruct Ripripgrep: ParsableCommand {\n\n  @Option(name: .shortAndLong)\n  var patterns: [String]\n\n  @Argument(help: \"use stdin if no args\")\n  var files: [String] = []\n\n  func validate() throws {\n    if patterns.isEmpty {\n      fatalError(\"no patterns!\")\n    }\n  }\n\n  struct Worker {\n    var line: UnsafeMutablePointer&lt;CChar&gt;?\n    var linecap = 0\n    let patterns: [Regex&lt;AnyRegexOutput&gt;]\n\n    mutating func start(stream: UnsafeMutablePointer&lt;FILE&gt;) {\n      while case let linelen = getline(&amp;line, &amp;linecap, stream),\n            linelen &gt; 0 {\n        let line = String(decoding: UnsafeRawBufferPointer(start: line!, count: linelen-1), as: UTF8.self)\n        if patterns.allSatisfy({ line.contains($0) }) {\n          print(line)\n        }\n      }\n    }\n  }\n\n  func run() throws {\n\n    var worker = Worker(patterns: try patterns.map { try Regex($0).ignoresCase() })\n\n    if files.isEmpty {\n      // use stdin\n      worker.start(stream: stdin)\n    } else {\n      for file in files {\n        let stream = fopen(file, \"rb\")!\n        defer { fclose(stream) }\n        worker.start(stream: stream)\n      }\n    }\n  }\n\n}\n\n</code></pre>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/f1197199424", 
        "name": "f1197199424", 
        "avatar": "https://cdn.v2ex.com/avatar/829a/4ec0/681881_large.png?m=1763082813"
      }, 
      "url": "https://www.v2ex.com/t/1109153", 
      "date_modified": "2025-02-07T10:50:05+00:00", 
      "content_html": "\u5982\u9898\uff1a\u6709\u6ca1\u6709 swift \u5927\u4f6c\u544a\u77e5\u4e00\u4e0b\uff0cMacOS \u4e1a\u5185\u5f00\u53d1\u5982\u679c\u9700\u8981\u64cd\u4f5c plist \u4e00\u822c\u7528\u4ec0\u4e48\u5e93\u554a\uff1f<br />\u6211\u6709\u4e00\u5b9a\u7684\u5f00\u53d1\u7ecf\u9a8c \u4f46\u662f\u65e0 IOS \u6216\u8005 MacOS \u5f00\u53d1\u7ecf\u9a8c\u3002<br />\u6211\u5c1d\u8bd5\u4f7f\u7528 PropertyListSerialization \u6765\u64cd\u4f5c\uff0c\u4ed6\u662f\u7cfb\u7edf\u5185\u7f6e\uff0c\u4e0d\u9700\u8981\u5f15\u5165\u989d\u5916\u7684\u5f00\u53d1\u5305\u3002\u4f46\u662f\u5e26\u6765\u7684\u95ee\u9898\u4e5f\u5c31\u5f88\u9ebb\u70e6\u3002\u6bd4\u5982\u6211\u901a\u8fc7\u547d\u4ee4\u884c\u6267\u884c\uff1a<br />```<br />/usr/libexec/PlistBuddy -c \"Add :NowDays:1:Children:0:Checked dict\" xx.plist<br />```<br />\u5c31\u5f88\u65b9\u4fbf\uff0c\u4f46\u662f\u4f7f\u7528 PropertyListSerialization \u5c31\u7279\u522b\u96be\u53d7\u3002<br /><br />\u6240\u4ee5\u8bf7\u6559\u4e0b\u5404\u4f4d IOS \u6216\u8005 MacOS \u5927\u4f6c\uff0c\u6709\u65e0\u7c7b\u4f3c\u7684\u7ecf\u9a8c\uff0c\u7ed9\u5c0f\u5f1f\u4e00\u70b9\u542f\u53d1\u6216\u8005\u53c2\u8003\u3002\u8c22\u8c22\ud83d\ude4f\u3002", 
      "date_published": "2025-02-05T09:54:51+00:00", 
      "title": "Swift \u64cd\u4f5c plist \u6587\u4ef6", 
      "id": "https://www.v2ex.com/t/1109153"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/Lambert2022", 
        "name": "Lambert2022", 
        "avatar": "https://cdn.v2ex.com/avatar/94fe/77db/581924_large.png?m=1751208551"
      }, 
      "url": "https://www.v2ex.com/t/1104338", 
      "title": "\u4f7f\u7528 SwiftUI + TCA \u91cd\u6784 Instagram Clone\uff1a\u4ece Flutter \u5230 SwiftUI \u7684\u8fc1\u79fb\u5b9e\u8df5", 
      "id": "https://www.v2ex.com/t/1104338", 
      "date_published": "2025-01-11T05:21:03+00:00", 
      "content_html": "<p>\u57fa\u4e8e\u73b0\u6709 Flutter Instagram Clone \u9879\u76ee\u8fdb\u884c SwiftUI \u91cd\u6784\nSwiftUI + TCA + PowerSync + Supabase\n\u79bb\u7ebf\u4f18\u5148\u3001\u5b9e\u65f6\u540c\u6b65\n<a href=\"https://github.com/AtmanChen/instagram-clone.git\" rel=\"nofollow\">Github</a></p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/wendstation", 
        "name": "wendstation", 
        "avatar": "https://cdn.v2ex.com/gravatar/475779cd716e669c34bee4539307a53a?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/1102959", 
      "title": "\u6fc0\u53d1\u7f16\u7a0b\u6fc0\u60c5\uff0c\u8f7b\u677e\u638c\u63e1 Swift SwiftUI", 
      "id": "https://www.v2ex.com/t/1102959", 
      "date_published": "2025-01-06T08:47:59+00:00", 
      "content_html": "<p>\u6700\u8fd1\u5f00\u53d1\u4e86\u4e00\u4e2a APP \uff0c\u6838\u5fc3\u529f\u80fd\u662f\uff1a</p>\n<ul>\n<li>\u672c\u5730\u5316\uff1a\u7a81\u7834\u8bed\u8a00\u969c\u788d\uff0c\u7528\u6bcd\u8bed\u67e5\u770b Apple \u6587\u6863\uff0c\u652f\u6301 70+\u79cd\u8bed\u8a00\u3002</li>\n<li>\n\u6613\u7528\uff1a\u5feb\u901f\u5b9a\u4f4d\u9700\u8981\u7684\u6587\u6863\u3002<ul>\n<li>\u641c\u7d22\uff1a\u7528\u6bcd\u8bed\u641c\u7d22\u5b9a\u4f4d\u6587\u6863\u3002</li>\n<li>\u8fc7\u6ee4\uff1a\u591a\u79cd\u7b5b\u9009\u673a\u5236\uff0c\u5feb\u901f\u7b5b\u9009\u3002</li>\n</ul>\n</li>\n<li>\u6613\u61c2\uff1a\u56fe\u6587\u6559\u7a0b\uff0c\u66f4\u61c2\u600e\u4e48\u4f7f\u7528\u5404\u79cd API \u3002</li>\n</ul>\n<hr/>\n<ol>\n<li>\u591a\u8bed\u8a00\u652f\u6301\uff1a\u8986\u76d6\u5168\u7403\u4e3b\u8981\u8bed\u8a00\uff0c\u6ee1\u8db3\u4e0d\u540c\u7528\u6237\u7684\u9700\u6c42\u3002(70+ \u8bed\u8a00)</li>\n<li>\u9ad8\u6548\u7b5b\u9009\u4e0e\u5b9a\u4f4d\uff1a\u6839\u636e\u6a21\u5757\u3001\u6587\u6863\u7c7b\u578b\u3001API \u72b6\u6001\u3001\u64cd\u4f5c\u7cfb\u7edf\u3001\u4ee3\u7801\u7247\u6bb5\u5feb\u901f\u627e\u5230\u6240\u9700\u6587\u6863\u3002</li>\n<li>\u672c\u5730\u5316\u641c\u7d22\uff1a\u7528\u60a8\u7684\u8bed\u8a00\u641c\u7d22\uff0c\u8ba9\u4fe1\u606f\u83b7\u53d6\u66f4\u76f4\u63a5\u3002</li>\n<li>\u79c1\u4eba\u5b9a\u5236\u6559\u7a0b\uff1a\u63d0\u4f9b\u4ece\u96f6\u5f00\u59cb\u7684 Swift \u5b66\u4e60\u8def\u5f84\uff0c\u9002\u5408\u6240\u6709\u6c34\u5e73\u7684\u5f00\u53d1\u8005\u3002</li>\n<li>\u6587\u6863\u5bfc\u51fa: \u5c06\u6587\u6863\u5bfc\u51fa\u4e3a Markdown \u683c\u5f0f\uff0c\u8f7b\u677e\u5206\u4eab\u3002</li>\n<li>\u7b14\u8bb0\u529f\u80fd: \u652f\u6301 iCloud \u7b14\u8bb0\u540c\u6b65\uff0c\u786e\u4fdd\u60a8\u7684\u7b14\u8bb0\u5b89\u5168\u4e14\u79c1\u5bc6\u3002</li>\n</ol>\n<p>\u6211\u4eec\u7684\u76ee\u6807\u662f\u7b80\u5316\u60a8\u7684\u5b66\u4e60\u8fc7\u7a0b\uff0c\u8ba9 Swift \u5f00\u53d1\u53d8\u5f97\u524d\u6240\u672a\u6709\u7684\u7b80\u5355\u3002</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/zhbhun", 
        "name": "zhbhun", 
        "avatar": "https://cdn.v2ex.com/gravatar/916b4b3d4e6263a4ebd7af9b33e9d770?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/1101104", 
      "date_modified": "2024-12-29T14:48:23+00:00", 
      "content_html": "<p><a href=\"https://github.com/zhbhun/ListKit\" rel=\"nofollow\">https://github.com/zhbhun/ListKit</a></p>\n<p>\u672c\u8eab\u662f\u4e2a\u524d\u7aef\u5f00\u53d1\uff0c\u6700\u8fd1\u4e00\u4e2a\u6708\u56e0\u4e1a\u52a1\u9700\u8981\u5728\u4f7f\u7528 Swift \u548c UIKit \u5f00\u53d1 iOS \u5e94\u7528\u3002\u4f46\u662f\u65e7\u9879\u76ee\u4e2d\u5404\u79cd\u4ee3\u7406\u548c\u534f\u8bae\uff0c\u90fd\u8ba9\u4ee3\u7801\u8df3\u6765\u8df3\u51fa\uff0c\u53e6\u5916\u9879\u76ee\u4e2d\u6ca1\u6709\u89c4\u8303\u7684 MVVM \u5f00\u53d1\u65b9\u5f0f\uff0c\u8ba9\u72b6\u6001\u6d41\u548c UI \u547d\u4ee4\u5f0f\u66f4\u65b0\uff0c\u50cf\u8718\u86db\u7f51\u4e00\u6837\u5404\u79cd\u4e71\u95ef\uff0c\u770b\u5f97\u6211\u8111\u58f3\u75bc\uff0c\u6240\u4ee5\u52a8\u624b\u505a\u4e86\u4e2a ListKit \u9879\u76ee\uff0c\u6c42\u5404\u4f4d\u5927\u4f6c\u6307\u70b9\u4e0b\uff0c\u8fd9\u6837\u5199\u662f\u4e0d\u662f\u6709\u4ec0\u4e48\u95ee\u9898\uff0c\u6216\u8005\u6709\u4ec0\u4e48\u66f4\u597d\u7684\u5efa\u8bae\uff1f</p>\n<p>ps\uff1a\u76ee\u524d\u6211\u5728\u4f7f\u7528\u58f0\u660e\u5f0f\u7684\u65b9\u5f0f\u5199\u590d\u6742\u914d\u7f6e\u7684\u65f6\u5019\uff0c\u4f1a\u9047\u5230 Swift \u63d0\u793a\u7f16\u8bd1\u5668\u65e0\u6cd5\u89e3\u6790\uff0c\u8ba9\u6211\u62c6\u5206\u8868\u8fbe\u5f0f\u7684\u95ee\u9898\ud83d\ude2d\uff01</p>\n", 
      "date_published": "2024-12-29T14:47:59+00:00", 
      "title": "\u5206\u4eab\u4e2a\u57fa\u4e8e UICollectionView \u5c01\u88c5\u7684\u6570\u636e\u9a71\u52a8\u548c\u58f0\u660e\u5f0f\u7ec4\u4ef6\u5e93 ListKit", 
      "id": "https://www.v2ex.com/t/1101104"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/blackguester", 
        "name": "blackguester", 
        "avatar": "https://cdn.v2ex.com/avatar/5256/2b05/600588_large.png?m=1732896283"
      }, 
      "url": "https://www.v2ex.com/t/1093851", 
      "title": "\u95ee\u4e00\u4e2a\u5173\u4e8e CALayer \u7684\u8d44\u6e90\u91ca\u653e\u95ee\u9898", 
      "id": "https://www.v2ex.com/t/1093851", 
      "date_published": "2024-11-29T16:22:32+00:00", 
      "content_html": "<p>\u5047\u8bbe\u4e00\u4e2a CALayer \u4f1a\u751f\u6210\u4e00\u4e9b\u5b50 layers \uff0c\u91cd\u7f6e\u7684\u65f6\u5019\uff0c\u5404\u4f4d\u662f\u7528<code>removeFromSuperlayer</code>\uff0c\u8fd8\u662f\u76f4\u63a5<code>sublayers = []</code>?</p>\n<p></p>\n<pre><code>class Mycalayer: CALayer {\n\n    func update () {\n\n        // insert some Sublayers here\n        .....\n    }\n\n    func refresh () {\n\n        // reset all sublayers\n        self.sublayers?.forEach { layer in\n            layer.removeFromSuperlayer()\n        }\n\n        // OR Just\n        self.sublayers = []\n\n    }\n\n}\n</code></pre>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/Livid", 
        "name": "Livid", 
        "avatar": "https://cdn.v2ex.com/avatar/c4ca/4238/1_large.png?m=1775624785"
      }, 
      "url": "https://www.v2ex.com/t/1077170", 
      "date_modified": "2024-09-30T09:42:55+00:00", 
      "content_html": "\u4e4b\u524d\u7684\u51e0\u4e2a macOS \u7248\u672c\u4e0a\u90fd\u6ca1\u6709\u8fd9\u4e2a\u95ee\u9898\u3002<br /><br /><video muted=\"\" preload=\"\" style=\"width: 100%; aspect-ratio: 16/9; vertical-align: bottom;\" playsinline=\"\" controls><source src=\"https://k51qzi5uqu5dg8wwt3hx6y9ek605hbkz5big2hv2fr7oo10j90ys0fvhld7eyo.eth.sucks/D13D6127-82C0-4100-B5AF-2B098E3512D2/Screen%20Recording%202024-09-30%20at%202.19.38%E2%80%AFAM.mov\" type=\"video/mp4\"></video>", 
      "date_published": "2024-09-30T09:40:36+00:00", 
      "title": "SwiftUI \u7684 TextEditor \u5728 macOS Sequoia 15.0 \u4e0a\u8f93\u5165\u4e2d\u6587\u65f6\u53c8\u4f1a\u8fd9\u6837\u4e00\u8df3\u4e00\u8df3\u7684\u4e86", 
      "id": "https://www.v2ex.com/t/1077170"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/jiangzm", 
        "name": "jiangzm", 
        "avatar": "https://cdn.v2ex.com/avatar/1421/149f/434602_large.png?m=1702373761"
      }, 
      "url": "https://www.v2ex.com/t/1076938", 
      "date_modified": "2024-09-29T14:31:42+00:00", 
      "content_html": "<p>\u56e0\u4e3a\u8981\u5199\u539f\u751f\u63d2\u4ef6\uff0cswift \u521a\u63a5\u89e6\uff0c\u8bed\u6cd5\u6bd4 objc \u597d\u770b\u591a\u4e86\u3002</p>\n<p>\u5728\u5f00\u53d1\u76f8\u673a\u7ec4\u4ef6\u65f6\u9047\u5230\u4e00\u4e2a\u95ee\u9898\uff0cAVCapturePhotoCaptureDelegate \u5951\u7ea6\u7528\u81ea\u5b9a\u4e49 UIView/UIViewController \u5b9e\u73b0\u6ca1\u95ee\u9898\uff0c \u6362\u6210\u72ec\u7acb\u7684\u7c7b\u5b9e\u73b0\u5c31\u56de\u8c03\u4e0d\u4e86\uff0c\u4e0d\u662f\u4ec0\u4e48\u539f\u56e0\u3002</p>\n<p>\u4e0a\u4ee3\u7801\uff1a</p>\n<h4>TakePhotoDelegate.swift</h4>\n<pre><code class=\"language-swift\">import Foundation\nimport AVFoundation\nimport UIKit\n\npublic typealias TakePhotoCallback = ((String, String) -&gt; Void)?;\n\nclass TakePhotoWithCompletion : NSObject, AVCapturePhotoCaptureDelegate {\n\n    // ...\n    var completion: TakePhotoCallback;\n    \n    init(callback: TakePhotoCallback) {\n\n        self.completion = callback;\n        super.init();\n    }\n\n    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {\n    \n        // todo sth\n    \n        self.completion!(\"{file path}\", \"{error}\");\n        \n    }\n}\n\n\n</code></pre>\n<h4>CameraxView.swift</h4>\n<pre><code class=\"language-swift\">import AVFoundation\nimport UIKit\n\nclass CameraxView: UIView {\n\n    // ...\n\n    @objc\n    func takePhoto(options: Dictionary&lt;String, String&gt;, completion: TakePhotoCallback) {\n        \n        let photoSettings = AVCapturePhotoSettings.init(format:[AVVideoCodecKey:AVVideoCodecType.jpeg])\n        let delegate = TakePhotoWithCompletion.init(callback: completion)\n        \n        imageOutPut?.capturePhoto(with:photoSettings, delegate: delegate)\n\n    }\n\n  // ...\n}\n</code></pre>\n<h3>\u70b9\u51fb\u62cd\u7167\u6309\u94ae\u80fd\u542c\u5230\u5feb\u95e8\u58f0\uff0c\u4f46\u662f photoOutput \u6ca1\u6709\u56de\u8c03</h3>\n<h3>\u5982\u679c\u6362\u6210\u5982\u4e0b\u81ea\u5b9a\u4e49 UIView \u5b9e\u73b0 AVCapturePhotoCaptureDelegate \u6ca1\u6709\u95ee\u9898\uff0c\u80fd\u6b63\u5e38\u56de\u8c03</h3>\n<pre><code class=\"language-swift\">import AVFoundation\nimport UIKit\n\nclass CameraxView: UIView, AVCapturePhotoCaptureDelegate {\n\n    // ...\n    var completion: TakePhotoCallback = nil;\n\n    @objc\n    func takePhoto(options: Dictionary&lt;String, String&gt;) {\n        \n        let photoSettings = AVCapturePhotoSettings.init(format:[AVVideoCodecKey:AVVideoCodecType.jpeg])\n\n        self.completion = completion\n        \n        imageOutPut?.capturePhoto(with:photoSettings, delegate: self)\n\n    }\n\n    @objc\n    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {\n    \n        // todo sth\n    \n        self.completion!(\"{file path}\", \"{error}\");\n        \n    }\n\n    // ...\n\n}\n\n</code></pre>\n<h3>\u6709\u8fd9\u4e2a\u5dee\u5f02\u7684\u539f\u56e0\u662f\u56e0\u4e3a\u7cfb\u7edf API \u7684\u9650\u5236\u5417\u8fd8\u662f swift \u8bed\u8a00\u5c42\u9762\u95ee\u9898\uff0c  \u5982\u679c takePhoto \u65b9\u6cd5\u5e0c\u671b\u4f20\u95ed\u5305\u53c2\u6570\u56de\u8c03\u62cd\u7167\u7ed3\u679c\uff0c\u6b63\u786e\u5e94\u8be5\u600e\u4e48\u5199\u3002</h3>\n<h3>\uff08\u56de\u8c03\u53c2\u6570\u8d4b\u503c\u7ed9\u5b9e\u4f8b\u5bf9\u8c61, \u4e2a\u4eba\u611f\u89c9\u662f\u4e2a\u5f88\u5947\u602a\u7684\u505a\u6cd5\uff09</h3>\n", 
      "date_published": "2024-09-29T14:25:35+00:00", 
      "title": "Swift \u4e2d\u7cfb\u7edf API delegate \u53c2\u6570\u4e00\u5b9a\u8981\u5728\u5f53\u524d\u7c7b\u5b9e\u73b0\u4f20 self \u5417", 
      "id": "https://www.v2ex.com/t/1076938"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/happydoze", 
        "name": "happydoze", 
        "avatar": "https://cdn.v2ex.com/avatar/a40f/2a37/37426_large.png?m=1726802885"
      }, 
      "url": "https://www.v2ex.com/t/1074320", 
      "title": "ScreenCaptureKit \u91cc\u9762\u7684 SCStreamOutput \u6ca1\u6709\u88ab\u987a\u5229\u89e6\u53d1\uff0c\u662f\u90a3\u4e2a\u6b65\u9aa4\u9519\u4e86\uff0c\u6c42\u89e3\u60d1", 
      "id": "https://www.v2ex.com/t/1074320", 
      "date_published": "2024-09-20T03:33:03+00:00", 
      "content_html": "<p>\u4ee3\u7801\u5982\u4e0b\uff1a</p>\n<pre><code class=\"language-swift\">import SwiftUI\nimport ScreenCaptureKit\n\n\n\n\nstruct ContentView: View {\n    @State private var showingScreenshotAlert = false\n    @State private var screenshotRect = CGRect(x: 100, y: 100, width: 400, height: 300) // \u793a\u4f8b\u533a\u57df\n    @State private var cc = \"\u622a\u56fe 1\"\n\n    var body: some View {\n        VStack {\n            Text(\"\u70b9\u51fb\u4e0b\u65b9\u6309\u94ae\u8fdb\u884c\u622a\u56fe\")\n                .padding()\n\n            Button(action: takeScreenshot) {\n                Text(cc)\n                    .padding()\n                    .background(Color.blue)\n                    .foregroundColor(.white)\n                    .cornerRadius(8)\n            }\n        }\n        .alert(isPresented: $showingScreenshotAlert) {\n            Alert(title: Text(\"\u622a\u56fe\u5b8c\u6210\"), message: Text(\"\u622a\u56fe\u5df2\u4fdd\u5b58\u81f3\u684c\u9762\"), dismissButton: .default(Text(\"\u786e\u5b9a\")))\n        }\n    }\n\n    class MyStreamOutput: NSObject, SCStreamOutput {\n        var onCaptureCompletion: (() -&gt; Void)?  // \u95ed\u5305\uff0c\u7528\u4e8e\u901a\u77e5\u622a\u56fe\u5b8c\u6210\n        func stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of type: SCStreamOutputType) {\n            // \u6bcf\u5f53\u6355\u83b7\u5230\u65b0\u7684\u6837\u672c\u5e27\u65f6\u6253\u5370\u6d88\u606f\n            print(\"Captured a new frame of type\")\n            onCaptureCompletion?()// \u8c03\u7528\u95ed\u5305\u901a\u77e5\u622a\u56fe\u5b8c\u6210\n        }\n    }\n    \n    func takeScreenshot() {\n        cc = \"\u5728\u622a\u56fe 1...\"\n        showingScreenshotAlert = true\n\n        SCShareableContent.getWithCompletionHandler { (content, error) in\n            if let error = error {\n                print(\"Error: \\(error)\")\n            } else if let content = content {\n                print(\"Displays: \\(content.displays)\")\n                print(\"Displays: \\(content.displays[0])\")\n                print(\"Displays: \\(content.displays[0].width)\")\n                print(\"Displays: \\(content.displays[0].height)\")\n                print(\"Windows:\\(content.windows[23])\")\n                print(\"Windows ID:\\(content.windows[23].windowID)\")\n                print(\"Windows Count:\\(content.windows.count)\")\n\n                // MARK: - \u521b\u5efa\n                // \u521b\u5efa\u4e00\u4e2a\u8fc7\u6ee4\u5668\u4ee5\u6355\u83b7\u6574\u4e2a\u5c4f\u5e55\n                let filter1 = SCContentFilter(display: content.displays[0], excludingWindows: [])\n                let config1 = SCStreamConfiguration()\n                let stream1 = SCStream(filter: filter1, configuration: config1, delegate: nil)\n                \n                \n                // \u5b9e\u4f8b\u5316\u6211\u4eec\u7684\u8f93\u51fa\u5904\u7406\u7c7b\n                let streamOutput = MyStreamOutput()\n                // \u5b9a\u4e49\u622a\u56fe\u5b8c\u6210\u65f6\u7684\u52a8\u4f5c\n                streamOutput.onCaptureCompletion = {\n                    DispatchQueue.main.async {\n                        cc = \"\u622a\u56fe\u5b8c\u6210\u4e86\"\n                        print(\"-----------\")\n                    }\n                }\n                // \u6dfb\u52a0\u8f93\u51fa\n                do {\n                    try stream1.addStreamOutput(streamOutput, type: .screen, sampleHandlerQueue: DispatchQueue.main)\n                    print(\"\u6d41\u8f93\u51fa\u5df2\u6210\u529f\u6dfb\u52a0\")\n                } catch {\n                    print(\"\u6dfb\u52a0\u6d41\u8f93\u51fa\u65f6\u51fa\u9519: \\(error)\")\n                }\n                stream1.startCapture { error in\n                    if let error = error {\n                        print(\"Failed to start capture: \\(error)\")\n                    } else {\n                        print(\"Capture started successfully!\")\n                    }\n                }\n            }\n        }\n        \n    }\n    \n}\n\n</code></pre>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/Livid", 
        "name": "Livid", 
        "avatar": "https://cdn.v2ex.com/avatar/c4ca/4238/1_large.png?m=1775624785"
      }, 
      "url": "https://www.v2ex.com/t/1073401", 
      "title": "\u4f3c\u4e4e SwiftUI app \u5728 macOS 15 \u4e0a\u542f\u52a8\u901f\u5ea6\u53d8\u5feb\u5f88\u591a\uff1f", 
      "id": "https://www.v2ex.com/t/1073401", 
      "date_published": "2024-09-16T20:53:06+00:00", 
      "content_html": "<p>\u73b0\u5728\u53ea\u9700\u8981\u5728 Dock \u4e0a\u8df3\u4e00\u4e0b\u5c31\u542f\u52a8\u5b8c\u6210\u4e86\u3002</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/qdwang", 
        "name": "qdwang", 
        "avatar": "https://cdn.v2ex.com/avatar/4be3/f330/40309_large.png?m=1758604322"
      }, 
      "url": "https://www.v2ex.com/t/1068887", 
      "title": "\u8bf7\u6559\u4e00\u4e2a\u5173\u4e8e Swift \u7684\u57fa\u7840\u5c0f\u95ee\u9898", 
      "id": "https://www.v2ex.com/t/1068887", 
      "date_published": "2024-08-29T21:00:20+00:00", 
      "content_html": "<p>\u5728\u9501\u5c4f\u5e55\u65b9\u5411\u7684\u60c5\u51b5\u4e0b\uff0c\u5982\u4f55\u83b7\u53d6\u8bbe\u5907\u7684\u65b9\u5411\u5462\uff1f</p>\n<p>\u6211\u8bd5\u4e86\u7f51\u4e0a\u5404\u79cd\u65b9\u6cd5\u90fd\u4e0d\u884c\uff0c\u7528\u4e86\u5b98\u65b9\u6587\u6863\u8bf4\u53ef\u4ee5\u7684<code>UIDevice.current.orientation</code>\uff0c\u4e5f\u4e0d\u884c\u3002\u3002\u3002</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/jamesdd", 
        "name": "jamesdd", 
        "avatar": "https://cdn.v2ex.com/gravatar/bb4b124ac90a707a2101745a1cdc1d93?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/1060673", 
      "title": "\u79bb\u7ebf iOS app \u4e5f\u9700\u8981 ICP \uff1f", 
      "id": "https://www.v2ex.com/t/1060673", 
      "date_published": "2024-07-28T08:48:03+00:00", 
      "content_html": "<p>\u63d0\u53ca\u4e86 iOS app \u7684\u66f4\u65b0\uff0c\u63d0\u53ca review \u7684\u65f6\u5019\u88ab\u8981\u6c42\u63d0\u4f9b ICP\uff1a</p>\n<pre><code>Unable to Add for Review\n\nThe items below are required to start the review process:\n\nYou must provide an Internet Content Provider (ICP) Filing Number to make this app available on the App Store in China mainland. Go to App Information\n</code></pre>\n<p>\u7136\u800c\u6211\u7684 app \u662f\u53ef\u4ee5\u79bb\u7ebf\u8fd0\u884c\u7684\uff0c\u4e0d\u9700\u8981\u8054\u7f51\uff0c\u4e5f\u6ca1\u6709 server \u7aef\uff0c\u5728 Xcode \u7684\u9879\u76ee\u4e2d\u4e5f\u628a networkextension \u4ece Signing&amp;Capabilities \u4e2d\u5220\u9664\u4e86\u3002</p>\n<p>\u5927\u5bb6\u662f\u5426\u9047\u5230\u8fc7\u7c7b\u4f3c\u60c5\u51b5\uff1f\u4e0d\u592a\u660e\u767d App store connect \u662f\u5982\u4f55\u5224\u65ad\u662f\u5426\u5e94\u8be5\u9700\u8981 ICP \u7684\u3002</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/whoami9426", 
        "name": "whoami9426", 
        "avatar": "https://cdn.v2ex.com/gravatar/c4c35e0545368c4592af2b2f54e01fc9?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/1060506", 
      "date_modified": "2024-08-01T12:07:05+00:00", 
      "content_html": "<p>\u60f3\u8981\u5b9e\u73b0\u4e00\u4e2a\u4e0a\u4e0b\u5206\u9875\u6ed1\u52a8,\u5de6\u53f3\u5206\u9875\u6ed1\u52a8\u7684\u4ea4\u4e92\u6548\u679c</p>\n<pre><code class=\"language-swift\"> var body: some View{\n  ScrollView(showsIndicators: false){\n            LazyVStack(spacing:0){\n                ForEach(1...10, id: \\.self){ index in\n                    ScrollView(.horizontal,showsIndicators: false){\n                        LazyHStack(spacing:0){\n                            \n                            VStack {\n                                Text(\"Left View \\(index)\")\n                                    .font(.system(.largeTitle))\n                                    .foregroundStyle(.white)\n                            }\n                            .frame(maxWidth: .infinity, maxHeight: .infinity)\n                            .background(Color.black)\n                            .containerRelativeFrame([.horizontal,.vertical])\n                           \n                            \n                            VStack {\n                                Text(\"Right View \\(index)\")\n                                    .font(.system(.largeTitle))\n                                    .foregroundStyle(.white)\n                            }\n                            .frame(maxWidth: .infinity, maxHeight: .infinity)\n                            .background(Color.blue)\n                            .containerRelativeFrame([.horizontal,.vertical])\n                            \n                        }.scrollTargetLayout()\n                    }\n                    .ignoresSafeArea()\n                    .containerRelativeFrame([.horizontal,.vertical])\n                    .scrollTargetBehavior(.paging)\n                    .onAppear(perform: {\n                        UIScrollView.appearance().bounces = false\n                        UIScrollView.appearance().alwaysBounceVertical = false\n                        UIScrollView.appearance().alwaysBounceHorizontal = false\n                    })\n                }\n            }.scrollTargetLayout()\n        }\n        .ignoresSafeArea()\n        .containerRelativeFrame([.horizontal,.vertical])\n        .scrollTargetBehavior(.paging)\n}\n</code></pre>\n<p>\u76ee\u524d\u7528\u8fd9\u79cd\u65b9\u5f0f\u5b9e\u73b0,\u4f46\u662f\u6709\u4e2a\u95ee\u9898,\u6ed1\u52a8\u5230 RightView \u53ef\u4ee5\u4e0a\u4e0b\u6ed1\u52a8\u5230\u4e0b\u4e00\u5c42,\u6709\u4ec0\u4e48\u529e\u6cd5\u5728\u6ed1\u52a8\u5230 RightView \u65f6\u53ea\u5141\u8bb8\u5de6\u6ed1\u56de Left View</p>\n<p><img alt=\"\" class=\"embedded_image\" loading=\"lazy\" referrerpolicy=\"no-referrer\" rel=\"noreferrer\" src=\"https://sso.xdsr.xyz/file/6cb6ed0f308af0bfa4fc1.gif\"/></p>\n", 
      "date_published": "2024-07-27T05:38:18+00:00", 
      "title": "\u8bf7\u6559 SwiftUI \u5e03\u5c40\u7684\u95ee\u9898", 
      "id": "https://www.v2ex.com/t/1060506"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/izzy27", 
        "name": "izzy27", 
        "avatar": "https://cdn.v2ex.com/avatar/a89c/c9a2/431329_large.png?m=1722241919"
      }, 
      "url": "https://www.v2ex.com/t/1050259", 
      "date_modified": "2024-06-17T08:44:11+00:00", 
      "content_html": "<p>\u6211\u6b63\u5728\u5f00\u53d1\u7684\u4e00\u4e2a iOS 17 Widget \uff0c\u5b83\u53ef\u4ee5\u4e3a\u7528\u6237\u7684 Thing \u5bf9\u8c61\u8fdb\u884c\u6253\u5361\u3002</p>\n<p>\u5f53\u6211\u540c\u65f6\u521b\u5efa\u591a\u4e2a Widget \u5b9e\u4f8b\u65f6\uff0c\u65e0\u8bba\u70b9\u51fb\u54ea\u4e2a Widget \u5b9e\u4f8b\u8fdb\u884c\u6253\u5361\uff0c\u5b83\u4eec\u66f4\u65b0\u7684\u90fd\u662f\u7b2c\u4e00\u4e2a Thing \uff0c\u770b\u8d77\u6765\u591a\u4e2a Widget \u90fd\u91cd\u590d\u6307\u5411\u4e86\u540c\u4e00\u4e2a Thing \u3002</p>\n<p>\u6211\u540e\u9762\u7ecf\u8fc7\u6392\u67e5\uff0c\u53d1\u73b0\u662f\u6211\u7684 AppIntent \u4e2d\uff0cParameter \u5e76\u4e0d\u8d77\u4f5c\u7528\uff0c\u7528\u6237\u65e0\u8bba\u9009\u62e9\u54ea\u4e2a thing,perform \u4e2d\u7684 thing \u90fd\u662f EntityQuery \u4e2d\u7684 defaultResult \u7684\u8fd4\u56de\u503c</p>\n<pre><code>struct ConfigurationAppIntent: WidgetConfigurationIntent {\n    @Parameter(title:\"Select thing\")\n    var thing: ThingData\n    \n    func perform() async throws -&gt; some IntentResult {\n            print(\"perform thing: \\(thing)\") // \u8fd9\u91cc\u4f1a\u76f4\u63a5\u8fd4\u56de defaultResult \u7684\u7ed3\u679c\uff0c\u800c\u4e0d\u662f\u7528\u6237\u9009\u62e9\u7684 thing\n\t}\n}\n\n    // EntityQuery \u4e2d\u7684\u4ee3\u7801\n    // AppIntent \u4e2d\u7684 thing \uff0c\u6c38\u8fdc\u662f\u8fd9\u91cc\u7684\u8fd4\u56de\u7ed3\u679c\uff0c\u800c\u4e0d\u662f\u7528\u6237\u9009\u62e9\u7684\u7ed3\u679c\n    func defaultResult() async -&gt; ThingData? {\n        logger.info(\"Entering defaultResult()\")\n        \n        let context = PersistenceController.shared.viewContext\n        let fetchRequest: NSFetchRequest&lt;Thing&gt; = Thing.fetchRequest()\n        fetchRequest.fetchLimit = 1\n\n        do {\n            let things = try context.fetch(fetchRequest)\n            things.forEach { logger.info(\"Default Thing: \\($0.description)\") }\n            logger.info(\"Exiting defaultResult()\")\n            return things.first?.toThingData()\n        } catch {\n            logger.error(\"Error fetching default result: \\(error.localizedDescription)\")\n            logger.info(\"Exiting defaultResult()\")\n            return nil\n        }\n    }\n</code></pre>\n<p>\u800c\u4e14\u8fd9\u6837\u4f1a\u6709\u4e00\u4e2a\u95ee\u9898\uff0c\u6bd4\u5982\u8bf4\u6211\u6709\u4e94\u516d\u4e2a thing \uff0c\u7528\u6237\u4e3a\u6bcf\u4e2a thing \u90fd\u6dfb\u52a0\u4e86\u4e00\u4e2a widget \uff0c\u4f46\u662f\u7531\u4e8e\u8fd9\u4e2a bug \u7684\u5b58\u5728\uff0c\u5bfc\u81f4\u53ea\u6709 defaultResult \u8fd4\u56de\u7684 Thing \u4f1a\u66f4\u65b0\uff0c\u5176\u4ed6\u90fd\u4e0d\u4f1a\u66f4\u65b0</p>\n<p>\u54ea\u4f4d\u5927\u4f6c\u77e5\u9053\u600e\u4e48\u89e3\u51b3\u5417\uff1f\u4fee\u4e86\u4e24\u5929\u4e86\uff0c\u6587\u6863\u3001\u89c6\u9891\u3001\u6559\u7a0b\u770b\u4e86\u4e00\u904d\uff0c\u90fd\u6ca1\u53d1\u73b0\u89e3\u51b3\u529e\u6cd5\u3002\u3002\u771f\u7684\u5f88\u75db\u82e6 T_T</p>\n", 
      "date_published": "2024-06-17T08:37:17+00:00", 
      "title": "ios 17 widget \u65e0\u6cd5\u6b63\u786e\u66f4\u65b0 core data", 
      "id": "https://www.v2ex.com/t/1050259"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/izzy27", 
        "name": "izzy27", 
        "avatar": "https://cdn.v2ex.com/avatar/a89c/c9a2/431329_large.png?m=1722241919"
      }, 
      "url": "https://www.v2ex.com/t/1046337", 
      "date_modified": "2024-06-03T09:30:26+00:00", 
      "content_html": "", 
      "date_published": "2024-06-03T05:21:01+00:00", 
      "title": "\u6709\u6ca1\u6709 Swift ui \u7248\u672c\u7684 tailwind css\uff1f", 
      "id": "https://www.v2ex.com/t/1046337"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/infyni", 
        "name": "infyni", 
        "avatar": "https://cdn.v2ex.com/gravatar/ab680cdf75f758f970bab3563a61625e?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/1045333", 
      "title": "swiftui \u91cc,\u8fd9\u91cc\u7528 hstack,\u4e3a\u4ec0\u4e48\u662f\u5782\u76f4\u5e03\u5c40,\u800c\u4e0d\u662f\u6c34\u5e73\u5e03\u5c40?", 
      "id": "https://www.v2ex.com/t/1045333", 
      "date_published": "2024-05-30T04:22:13+00:00", 
      "content_html": "<p>\u534a\u8def\u51fa\u5bb6\u5b66 swiftui,\u73b0\u5728\u5728\u5199\u4e00\u4e2a macos \u7684\u72b6\u6001\u680f\u7684\u5e94\u7528, \u6709\u4e2a\u5e03\u5c40\u95ee\u9898\u6211\u4e00\u76f4\u641e\u4e0d\u61c2\u554a.</p>\n<p>\u6bd4\u5982\u4e0b\u9762\u7684\u4ee3\u7801:</p>\n<pre><code> @SceneBuilder\n    private func menuBarExtra() -&gt; some Scene {\n        \n        if #available(macOS 13.0, *)  {\n\n            MenuBarExtra(isInserted: $statusMenu){\n                AppMenu()\n            } label: {\n                let image: NSImage = {\n                    let ratio = $0.size.height / $0.size.width\n                    $0.size.height = 18\n                    $0.size.width = 18 / ratio\n                    return $0\n                }(NSImage(named: \"Finder\")!)\n                \n                Image(nsImage: image)\n            }\n        }\n        \n       \n</code></pre>\n<pre><code>   struct AppMenu: View {\n    \n      var body: some View {\n         HStack{\n                Text(\"1\")\n                Text(\"2\")\n                Text(\"3\")\n            }\n       }\n    }\n</code></pre>\n<p>\u6211\u7684\u671f\u671b\u662f,\u4e09\u4e2a text \u5e94\u8be5\u662f\u6c34\u5e73\u5e03\u5c40\u5427.\u4e3a\u4ec0\u4e48\u5b9e\u9645\u51fa\u6765\u4f1a\u662f\u5782\u76f4\u5e03\u5c40\u5462?</p>\n<p><img alt=\"image\" class=\"embedded_image\" loading=\"lazy\" referrerpolicy=\"no-referrer\" rel=\"noreferrer\" src=\"https://www.freeimg.cn/i/2024/05/30/6657fe6f7f003.jpg\"/></p>\n<p>\u8bf7\u5404\u4f4d\u5927\u4f6c\u89e3\u60d1,\u6211\u53bb\u95ee\u8fc7 gpt, \u6ca1\u95ee\u51fa\u6765\u7ed3\u679c.</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/zhwguest", 
        "name": "zhwguest", 
        "avatar": "https://cdn.v2ex.com/avatar/b633/f688/433522_large.png?m=1685067457"
      }, 
      "url": "https://www.v2ex.com/t/1044950", 
      "title": "\u5927\u5bb6\u89c9\u5f97 Swift \u7684\u53c2\u6570\u5fc5\u987b\u6309\u5e8f\u63d0\u4f9b\u600e\u4e48\u6837\uff1f", 
      "id": "https://www.v2ex.com/t/1044950", 
      "date_published": "2024-05-29T02:25:10+00:00", 
      "content_html": "<p>\u6211\u662f\u89c9\u5f97\u633a\u522b\u626d\u7684\uff0c\u5df2\u7ecf\u6709\u6807\u7b7e\u4e86\uff0c\u4e3a\u4ec0\u4e48\u8fd8\u8981\u9075\u5faa\u987a\u5e8f\uff0c\u8ba9\u7f16\u8bd1\u5668\u505a\u591a\u597d\u3002</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/izzy27", 
        "name": "izzy27", 
        "avatar": "https://cdn.v2ex.com/avatar/a89c/c9a2/431329_large.png?m=1722241919"
      }, 
      "url": "https://www.v2ex.com/t/1043961", 
      "title": "Swift \u5f00\u6e90\u7684\u7ec4\u4ef6\u5e93\u597d\u50cf\u4e0d\u662f\u5f88\u591a\u554a", 
      "id": "https://www.v2ex.com/t/1043961", 
      "date_published": "2024-05-25T15:53:08+00:00", 
      "content_html": "<p>\u4e0d\u60f3\u91cd\u590d\u9020\u8f6e\u5b50\uff0c\u4f46\u662f\u7f51\u4e0a\u7684\u7ec4\u4ef6\u8981\u4e48\u8fc7\u671f\u4e86\uff0c\u8981\u4e48\u529f\u80fd\u4e0d\u662f\u5f88\u9f50\u5168</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/chopin1998519", 
        "name": "chopin1998519", 
        "avatar": "https://cdn.v2ex.com/gravatar/bc99c86f29b284e7b26decc964292ca5?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/1040249", 
      "date_modified": "2024-05-13T06:27:35+00:00", 
      "content_html": "<p>swift \u65b0\u624b</p>\n<p>\u5199\u4e86\u4e00\u4e2a 1000 \u591a\u884c\u7684\u4ee3\u7801\uff0c \u6ca1\u6709\u7528 xcode \u5f00\u53d1\uff0c \u76f4\u63a5 vscode \u64b8\u7684\uff0c</p>\n<p>\u8fd0\u884c\u65f6 \u76f4\u63a5 ./main.swift \uff08\u4ee3\u7801\u9996\u884c #!env swift \uff09\n\u6216\u8005 swiftc main.swift -o main.bin \uff0c \u7136\u540e ./main.bin \u8fd0\u884c</p>\n<p>\u73b0\u5728\u7a0b\u5e8f\u5927\u4f53\u7a33\u5b9a\uff0c \u4f46\u662f\u5076\u5c14\u4f1a\u5d29\u6e83\u4e00\u4e0b\uff0c\n\u5d29\u6e83\u65f6\u53ea\u662f\u63d0\u793a crash \u548c\u5f88\u5c11\u4fe1\u606f\uff0c \u641e\u4e0d\u6e05\u695a\u54ea\u91cc\u9519\u8bef\u3002</p>\n<p>\u4e5f\u8bd5\u8fc7 swiftc -g main.swift -o main.bin\n\u7136\u540e\u6709 lldb ./main.bin \uff0c \u518d run, crash \u7684\u65f6\u5019\u63d0\u793a\nerror: No auto repeat.com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x8)<br/>\n(lldb) me #0: 0x0000000192db0154 CoreFoundation<code>CFGetTypeID + 100</code> </p>\n<p>\u5c31\u4e0d\u4f1a\u4e86\u3002\u3002\u3002</p>\n<p>\u6709\u6ca1\u6709\u53ef\u80fd\u50cf python \u90a3\u4e9b\uff0ccrash \u4e86\u544a\u8bc9\u6211\u662f\u54ea\u884c\u56e0\u4e3a\u4ec0\u4e48\u539f\u56e0\u9519\u6389\u7684\u5462\uff1f\uff1f</p>\n<p>\u8c22\u8c22\u5404\u4f4d\u5927\u4f6c\uff01</p>\n", 
      "date_published": "2024-05-13T06:25:04+00:00", 
      "title": "Swift \u5982\u4f55\u50cf Python \u90a3\u6837 \u5d29\u6e83\u4e86\u8f93\u51fa backtrace \u6216\u8005\u81f3\u5c11\u662f\u54ea\u884c\u51fa\u9519\u4e86\u3002\u3002\u3002", 
      "id": "https://www.v2ex.com/t/1040249"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/realzzz", 
        "name": "realzzz", 
        "avatar": "https://cdn.v2ex.com/gravatar/98239ae4637aa7ee8fd8e97355503c2e?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/1036449", 
      "date_modified": "2024-04-28T11:18:11+00:00", 
      "content_html": "<p>\u9875\u9762\u5185\u5bb9\u662f\uff1a\u6709\u4e00\u4e2a\u5361\u7247\u5217\u8868\uff0c\u70b9\u51fb\u5361\u7247\uff0c\u5f39\u7a97\u5c55\u793a\u5361\u7247\u8be6\u60c5\u3002\n\u76ee\u524d\u95ee\u9898\uff0c\u9996\u6b21\u70b9\u51fb\u540e\uff0c\u5f39\u7a97\u6709\u6253\u5f00\uff0c\u4f46\u662f\u5f39\u7a97\u91cc\u6ca1\u6709\u6e32\u67d3\u5185\u5bb9\uff0c\u5173\u95ed\u540e\u6253\u5f00\u5176\u5b83\u5361\u7247\u53ef\u6b63\u5e38\u663e\u793a\u3002\u3002\u3002</p>\n<p>\u7b80\u5316\u4ee3\u7801\u5982\u4e0b\uff1a</p>\n<pre><code class=\"language-swift\">@State private var showStudentDetail: Bool = false\n@State private var studentDetail: Student?                    \n...\n\nVStack(alignment: .leading, spacing: 12) {\n  ForEach(students) { student in\n    CardView(student: student)\n      .onTapGesture {\n        studentDetail = student\n        showStudentDetail.toggle()\n      }\n    }\n    .sheet(isPresented: $showStudentDetail) {\n      if let studentDetail = studentDetail {\n        StudentDetailView(student: studentDetail)\n      }\n    }\n}\n</code></pre>\n", 
      "date_published": "2024-04-28T08:47:09+00:00", 
      "title": "\u8bf7\u6559\u4e00\u4e0b\u5404\u4f4d iOSer \u5de8\u4f6c\u4eec\u4e00\u4e2a SwiftUI sheet \u7ec4\u4ef6\u7684\u95ee\u9898", 
      "id": "https://www.v2ex.com/t/1036449"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/realzzz", 
        "name": "realzzz", 
        "avatar": "https://cdn.v2ex.com/gravatar/98239ae4637aa7ee8fd8e97355503c2e?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/1032689", 
      "date_modified": "2024-04-15T23:29:47+00:00", 
      "content_html": "<p>swiftUI \u65b0\u624b\u6c42\u6559\uff0c\u5728 HStack \u4e2d\uff0c\u5982\u679c\u8d85\u51fa\u5c4f\u5e55\u5bbd\u5ea6\uff0c\u5b50\u5143\u7d20\u5982\u4f55\u81ea\u52a8\u6362\u884c\u5462\uff1f</p>\n<p>\u6709\u50cf web \u5f00\u53d1\u4e2d\u7684 flex wrap \u5c5e\u6027\u5417\uff1f</p>\n<p>\u5927\u6982\u50cf\u662f\u8fd9\u4e2a\u56fe\u7684\u6548\u679c\uff1a</p>\n<p><img alt=\"1713172462275.png\" class=\"embedded_image\" loading=\"lazy\" referrerpolicy=\"no-referrer\" rel=\"noreferrer\" src=\"https://www.freeimg.cn/i/2024/04/15/661cefef69b9b.png\"/></p>\n", 
      "date_published": "2024-04-15T09:15:33+00:00", 
      "title": "\u8bf7\u6559\u4e00\u4e0b\u5404\u4f4d iOSer \u5de8\u4f6c\u4eec\u4e00\u4e2a SwiftUI \u4e2d HStack \u7684\u5e03\u5c40\u95ee\u9898", 
      "id": "https://www.v2ex.com/t/1032689"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/sunshinev", 
        "name": "sunshinev", 
        "avatar": "https://cdn.v2ex.com/avatar/8f02/7cc0/455653_large.png?m=1740458717"
      }, 
      "url": "https://www.v2ex.com/t/1032030", 
      "date_modified": "2024-04-12T09:43:32+00:00", 
      "content_html": "<p>swiftui \u7528\u8d77\u6765\u5f88\u7075\u6d3b\uff0c\u4f46\u662f\u611f\u89c9\u50cf\u641c\u7d22\u6846\uff0c\u8fd9\u4e9b\u662f\u4e0d\u662f\u53ef\u4ee5\u76f4\u63a5\u6709\u5c01\u88c5\u597d\u7684\u7ec4\u4ef6\u5565\u7684</p>\n<p>\u6bd4\u5982\u56fe\u7247\u7ffb\u9875\u6d4f\u89c8\u8fd9\u4e9b</p>\n", 
      "date_published": "2024-04-12T09:42:40+00:00", 
      "title": "swiftui \u6709\u597d\u7528\u7684\u7ec4\u4ef6\u5e93\u5417\uff1f", 
      "id": "https://www.v2ex.com/t/1032030"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/ZhuWenJian", 
        "name": "ZhuWenJian", 
        "avatar": "https://cdn.v2ex.com/gravatar/b4c256a25835ea97ffb5e73dc97c4aaf?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/1031831", 
      "title": "\u6c42\u95ee\uff1a\u82f9\u679c\u624b\u673a\u662f\u5426\u65e0\u6cd5\u50cf\u5b89\u5353\u4e00\u6837\uff0c\u53ef\u4ee5\u626b\u63cf\u51fa\u672c\u5730\u7684\u97f3\u4e50\uff1f", 
      "id": "https://www.v2ex.com/t/1031831", 
      "date_published": "2024-04-12T01:22:58+00:00", 
      "content_html": "<p>\u6709\u4e2a idea \uff0c\u76ee\u524d\u662f\u7528 flutter \u8fdb\u884c\u5f00\u53d1\uff0c\u4f46\u662f\u53d1\u73b0\u65e0\u6cd5\u83b7\u53d6\u672c\u5730\u97f3\u4e50\u3002\n\u4e0b\u8f7d\u4e86\u51e0\u4e2a app \uff0c\u50cf QQ \u97f3\u4e50\u3001\u7f51\u6613\u4e91\u97f3\u4e50\u4ee5\u53ca\u5176\u5b83\u7684\u4e00\u4e9b app \uff0c\u90fd\u6ca1\u6cd5\u83b7\u53d6\u5230\u5728\u5176\u5b83\u7b2c\u4e09\u65b9 app \u4e0a\u4e0b\u8f7d\u7684\u97f3\u4e50\u3002\n\u4e0d\u77e5\u9053\u662f\u4e0d\u662f\u6211\u4e0b\u8f7d\u7684\u5c11\uff0c\u8fd8\u662f\u64cd\u4f5c\u4e4b\u7c7b\u7684\u4e0d\u5bf9\u3002\n\u6240\u4ee5\u95ee\u4e0b\uff1a\u82f9\u679c\u624b\u673a\u4e0a\u7684 app \uff0c\u65e0\u6cd5\u83b7\u53d6\u5176\u5b83\u5e94\u7528\u4e0b\u8f7d\u7684\u97f3\u4e50\uff1f</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/jamesdd", 
        "name": "jamesdd", 
        "avatar": "https://cdn.v2ex.com/gravatar/bb4b124ac90a707a2101745a1cdc1d93?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/1025133", 
      "title": "macOS \u6c99\u76d2\u4e2d\u5982\u4f55\u83b7\u5f97\u5bf9\u4efb\u610f\u76ee\u5f55\u7684\u5199\u6743\u9650\uff1f", 
      "id": "https://www.v2ex.com/t/1025133", 
      "date_published": "2024-03-19T09:20:31+00:00", 
      "content_html": "<p>\u6253\u7b97\u505a\u4e00\u4e2a macOS app \u6765\u5b89\u88c5\u81ea\u5df1\u7684\u4e00\u4e2a\u63d2\u4ef6\u5230 Adobe \u5e94\u7528\uff0c\u5728\u6211\u7684 app \u4e2d\u6765\u628a\u63d2\u4ef6\u5b89\u88c5\u5230 Adobe \u5e94\u7528\u7684\u76ee\u5f55\u4e2d\u3002\n1.\u5982\u679c Adobe \u5e94\u7528\u662f\u5b89\u88c5\u5728\u9ed8\u8ba4\u76ee\u5f55 /Appliactions \u4e2d\uff0c\u4e0d\u9700\u8981\u7528\u6237\u9009\u62e9\uff1b\n2.\u7528\u6237\u53ef\u4ee5\u9009\u62e9\u4e00\u4e2a\u76ee\u5f55\u6765\u8fdb\u884c\u63d2\u4ef6\u7684\u5b89\u88c5\u3002\n\u95ee\u9898\u662f\u5728 sandbox \u4e2d\u662f\u6ca1\u6709\u5176\u4ed6\u76ee\u5f55\u7684\u5199\u6743\u9650\u7684\uff0c\u8be5\u5982\u4f55\u7533\u8bf7\u5199\u6743\u9650\uff1f\u76ee\u524d\u63a2\u7d22\u5230\u7684\u65b9\u6cd5\u662f\u9700\u8981\u7528\u6237\u624b\u52a8\u9009\u62e9\u4e00\u4e2a\u76ee\u5f55\uff08\u7528 NSOpenPanel)\uff0c\u8fd9\u53ea\u9002\u5408\u4e0a\u9762\u63d0\u5230\u7684\u7b2c 2 \u79cd\u573a\u666f\uff0c\u4f46\u5982\u679c\u91cd\u542f app \u540e\u7528\u6237\u4e0a\u6b21\u9009\u62e9\u7684\u8def\u5f84\u4e5f\u6ca1\u6709\u6743\u9650\u4e86\u3002\n\u8bf7\u95ee\u6709\u6ca1\u6709\u4ec0\u4e48\u65b9\u6cd5\u53ef\u4ee5\u5728 sandbox \uff08 app \u8ba1\u5212\u53d1\u5e03\u5230 app store \uff09\u4e2d\u7533\u8bf7\u4efb\u610f\u6587\u4ef6\u5939\u7684\u5199\u6743\u9650\uff1f\u8fd8\u662f\u8bf4 macOS \u4e0a\u4e3a\u4e86\u5b89\u5168\u6ca1\u6709\u8fd9\u4e2a\u673a\u5236\uff0c\u53ea\u80fd\u7528\u6237\u9009\u62e9\u5177\u4f53\u8def\u5f84\uff1f\n\u4e0d\u7528\u5177\u4f53\u4ee3\u7801\uff0c\u9ebb\u70e6\u6307\u4e2a\u65b9\u5411\uff0c\u8be5\u5b66\u4e60 apple \u7684\u54ea\u65b9\u9762\u7684\u5f00\u53d1\u4e3b\u9898\u3002\n\u591a\u8c22\uff01</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/rookiemaster", 
        "name": "rookiemaster", 
        "avatar": "https://cdn.v2ex.com/avatar/b368/6614/659911_large.png?m=1769416716"
      }, 
      "url": "https://www.v2ex.com/t/1021570", 
      "title": "swiftui \u4e2d\u7684\u8bed\u6cd5\u7cd6\u7591\u95ee", 
      "id": "https://www.v2ex.com/t/1021570", 
      "date_published": "2024-03-07T10:17:38+00:00", 
      "content_html": "<pre><code class=\"language-swift\">VStack{\n    Image(systemName: \"globe\")\n    Text(\"\ud83d\udc7b\").font(.largeTitle)\n}\n</code></pre>\n<p>\u4e0a\u9762\u662f\u4e00\u6bb5 swiftui \u4ee3\u7801\uff0c\u5b83\u80fd\u521b\u5efa\u4e00\u4e2a\u5782\u76f4\u6392\u5217\u7684 view \uff0c\u91cc\u9762\u7684\u95ed\u5305\u662f\u4f5c\u4e3a VStack.init \u4e2d content \u7684\u53c2\u6570\uff0c\u67e5\u770b\u6e90\u7801\u53ef\u77e5 content \u7684\u7c7b\u578b\u662f()-&gt;Content \u3002\n\u6211\u7684\u7591\u95ee\u662f</p>\n<pre><code>Image(systemName: \"globe\")\nText(\"\ud83d\udc7b\").font(.largeTitle)\n</code></pre>\n<p>\u662f\u4ec0\u4e48\u8bed\u6cd5\uff0c\u4ed6\u4e3a\u4ec0\u4e48\u80fd\u8fd4\u56de\u4e00\u4e2a Content \uff0c\u6211\u6240\u4e86\u89e3\u7684\u662f\u8981\u662f\u53ea\u6709\u4e00\u884c\u4ee3\u7801\u7684\u8bdd\u624d\u53ef\u4ee5\u5ffd\u7565\u6389 return \uff0c\u8fd9\u91cc\u4e0d\u662f\u6709\u4e24\u884c\u561b\uff0c\u6c42\u89e3\u7b54\u3002</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/ShiJh", 
        "name": "ShiJh", 
        "avatar": "https://cdn.v2ex.com/avatar/bddc/d9af/582830_large.png?m=1708169807"
      }, 
      "url": "https://www.v2ex.com/t/1016042", 
      "title": "\u5f00\u53d1 macOS \u5e94\u7528\u65e0\u6cd5\u8bbf\u95ee\u7528\u6237\u9009\u62e9\u7684\u6587\u4ef6\u5939\u4e0b\u7684\u6587\u4ef6", 
      "id": "https://www.v2ex.com/t/1016042", 
      "date_published": "2024-02-17T11:38:17+00:00", 
      "content_html": "<h3>\u5f00\u53d1 macOS \u5e94\u7528\u9047\u5230\u7684\u6587\u4ef6\u8bbf\u95ee\u6743\u9650\u95ee\u9898</h3>\n<p>\u65e0\u6cd5\u8bbf\u95ee\u7528\u6237\u9009\u62e9\u7684\u6587\u4ef6\u5939\u4e0b\u7684\u6587\u4ef6\uff0c\u8fd9\u4e2a\u95ee\u9898\u6211\u4e5f\u53d1\u5230<a href=\"https://stackoverflow.com/questions/78011895/swiftui-how-to-access-read-only-files-under-users-selected-directory\" rel=\"nofollow\">Stackoverflow</a>\u4e2d\uff0c\u5927\u4f6c\u4eec\u80fd\u5426\u770b\u770b\ud83d\udc40\uff0c\u5728\u8fd9\u91cc\u6216\u8005 stackoverflow \u4e2d\u56de\u7b54\u90fd\u53ef\u4ee5\uff01</p>\n<p>\u5e94\u7528\u7684\u76ee\u6807\u662f\u83b7\u53d6\u6587\u4ef6\u5939\u4e0b\u7684\u6240\u6709\u89c6\u9891\uff0c\u50a8\u5b58\u6210\u4e00\u4e2a\u6570\u7ec4\uff0c\u5728\u9700\u8981\u7684\u65f6\u5019\u4f7f\u7528 URL \u52a0\u8f7d\u89c6\u9891\u3002\u8c03\u67e5\u4e86\u51e0\u6b3e\u89c6\u9891\u64ad\u653e App \u90fd\u80fd\u652f\u6301\uff0c\u4e0d\u77e5\u9053\u4e3a\u4ec0\u4e48\u6211\u6309\u7167\u7f51\u4e0a\u7684\u6559\u7a0b\u64cd\u4f5c\u540e\uff0c\u4ecd\u7136\u65e0\u6cd5\u652f\u6301</p>\n<h4>\u53e6\u4e00\u4e2a\u4e0d\u91cd\u8981\u7684\u5c0f\u95ee\u9898</h4>\n<p>\u6211\u60f3\u7528 SwiftUI \u4e2d\u7684.help \u4fee\u9970\u7b26\u5728 hover \u7684\u65f6\u5019\u663e\u793a tooltip \uff0c\u4f46\u662f\u5728 macOS 14.0 \u4e2d\u65e0\u6cd5\u751f\u6548\uff0c\u5176\u4ed6\u7cfb\u7edf\u7248\u672c\u672a\u6d4b\u8bd5</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/YugenFring", 
        "name": "YugenFring", 
        "avatar": "https://cdn.v2ex.com/avatar/2ba6/53bd/672175_large.png?m=1711347569"
      }, 
      "url": "https://www.v2ex.com/t/1009883", 
      "title": "\u5f04\u4e86\u4e00\u4e2a Swift \u5b98\u65b9\u6559\u7a0b\u7684\u901f\u89c8\u7248", 
      "id": "https://www.v2ex.com/t/1009883", 
      "date_published": "2024-01-19T01:17:58+00:00", 
      "content_html": "<p>\u6709\u9700\u8981\u7684\u670b\u53cb\u70b9\u4e2a star \u5440, \u81ea\u5df1\u4e5f\u662f\u521a\u5b66, \u89c9\u5f97\u5b98\u65b9\u6559\u7a0b\u867d\u7136\u8be6\u7ec6, \u4f46\u662f\u786e\u5b9e\u6709\u70b9\u957f, \u4e0d\u65b9\u4fbf\u67e5\u9605\u548c\u5feb\u901f\u5b66\u4e60</p>\n<p>\u8d34\u4e2a\u94fe\u63a5: <a href=\"https://github.com/YugenFring/swift-tutorial-quickstart\" rel=\"nofollow\">https://github.com/YugenFring/swift-tutorial-quickstart</a></p>\n<p><img alt=\"image\" class=\"embedded_image\" loading=\"lazy\" referrerpolicy=\"no-referrer\" rel=\"noreferrer\" src=\"https://img.nga.178.com/attachments/mon_202401/18/-4bvoQ2t-81opZeT3cSon-nl.jpg\"/></p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/terrysnake", 
        "name": "terrysnake", 
        "avatar": "https://cdn.v2ex.com/avatar/f3d9/de86/2214_large.png?m=1684829468"
      }, 
      "url": "https://www.v2ex.com/t/1004278", 
      "title": "2024 \u5e74\u4e86\uff0c\u73b0\u5728\u5b66 SwiftUI \u8fd8\u6709\u5fc5\u8981\u5b66 UIkit \u5417\uff1f", 
      "id": "https://www.v2ex.com/t/1004278", 
      "date_published": "2023-12-29T01:07:52+00:00", 
      "content_html": "<p>\u5982\u9898\uff0c\u51fa\u5165\u95e8\uff0c\u4e3b\u5b66 SwiftUI \u505a\u4e00\u4e9b\u7b80\u5355\u7684 iOS APP \uff0c\u8fd8\u6709\u5fc5\u8981\u5b66 UIkit \u5417\uff1f\n\u73b0\u5728\u7684\u5e93\u591f\u5417\uff1f</p>\n<p>\u611f\u8c22\u89e3\u7b54</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/Kinnikuman", 
        "name": "Kinnikuman", 
        "avatar": "https://cdn.v2ex.com/avatar/5951/a7f8/645335_large.png?m=1692927861"
      }, 
      "url": "https://www.v2ex.com/t/997316", 
      "title": "\u5927\u4f6c\u4eec\u6307\u70b9\u4e0b\u82f9\u679c\u751f\u6001\u4e0b\u97f3\u9891\u76f8\u5173\u7684\u8fd9\u4e9b\u5e93\u90fd\u662f\u4ec0\u4e48\u5173\u7cfb\uff1f", 
      "id": "https://www.v2ex.com/t/997316", 
      "date_published": "2023-12-03T14:14:05+00:00", 
      "content_html": "<p>\u60f3\u5b66\u4e60\u4e00\u4e0b\u97f3\u9891\u76f8\u5173\u7684\u5f00\u53d1\uff0c\u4f46\u627e\u4e86\u4e0b\uff0c\u6709\u592a\u591a\u7684\u5e93\u4f9b\u9009\u62e9\u4e86\uff0c\u628a\u6211\u7ed5\u6655\u4e86:</p>\n<ul>\n<li>AVFoundation</li>\n<li>MediaPlayer</li>\n<li>AVFAudio</li>\n<li>Audio Engine</li>\n<li>CoreAudio</li>\n<li>AudioToolbox</li>\n<li>Audio Unit</li>\n</ul>\n<p>\u5982\u679c\u60f3\u5b9e\u73b0\u64ad\u653e\u7f51\u7edc\u6216\u8005\u672c\u5730\u7684\u97f3\u4e50\u6570\u636e\uff08 flac/wav/mp3/aac/wma/ogg \uff09\u5e94\u8be5\u7528\u5230\u54ea\u4e9b\u5e93\uff1f\u90fd\u662f\u8d77\u5230\u4ec0\u4e48\u4f5c\u7528\uff1f</p>\n<p>\u6211\u7406\u89e3\u7684\u662f\uff0c\u5e94\u8be5\u4f7f\u7528 ffmpeg \u5148\u8fdb\u884c demux \u89e3\u5c01\u88c5\uff0c\u7136\u540e\u518d\u5bf9 stream \u8fdb\u884c decode \u83b7\u53d6\u5230 PCM sample \uff0c\u6700\u540e\u8c03\u7528\u4e0a\u9762\u67d0\u4e00\u4e2a\u5e93\uff08\u53ef\u80fd\u662f Audio Engine \uff09\u8fdb\u884c\u64ad\u653e\u3002</p>\n<p>\u4f46\u6211\u8bf4\u7684\u8fd9\u4e2a\u65b9\u6cd5\u662f\u8f6f\u89e3\u7801\u4e48\uff1f\u5982\u679c\u82f9\u679c\u81ea\u5df1\u652f\u6301\u7684\u683c\u5f0f\u6bd4\u5982 mp3 \u7b49\uff0c\u662f\u5426\u53ef\u4ee5\u4e0d\u4f7f\u7528 ffmpeg \u6765\u89e3\u7801\uff1f\u90a3\u5e94\u8be5\u7528\u4e0a\u9762\u54ea\u4e2a\u5e93\u6765\u5904\u7406\uff1f</p>\n<p>\u8fd8\u6709\u97f3\u4e50\u6587\u4ef6\u7684 metadata \u89e3\u6790\uff08\u97f3\u4e50\u540d/\u827a\u672f\u5bb6/\u5c01\u9762/\u6b4c\u8bcd\u7b49\u4fe1\u606f\uff09\uff0c\u5982\u4f55\u63d0\u53d6 metadata? \u82f9\u679c\u81ea\u5bb6\u7684\u4ec5\u652f\u6301 ID3 \u6216\u8005 iTunes \uff0c\u5bf9\u4e8e\u5176\u4ed6\u683c\u5f0f\u7684\u6bd4\u5982 wav/flac \u7b49\uff0c\u5e94\u8be5\u600e\u4e48\u5904\u7406\uff1f</p>\n<p>\u4e0b\u9762\u4e24\u4e2a\u94fe\u63a5\u662f\u6211\u770b\u8fc7\u7684\u53c2\u8003\u8d44\u6599\uff0c\u597d\u50cf\u5df2\u7ecf\u8fc7\u65f6\u4e86\u3002\u7ecf\u8fc7\u641c\u7d22\u4e5f\u6ca1\u6709\u627e\u5230\u65b0\u7684\u6bd4\u8f83\u9760\u8c31\u7684\u8bb2\u89e3\u3002</p>\n<ul>\n<li><a href=\"https://stackoverflow.com/questions/1877410/whats-the-difference-between-the-apple-audio-frameworks\" rel=\"nofollow\">whats-the-difference-between-the-apple-audio-frameworks</a></li>\n<li><a href=\"https://developer.apple.com/library/archive/documentation/MusicAudio/Conceptual/CoreAudioOverview/CoreAudioEssentials/CoreAudioEssentials.html#//apple_ref/doc/uid/TP40003577-CH10-SW1\" rel=\"nofollow\">Core Audio Essentials</a></li>\n</ul>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/Livid", 
        "name": "Livid", 
        "avatar": "https://cdn.v2ex.com/avatar/c4ca/4238/1_large.png?m=1775624785"
      }, 
      "url": "https://www.v2ex.com/t/978140", 
      "title": "\u5347\u7ea7\u5230 Xcode 15 \u4e4b\u540e\u9047\u5230\u7684 GeneratedAssetSymbols \u8fc7\u4e0d\u4e86\u7f16\u8bd1\u8fd9\u4e2a\u95ee\u9898", 
      "id": "https://www.v2ex.com/t/978140", 
      "date_published": "2023-09-29T05:28:02+00:00", 
      "content_html": "<p>\u8fd9\u8c8c\u4f3c\u662f Xcode 15 \u7684\u67d0\u4e2a\u65b0\u529f\u80fd\u81ea\u52a8\u751f\u6210\u4e86\u4ee3\u7801\uff0c\u5374\u8fc7\u4e0d\u4e86\u81ea\u5df1\u7684\u7f16\u8bd1\u5668\u3002</p>\n<p><img alt=\"\" class=\"embedded_image\" loading=\"lazy\" referrerpolicy=\"no-referrer\" rel=\"noreferrer\" src=\"https://i.v2ex.co/8b88os0t.png\"/></p>\n<p>\u76ee\u524d\u67e5\u5230\u7684\u4e00\u4e2a\u89e3\u51b3\u65b9\u6848\u662f\u5728 xcconfig \u91cc\u52a0\u4e0a\u8fd9 3 \u6761\u628a\u8fd9\u4e2a\u65b0\u529f\u80fd\u6682\u65f6\u7981\u7528\u3002</p>\n<pre><code>ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO;\nASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOL_FRAMEWORKS = \"\";\nASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = NO;\n</code></pre>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/zhwguest", 
        "name": "zhwguest", 
        "avatar": "https://cdn.v2ex.com/avatar/b633/f688/433522_large.png?m=1685067457"
      }, 
      "url": "https://www.v2ex.com/t/973337", 
      "title": "\u73b0\u5728\u7528 Swift \u5f00\u53d1\u540e\u7aef\u6210\u719f\u4e86\u5417\uff1f", 
      "id": "https://www.v2ex.com/t/973337", 
      "date_published": "2023-09-13T03:54:29+00:00", 
      "content_html": "<p>\u5e0c\u671b\u5927\u795e\u6765\u6307\u70b9\u4e0b\uff0c\u7528\u5f97\u6bd4\u8f83\u591a\u7684\u5c31\u662f http \u7684\u6846\u67b6\u3001crypto \u7684\u5e93\uff0c\u8fd8\u6709\u5f02\u6b65\u5316\u3002</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/luamer", 
        "name": "luamer", 
        "avatar": "https://cdn.v2ex.com/gravatar/dd74abc2263f67d610fd2dd58626afa8?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/966566", 
      "date_modified": "2023-08-18T15:34:47+00:00", 
      "content_html": "<a target=\"_blank\" href=\"https://github.com/OpenLyl/Water\" rel=\"nofollow noopener\">https://github.com/OpenLyl/Water</a><br /><br />\u8fd9\u4e2a\u5e93\u80fd\u5e72\u4ec0\u4e48\uff1f<br /><br />- \u6e10\u8fdb\u5f0f\u7684\u5e2e\u52a9\u4f60\u5f00\u53d1 SwiftUI \u754c\u9762<br />- \u72b6\u6001\u7ba1\u7406\u539f\u5b50\u5316\uff0c\u53ef\u81ea\u7531\u7ec4\u5408<br />- \u53ef\u5355\u72ec\u4f7f\u7528\uff0c\u4e5f\u53ef\u4e0e TCA \u548c MVVM \u67b6\u6784\u7ed3\u5408\u4f7f\u7528<br /><br />\u603b\u4e4b\uff0c\u5982\u679c\u4f60\u89c9\u5f97\u5176\u4ed6\u5e93\u590d\u6742\u4e14\u4e0d\u597d\u638c\u63e1\uff0c\u6216\u8005\u4f60\u662f\u4e00\u4e2a SwiftUI \u65b0\u624b\uff0c\u90fd\u53ef\u4ee5\u5c1d\u8bd5\u4f7f\u7528\u8fd9\u4e2a\u5e93", 
      "date_published": "2023-08-18T15:28:47+00:00", 
      "title": "Composable SwiftUI", 
      "id": "https://www.v2ex.com/t/966566"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/8888888888", 
        "name": "8888888888", 
        "avatar": "https://cdn.v2ex.com/gravatar/11f796086ce788cebdf0900cf27c3d3d?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/957188", 
      "title": "2023 \u5e74\uff0c swiftui \u4f7f\u7528 WKWebView \u52a0\u8f7d html \u5b57\u7b26\u4e32\uff0c\u5982\u4f55\u81ea\u9002\u5e94 frame \u9ad8\u5ea6\uff1f", 
      "id": "https://www.v2ex.com/t/957188", 
      "date_published": "2023-07-16T12:01:26+00:00", 
      "content_html": "<p>\u81ea\u5b66 swift \u4e2d\uff0c\u627e\u4e86\u5f88\u591a\u8d44\u6599\uff0c\u8bd5\u4e86\u90fd\u4e0d\u592a\u884c\uff0c\u6709\u5927\u4f6c\u6559\u4e00\u6559\u600e\u4e48\u5904\u7406\u5417</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/wangsilence", 
        "name": "wangsilence", 
        "avatar": "https://cdn.v2ex.com/avatar/bdf3/c45e/438835_large.png?m=1729066360"
      }, 
      "url": "https://www.v2ex.com/t/954647", 
      "title": "\u7528 network extension \u6846\u67b6\u5f00\u542f Tunnel\uff0c\u600e\u4e48\u80fd\u4fdd\u6301\u540e\u53f0\u8bf7\u6c42\u63a5\u53e3\uff0c\u89e3\u51b3\u8bf7\u559d\u676f\u5496\u5561", 
      "id": "https://www.v2ex.com/t/954647", 
      "date_published": "2023-07-06T10:03:48+00:00", 
      "content_html": "<p>\u6211\u7528 network extension \u6846\u67b6\u5f00\u542f Tunnel \u5c06 http \u4ee3\u7406\u8bbe\u7f6e\u6210\u6211\u542f\u52a8\u7684\u4e00\u4e2a\u7aef\u53e3\uff0c\u8f6c\u53d1\u6293\u53d6 http \u8bf7\u6c42\uff0c\u4f46\u662f\u5207\u6362\u5230\u540e\u53f0\u5c31\u4e0d\u4f1a\u518d\u8bf7\u6c42\u63a5\u53e3\u4e86\uff0c\u5207\u6362\u5230\u524d\u53f0\u8fd0\u884c\u7684\u597d\u597d\u7684\u3002</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/ben123321", 
        "name": "ben123321", 
        "avatar": "https://cdn.v2ex.com/gravatar/5733bdaf38d051df8be389a7e67da997?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/953185", 
      "title": "\u5b66\u751f\u515a\u6c42\u95ee\u5404\u4f4d\u5927\u4f6c\uff0c\u4e00\u4e2a\u5173\u4e8e ios \u5c0f\u7ec4\u4ef6\u7684\u95ee\u9898", 
      "id": "https://www.v2ex.com/t/953185", 
      "date_published": "2023-07-01T01:13:56+00:00", 
      "content_html": "<p>\u80cc\u666f\u662f\u8fd9\u6837\u7684\uff0c\u6211\u4eec\u5b66\u6821\u7684\u8001\u5e08\u8981\u6c42\u6211\u4eec\u505a\u4e00\u4e2a iphone \u7684\u5927\u4f5c\u4e1a\u3002\u7136\u800c\u5c0f\u5f1f\u6211\u597d\u6b7b\u4e0d\u6b7b\uff0c\u4e3a\u4e86\u80fd\u591f\u627e\u5230\u5b9e\u4e60\u7684\u5de5\u4f5c\uff0c\u8ffd\u6c42\u524d\u6cbf\u6280\u672f\u3002\u60f3\u8981\u505a\u4e00\u4e2a\u65f6\u949f\u5c0f\u7ec4\u4ef6\u7684\u5e94\u7528\u3002</p>\n<p>\u505a\u7740\u505a\u7740\uff0c\u8eab\u8fb9\u7684\u540c\u5b66\u4e5f\u4e0d\u9009\u62e9\u5c0f\u7ec4\u4ef6\u7684\u5e94\u7528\u3002\u6ca1\u540c\u5b66\u53ef\u4ee5\u8bf7\u6559\u3002\u53ea\u80fd\u5bfb\u6c42\u7f51\u4e0a\u5389\u5bb3\u7684\u5927\u4f6c\u3002</p>\n<p>\u6211\u9047\u5230\u7684\u95ee\u9898\u662f\uff1a\n\u6211\u60f3\u5b9e\u73b0\u65f6\u949f\u5c0f\u7ec4\u4ef6\u6dfb\u52a0\u5230\u684c\u9762\u540e\u80fd\u81ea\u52a8\u5237\u65b0\u3002\u6211\u53ea\u505a\u5230\u4e86\u5c0f\u7ec4\u4ef6\u7684\u79d2\u9488\u8dd1\u4e86\u51e0\u5708\uff0c\u7136\u540e\u5c31\u505c\u4e0b\u6765\u4e86\u3002</p>\n<p>\u8981\u662f\u6709\u5927\u4f6c\u80fd\u591f\u89e3\u7b54\uff0c\u613f\u610f\u8bf7\u5927\u4f6c\u559d\u676f\u5976\u8336\uff08\u5b66\u751f\u515a\uff0c\u8bf7\u8c05\u89e3\uff09\ud83d\ude02\ud83d\ude02\ud83d\ude02</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/zouzls", 
        "name": "zouzls", 
        "avatar": "https://cdn.v2ex.com/avatar/3422/321f/172250_large.png?m=1699539023"
      }, 
      "url": "https://www.v2ex.com/t/942929", 
      "title": "\u6bd4\u8f83\u597d\u7684 Swift UI \u5b66\u4e60\u4ea4\u6d41\u7fa4", 
      "id": "https://www.v2ex.com/t/942929", 
      "date_published": "2023-05-25T09:01:18+00:00", 
      "content_html": "<p>\u6709\u6ca1\u6709\u6bd4\u8f83\u597d\u7684 Swift UI \u5b66\u4e60\u4ea4\u6d41\u7fa4\uff0c\u5de5\u4f5c\u95f2\u9c7c\u65f6\u95f4\u60f3\u5b66\u4e60\u81ea\u5df1\u5f00\u53d1\u4e2a app \uff0c\u6709\u4e00\u4e9b\u60f3\u6cd5\uff0c\u65e5\u540e\u67d0\u4e00\u5929\u8bf4\u4e0d\u5b9a\u6210\u72ec\u7acb\u5f00\u53d1\u8005\u3002</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/PhanKiap", 
        "name": "PhanKiap", 
        "avatar": "https://cdn.v2ex.com/avatar/e48e/586e/89488_large.png?m=1773740302"
      }, 
      "url": "https://www.v2ex.com/t/941360", 
      "date_modified": "2023-05-19T10:19:26+00:00", 
      "content_html": "", 
      "date_published": "2023-05-19T10:16:24+00:00", 
      "title": "CAID \u8fd9\u5783\u573e\u4e1c\u897f\u662f\u8c01\u5728\u63a8\uff0c\u4e00\u8fb9\u558a\u7740\u4fdd\u62a4\u9690\u79c1\uff0c\u4e00\u8fb9\u60f3\u7740\u6cd5\u5b50\u6765\u8ddf\u8e2a\u7528\u6237", 
      "id": "https://www.v2ex.com/t/941360"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/sl0000", 
        "name": "sl0000", 
        "avatar": "https://cdn.v2ex.com/avatar/b2cb/f035/161416_large.png?m=1486131040"
      }, 
      "url": "https://www.v2ex.com/t/934873", 
      "date_modified": "2023-04-23T12:14:36+00:00", 
      "content_html": "<pre><code>var a: Int? = nil\nprint(\"\\(type(of: a))\")\nprint(\"\\(a is String?)\")\n\nvar b: Int? = 1\nprint(\"\\(type(of: b))\")\nprint(\"\\(b is String?)\")\n\n/*\noutput::\nOptional&lt;Int&gt;\ntrue\nOptional&lt;Int&gt;\nfalse\n */\n</code></pre>\n<p>\u4e0b\u9762\u662f GPT \u7684\u7b54\u6848</p>\n<p><a href=\"https://imgur.com/icrQLyL\" rel=\"nofollow\">Imgur</a></p>\n", 
      "date_published": "2023-04-23T12:07:55+00:00", 
      "title": "Swift \u7684 Optional \u5982\u4f55\u6bd4\u8f83\u5305\u88c5\u7c7b\u578b\u7684\u5173\u7cfb\u5462\uff1f", 
      "id": "https://www.v2ex.com/t/934873"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/0littleboy", 
        "name": "0littleboy", 
        "avatar": "https://cdn.v2ex.com/avatar/9c6f/fcda/478438_large.png?m=1757388573"
      }, 
      "url": "https://www.v2ex.com/t/932292", 
      "title": "Alamofire \u63a8\u8350\u4f7f\u7528\u5417\uff1f", 
      "id": "https://www.v2ex.com/t/932292", 
      "date_published": "2023-04-13T09:19:06+00:00", 
      "content_html": "<p>\u6700\u8fd1\u5728\u5199 APP \u7684\u65f6\u5019\uff0c\u53d1\u73b0\u4e86 Alamofire \u8fd9\u4e2a\u4e1c\u897f</p>\n<p>\u4f3c\u4e4e\u53ef\u4ee5\u66ff\u4ee3\u81ea\u5e26\u7684 URLSession.shared.dataTask \u8fdb\u884c\u7f51\u7edc\u8bf7\u6c42\u53ca\u81ea\u52a8\u89e3\u6790 json \u6587\u4ef6</p>\n<p>\u53ef\u4ee5\u6781\u5927\u7b80\u5316\u5f00\u53d1\u96be\u5ea6</p>\n<p>\u63a8\u8350\u4f7f\u7528\u5417\uff0c\u4f1a\u4e0d\u4f1a\u9047\u5230\u4ec0\u4e48\u95ee\u9898</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/novolei2018", 
        "name": "novolei2018", 
        "avatar": "https://cdn.v2ex.com/gravatar/420bb79626dd1ff6b724fb7654dcbd2b?s=73&d=retro"
      }, 
      "url": "https://www.v2ex.com/t/932147", 
      "title": "\u6211\u81ea\u5df1\u662f\u521d\u5b66\u8005\u60f3\u627e\u4e2a\u670b\u53cb\u5e26\u6211\u4e00\u8d77\u5199\u4e24\u4e2a\u5de5\u4f5c\u7528\u7684 app \u6709\u507f\u7684", 
      "id": "https://www.v2ex.com/t/932147", 
      "date_published": "2023-04-13T01:55:20+00:00", 
      "content_html": "<p>\u4e3b\u8981\u662f\u6211\u4e2a\u4eba\u5de5\u4f5c\u9700\u8981\u7684\u5de5\u5177\u7f16\u5199\u6211\u81ea\u5df1\u80fd\u529b\u6709\u9650\u4f46\u4e5f\u5199\u4e86\u4e00\u5927\u534a\u4e86 \u5e0c\u671b\u770b\u5230\u7684\u597d\u5fc3\u4eba\u6216\u5927\u4f6c\u53ef\u4ee5\u5e2e\u5fd9\u6307\u5bfc \u6709\u507f\u7684</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/0littleboy", 
        "name": "0littleboy", 
        "avatar": "https://cdn.v2ex.com/avatar/9c6f/fcda/478438_large.png?m=1757388573"
      }, 
      "url": "https://www.v2ex.com/t/932146", 
      "title": "Swift \u5982\u4f55\u4f18\u5316\u6570\u636e\u52a0\u8f7d\u65b9\u5f0f\uff1f", 
      "id": "https://www.v2ex.com/t/932146", 
      "date_published": "2023-04-13T01:53:52+00:00", 
      "content_html": "<p>\u6211\u6709\u4e00\u4e2a\u7528\u4e8e\u8bb0\u5f55\u5168\u5c40\u6570\u636e\u7684\u7c7b</p>\n<pre><code class=\"language-swift\">class GlobalData {\n//    static let shared = GlobalData()\n    // \u4e0d\u4f7f\u7528\u5355\u4f8b\u6a21\u5f0f\uff0c\u6ca1\u6709\u5b9e\u4f8b\uff0c\u76f4\u63a5\u8c03\u7528\u7c7b\n    static var allProblems: [Problem] = getAllProblems()\n    static var allContests: [Contest] = getAllContests()\n}\n</code></pre>\n<p>\u95ee\u9898\u5176\u4e00\u662f\u4f7f\u7528 static \u52a0\u8f7d\u901f\u5ea6\u592a\u6162\u4e86\uff0c\u5fc5\u987b\u7b49\u5176\u52a0\u8f7d\u5b8c\u624d\u80fd\u663e\u793a APP \u7684\u5185\u5bb9</p>\n<p>\u7ed9\u51fa\u5176\u4e2d\u4e00\u4e2a\u8c03\u7528 GlobalData \u7684\u6837\u4f8b</p>\n<pre><code class=\"language-swift\">struct HistoryContestsView: View {\n    @State var contests: [Contest] = GlobalData.allContests\n    @State var allProblems: [Problem] = GlobalData.allProblems\n    \n    var body: some View {\n        NavigationView {\n            // ...\n        }\n        .refreshable {\n            reloadHistoryContests()\n        }\n    }\n    \n    private func reloadHistoryContests() {\n        GlobalData.allProblems = getAllProblems()\n        allProblems = GlobalData.allProblems\n        GlobalData.allContests = getAllContests()\n        contests = GlobalData.allContests\n        print(\"Successfully reload history contests\")\n    }\n}\n</code></pre>\n<p>\u5176\u4e8c\u662f reloadHistoryContests \u5185\u5bb9\u663e\u5f97\u5341\u5206\u5197\u4f59</p>\n<p>\u76ee\u524d\u60f3\u5230\u7684\u7b56\u7565\u662f\u5b9a\u4e49\u4e00\u4e2a ObservableObject \u7c7b\nHistoryContestsView \u5c31\u53ef\u4ee5\u76f4\u63a5\u8ba2\u9605 GlobalData \u7c7b\n\u5e76\u4e14\u5728 .task \u4e2d\u5f02\u6b65\u52a0\u8f7d\u6570\u636e\uff0c\u4e5f\u80fd\u89e3\u51b3\u6027\u80fd\u95ee\u9898</p>\n<pre><code class=\"language-swift\">class GlobalData: ObservableObject {\n    @Published var allProblems: [Problem] = []\n    @Published var allContests: [Contest] = []\n\n    func loadData() {\n        // \u52a0\u8f7d\u6570\u636e\u7684\u4ee3\u7801\n        // ...\n        self.allProblems = getAllProblems()\n        self.allContests = getAllContests()\n    }\n}\n</code></pre>\n<p>\u4f46\u53c8\u51fa\u73b0\u4e86\u4e2a\u95ee\u9898\uff0c\u5728\u5176\u4ed6 model \u6587\u4ef6\u4e2d\uff0c\u539f\u672c\u8c03\u7528 GlobalData.allContests \u7684\u51fd\u6570\uff0c\u90fd\u65e0\u6cd5\u4f7f\u7528\u4e86</p>\n<pre><code class=\"language-swift\">func getPredictiveContestList(by userid: String) -&gt; [User.AttendedContest] {\n        let predictiveContests = Global.allContests.filter {\n            $0.avgRatingOfProblems == nil\n        }\n    //    print(predictiveContests)\n        var res: [User.AttendedContest] = []\n        for contest in predictiveContests {\n            /// \u53c2\u52a0\u4e86\u4e14\u6709\u4e86\u9884\u6d4b\u7ed3\u679c\n            // TODO - \u540e\u9762\u7edf\u8ba1\u53c2\u52a0\u4e86\u8fd8\u6ca1\u6709\u7ed3\u679c\u7684\n            if let tmp = predictRatingOfUser(by: contest.titleSlug, userid: userid) {\n                res.append(tmp)\n            }\n        }\n        \n        return res\n    }\n</code></pre>\n<p>\u5982\u4f55\u89e3\u51b3\uff1f</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/usVexMownCzar", 
        "name": "usVexMownCzar", 
        "avatar": "https://cdn.v2ex.com/avatar/b0b6/208d/209640_large.png?m=1774107477"
      }, 
      "url": "https://www.v2ex.com/t/930584", 
      "title": "\u73b0\u5728\u611f\u89c9 Swift \u771f\u7684\u88ab OC \u62d6\u540e\u817f\u4e86", 
      "id": "https://www.v2ex.com/t/930584", 
      "date_published": "2023-04-07T06:52:17+00:00", 
      "content_html": "<p>\u6700\u8fd1\u63a5\u624b\u4e86\u516c\u53f8\u4e00\u4e2a\u9879\u76ee\uff0c\u770b\u4e86\u51e0\u5929\uff0c\u53d1\u73b0\u4e00\u4e2a\u7528 Swift \u5f00\u53d1\u7684\u9879\u76ee\uff0c\u4f46\u662f\u6240\u6709\u7684\u6570\u7ec4\uff0c\u5b57\u5178\u7c7b\u578b\u7528\u7684\u5168\u662f OC \u4e2d\u7684\u7c7b\u578b\uff0c<code>NSArray</code>\uff0c<code>NSMutableArray</code>\uff0c<code>NSDictionary</code>\uff0c<code>NSMutableDictionary</code>\u3002</p>\n<p>\u6bcf\u6b21\u770b\u5230\u4ece\u8fd9\u4e9b\u7c7b\u578b\u4e2d\u53d6\u503c\u3001\u8bbe\u7f6e\u503c\u90fd\u5f88\u5934\u75bc\uff08\u597d\u51e0\u5e74\u6ca1\u5199 OC \u4e86\uff09\uff1a</p>\n<pre><code>var dict = NSMutableDictionary()\ndict = NSMutableDictionary(dictionary: te as! NSDictionary)\ndict.setValue(\"\\((index as! NSDictionary).object(forKey: \"foo\")!)\", forKey: \"foo\")\n</code></pre>\n<p>\u5b8c\u5168\u4e0d\u4f7f\u7528 <code>Swift</code> \u7684\u8bed\u8a00\u7279\u6027\uff0c\u4e00\u4e9b\u9ad8\u7ea7\u51fd\u6570\u90fd\u65e0\u6cd5\u4f7f\u7528\uff0c\u5173\u952e\u8fd9\u662f\u4e00\u4e2a Swift \u9879\u76ee\u3002</p>\n<p>\u867d\u7136\u5176\u4e2d\u6709\u4e00\u4e9b\u662f\u4ece 16 \u5e74\u5c31\u6709\u7684\u4ee3\u7801\uff0c\u4f46\u662f\u6700\u8fd1\u5f00\u53d1\u7684\u529f\u80fd\u8fd8\u8fd9\u4e48\u505a\uff0c\u5c31\u5f88\u65e0\u8bed\u3002</p>\n<p>\u5c31\u50cf\u662f\u7528 <code>TypeScript</code> \u8fdb\u884c\u9879\u76ee\u5f00\u53d1\uff0c\u4f46\u662f\u6240\u6709\u7684\u7c7b\u578b\u90fd\u662f <code>Any</code> </p>\n<p>\u8bf6\uff0c\u4ec0\u4e48\u65f6\u5019 <code>Swift</code> \u80fd\u628a OC \u8e22\u51fa\u53bb\u5440</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/shindgewongxj", 
        "name": "shindgewongxj", 
        "avatar": "https://cdn.v2ex.com/avatar/c21b/ce80/467781_large.png?m=1762238076"
      }, 
      "url": "https://www.v2ex.com/t/929149", 
      "title": "\u671f\u5f85\u5404\u4f4d Swiftor \u7684\u52a0\u5165\uff01", 
      "id": "https://www.v2ex.com/t/929149", 
      "date_published": "2023-04-02T04:56:49+00:00", 
      "content_html": "<p>\u4e3a\u4e86\u65b9\u4fbf\u8ba8\u8bba Swift \u5f00\u53d1\u76f8\u5173\u7684\u95ee\u9898\uff0c\u5728 Telegeram \u4e0a\u521b\u5efa\u4e86\u4e00\u4e2a\u7fa4\u7ec4\uff01<br/>\n\u671f\u5f85\u5404\u4f4d\u7684\u52a0\u5165\uff01<br/>\n<a href=\"https://t.me/swiftorsgroup\" rel=\"nofollow\">\u94fe\u63a5</a></p>\n"
    }
  ]
}