{"id":4783,"date":"2021-12-26T09:31:05","date_gmt":"2021-12-26T01:31:05","guid":{"rendered":"http:\/\/123.57.164.21\/?p=4783"},"modified":"2021-12-26T09:31:05","modified_gmt":"2021-12-26T01:31:05","slug":"attributedstring-%e4%b8%8d%e4%bb%85%e4%bb%85%e8%ae%a9%e6%96%87%e5%ad%97%e6%9b%b4%e6%bc%82%e4%ba%ae","status":"publish","type":"post","link":"https:\/\/92it.top\/?p=4783","title":{"rendered":"AttributedString\u2014\u2014\u4e0d\u4ec5\u4ec5\u8ba9\u6587\u5b57\u66f4\u6f02\u4eae"},"content":{"rendered":"\n<p>\u5728 WWDC 2021 \u4e0a\uff0c\u82f9\u679c\u4e3a\u5f00\u53d1\u8005\u5e26\u6765\u4e86\u6709\u4e00\u4e2a\u671f\u5f85\u5df2\u4e45\u7684\u529f\u80fd\u2014\u2014AttributedString\uff0c\u8fd9\u610f\u5473\u7740 Swift \u5f00\u53d1\u4eba\u5458\u4e0d\u518d\u9700\u8981\u4f7f\u7528\u57fa\u4e8e Objective-C \u7684 NSAttributedString \u6765\u521b\u5efa\u6837\u5f0f\u5316\u6587\u672c\u3002\u672c\u6587\u5c06\u5bf9\u5176\u505a\u5168\u9762\u7684\u4ecb\u7ecd\u5e76\u6f14\u793a\u5982\u4f55\u521b\u5efa\u81ea\u5b9a\u4e49\u5c5e\u6027\u3002<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">\u521d\u6b65\u5370\u8c61<\/h5>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>AttributedString \u662f\u5177\u6709\u5355\u4e2a\u5b57\u7b26\u6216\u5b57\u7b26\u8303\u56f4\u7684\u5c5e\u6027\u7684\u5b57\u7b26\u4e32\u3002\u5c5e\u6027\u63d0\u4f9b\u4e86\u4e00\u4e9b\u7279\u5f81\uff0c\u5982\u7528\u4e8e\u663e\u793a\u7684\u89c6\u89c9\u98ce\u683c\u3001\u7528\u4e8e\u65e0\u969c\u788d\u5f15\u5bfc\u4ee5\u53ca\u7528\u4e8e\u5728\u6570\u636e\u6e90\u4e4b\u95f4\u8fdb\u884c\u94fe\u63a5\u7684\u8d85\u94fe\u63a5\u6570\u636e\u7b49\u3002<\/p>\n\n\n\n<p>\u4e0b\u9762\u7684\u4ee3\u7801\u5c06\u751f\u6210\u4e00\u4e2a\u5305\u542b\u7c97\u4f53\u4ee5\u53ca\u8d85\u94fe\u63a5\u7684\u5c5e\u6027\u5b57\u7b26\u4e32\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var attributedString = AttributedString(\"\u8bf7\u8bbf\u95ee\u8098\u5b50\u7684\u535a\u5ba2\")\nlet zhouzi = attributedString.range(of: \"\u8098\u5b50\")!  \/\/ \u83b7\u53d6\u8098\u5b50\u4e8c\u5b57\u7684\u8303\u56f4\uff08Range\uff09\nattributedString[zhouzi].inlinePresentationIntent = .stronglyEmphasized \/\/ \u8bbe\u7f6e\u5c5e\u6027\u2014\u2014\u7c97\u4f53\nlet blog = attributedString.range(of: \"\u535a\u5ba2\")! \nattributedString[blog].link = URL(string: \"https:\/\/www.fatbobman.com\")! \/\/ \u8bbe\u7f6e\u5c5e\u6027\u2014\u2014\u8d85\u94fe\u63a5\n<\/pre>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2021\/12\/image-261-1024x138.png\" alt=\"\" class=\"wp-image-4784\" width=\"464\" height=\"62\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-261-1024x138.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-261-300x40.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-261-768x103.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-261-830x112.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-261-230x31.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-261-350x47.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-261-480x65.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-261.png 1130w\" sizes=\"(max-width: 464px) 100vw, 464px\" \/><\/figure><\/div>\n\n\n\n<p>\u5728 WWDC 2021 \u4e4b\u524d\uff0cSwiftUI \u6ca1\u6709\u63d0\u4f9b\u5bf9\u5c5e\u6027\u5b57\u7b26\u4e32\u7684\u652f\u6301\uff0c\u5982\u679c\u6211\u4eec\u5e0c\u671b\u663e\u793a\u5177\u6709\u4e30\u5bcc\u6837\u5f0f\u7684\u6587\u672c\uff0c\u901a\u5e38\u4f1a\u91c7\u7528\u4ee5\u4e0b\u4e09\u79cd\u65b9\u5f0f\uff1a<\/p>\n\n\n\n<ul><li>\u5c06 UIKit \u6216 AppKit \u63a7\u4ef6\u5305\u88c5\u6210 SwiftUI \u63a7\u4ef6\uff0c\u5728\u5176\u4e2d\u663e\u793a NSAttributedString<\/li><li>\u901a\u8fc7\u4ee3\u7801\u5c06 NSAttributedString \u8f6c\u6362\u6210\u5bf9\u5e94\u7684 SwiftUI \u5e03\u5c40\u4ee3\u7801<\/li><li>\u4f7f\u7528 SwiftUI \u7684\u539f\u751f\u63a7\u4ef6\u7ec4\u5408\u663e\u793a<\/li><\/ul>\n\n\n\n<p>\u4e0b\u9762\u7684\u6587\u5b57\u968f\u7740 SwiftUI \u7248\u672c\u7684\u53d8\u5316\uff0c\u53ef\u91c7\u53d6\u7684\u624b\u6bb5\u4e5f\u5728\u4e0d\u65ad\u5730\u589e\u52a0\uff08\u4e0d\u4f7f\u7528 NSAttributedString\uff09\uff1a<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2021\/12\/image-262-1024x117.png\" alt=\"\" class=\"wp-image-4785\" width=\"471\" height=\"53\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-262-1024x117.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-262-300x34.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-262-768x87.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-262-830x95.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-262-230x26.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-262-350x40.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-262-480x55.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-262.png 1124w\" sizes=\"(max-width: 471px) 100vw, 471px\" \/><\/figure><\/div>\n\n\n\n<p><strong><em>SwiftUI 1.0<\/em><\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> @ViewBuilder\n    var helloView:some View{\n        HStack(alignment:.lastTextBaseline, spacing:0){\n            Text(\"Hello\").font(.title).foregroundColor(.red)\n            Text(\" world\").font(.callout).foregroundColor(.cyan)\n        }\n    }<\/pre>\n\n\n\n<p><strong><em>SwiftUI 2.0<\/em><\/strong><\/p>\n\n\n\n<p>SwiftUI 2.0 \u589e\u5f3a\u4e86 Text \u7684\u529f\u80fd\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u4e0d\u540c\u7684 Text \u901a\u8fc7<code>+<\/code>\u5408\u5e76\u663e\u793a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> var helloText:Text {\n        Text(\"Hello\").font(.title).foregroundColor(.red) + Text(\" world\").font(.callout).foregroundColor(.cyan)\n    }<\/pre>\n\n\n\n<p><strong><em>SwiftUI 3.0<\/em><\/strong><\/p>\n\n\n\n<p>\u9664\u4e86\u4e0a\u8ff0\u7684\u65b9\u6cd5\u5916\uff0cText \u6dfb\u52a0\u4e86\u5bf9 AttributedString \u7684\u539f\u751f\u652f\u6301<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">  var helloAttributedString:AttributedString {\n        var hello = AttributedString(\"Hello\")\n        hello.font = .title.bold()\n        hello.foregroundColor = .red\n        var world = AttributedString(\" world\")\n        world.font = .callout\n        world.foregroundColor = .cyan\n        return hello + world\n    }\n\n    Text(helloAttributedString)<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>\u5355\u7eaf\u770b\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u5e76\u4e0d\u80fd\u770b\u5230 AttributedString \u6709\u4ec0\u4e48\u4f18\u52bf\u3002\u76f8\u4fe1\u968f\u7740\u7ee7\u7eed\u9605\u8bfb\u672c\u6587\uff0c\u4f60\u4f1a\u53d1\u73b0 AttributedString \u53ef\u4ee5\u5b9e\u73b0\u592a\u591a\u4ee5\u524d\u60f3\u505a\u800c\u65e0\u6cd5\u505a\u5230\u7684\u529f\u80fd\u548c\u6548\u679c\u3002<\/p><\/blockquote>\n\n\n\n<h5 class=\"wp-block-heading\">AttributedString vs NSAttributedString<\/h5>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>AttributedString \u57fa\u672c\u4e0a\u53ef\u4ee5\u770b\u4f5c\u662f NSAttributedString \u7684 Swift \u5b9e\u73b0\uff0c\u4e24\u8005\u5728\u529f\u80fd\u548c\u5185\u5728\u903b\u8f91\u4e0a\u5dee\u522b\u4e0d\u5927\u3002\u4f46\u7531\u4e8e\u5f62\u6210\u5e74\u4ee3\u3001\u6838\u5fc3\u4ee3\u7801\u8bed\u8a00\u7b49\uff0c\u4e24\u8005\u4e4b\u95f4\u4ecd\u6709\u4e0d\u5c11\u7684\u533a\u522b\u3002\u672c\u8282\u5c06\u4ece\u591a\u4e2a\u65b9\u9762\u5bf9\u5b83\u4eec\u8fdb\u884c\u6bd4\u8f83\u3002<\/p>\n\n\n\n<p>AttributedString \u662f\u503c\u7c7b\u578b\u7684\uff0c\u8fd9\u4e5f\u662f\u5b83\u540c\u7531 Objective-C \u6784\u5efa\u7684 NSAttributedString\uff08\u5f15\u7528\u7c7b\u578b\uff09\u4e4b\u95f4\u6700\u5927\u7684\u533a\u522b\u3002\u8fd9\u610f\u5473\u7740\u5b83\u53ef\u4ee5\u901a\u8fc7 Swift \u7684\u503c\u8bed\u4e49\uff0c\u50cf\u5176\u4ed6\u503c\u4e00\u6837\u88ab\u4f20\u9012\u3001\u590d\u5236\u548c\u6539\u53d8\u3002<\/p>\n\n\n\n<p>NSAttributedString \u53ef\u53d8\u6216\u4e0d\u53ef\u53d8\u9700\u4e0d\u540c\u7684\u5b9a\u4e49<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">let hello = NSMutableAttributedString(\"hello\")\nlet world = NSAttributedString(\" world\")\nhello.append(world)<\/pre>\n\n\n\n<p>AttributedString<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var hello = AttributedString(\"hello\")\nlet world = AttributedString(\" world\")\nhello.append(world)\n<\/pre>\n\n\n\n<ul><li><strong>\u5b89\u5168\u6027<\/strong><\/li><\/ul>\n\n\n\n<p>\u5728 AttributedString \u4e2d\u9700\u8981\u4f7f\u7528 Swift \u7684\u70b9\u6216\u952e\u8bed\u6cd5\u6309\u540d\u79f0\u8bbf\u95ee\u5c5e\u6027\uff0c\u4e0d\u4ec5\u53ef\u4ee5\u4fdd\u8bc1\u7c7b\u578b\u5b89\u5168\uff0c\u800c\u4e14\u53ef\u4ee5\u83b7\u5f97\u7f16\u8bd1\u65f6\u68c0\u67e5\u7684\u4f18\u52bf\u3002<\/p>\n\n\n\n<p>AttributedString \u4e2d\u57fa\u672c\u4e0d\u91c7\u7528 NSAttributedString \u5982\u4e0b\u7684\u5c5e\u6027\u8bbf\u95ee\u65b9\u5f0f\uff0c\u6781\u5927\u7684\u51cf\u5c11\u51fa\u9519\u51e0\u7387<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u53ef\u80fd\u51fa\u73b0\u7c7b\u578b\u4e0d\u5339\u914d\nlet attributes: [NSAttributedString.Key: Any] = [\n    .font: UIFont.systemFont(ofSize: 72),\n    .foregroundColor: UIColor.white,\n]\n<\/pre>\n\n\n\n<ul><li><strong>\u672c\u5730\u5316\u652f\u6301<\/strong><\/li><\/ul>\n\n\n\n<p>Attributed \u63d0\u4f9b\u4e86\u539f\u751f\u7684\u672c\u5730\u5316\u5b57\u7b26\u4e32\u652f\u6301\uff0c\u5e76\u53ef\u4e3a\u672c\u5730\u5316\u5b57\u7b26\u4e32\u6dfb\u52a0\u4e86\u7279\u5b9a\u5c5e\u6027\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var localizableString = AttributedString(localized: \"Hello \\(Date.now,format: .dateTime) world\",locale: Locale(identifier: \"zh-cn\"),option:.applyReplacementIndexAttribute)\n<\/pre>\n\n\n\n<ul><li><strong>Formatter \u652f\u6301<\/strong><\/li><\/ul>\n\n\n\n<p>\u540c\u4e3a WWDC 2021 \u4e2d\u63a8\u51fa\u7684\u65b0 Formatter API \u5168\u9762\u652f\u6301\u4e86 AttributedString \u7c7b\u578b\u7684\u683c\u5f0f\u5316\u8f93\u51fa\u3002\u6211\u4eec\u53ef\u4ee5\u8f7b\u677e\u5b9e\u73b0\u8fc7\u53bb\u65e0\u6cd5\u5b8c\u6210\u7684\u5de5\u4f5c\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var dateString: AttributedString {\n        var attributedString = Date.now.formatted(.dateTime\n            .hour()\n            .minute()\n            .weekday()\n            .attributed\n        )\n        let weekContainer = AttributeContainer()\n            .dateField(.weekday)\n        let colorContainer = AttributeContainer()\n            .foregroundColor(.red)\n        attributedString.replaceAttributes(weekContainer, with: colorContainer)\n        return attributedString\n}\n\nText(dateString)\n<\/pre>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2021\/12\/image-263-1024x155.png\" alt=\"\" class=\"wp-image-4789\" width=\"529\" height=\"80\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-263-1024x155.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-263-300x45.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-263-768x116.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-263-830x126.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-263-230x35.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-263-350x53.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-263-480x73.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-263.png 1122w\" sizes=\"(max-width: 529px) 100vw, 529px\" \/><\/figure><\/div>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>\u66f4\u591a\u5173\u4e8e\u65b0 Formatter API \u540c AttributedString \u914d\u5408\u8303\u4f8b\uff0c\u8bf7\u53c2\u9605\u00a0<a href=\"https:\/\/www.fatbobman.com\/posts\/newFormatter\/\">WWDC 2021 \u65b0 Formatter API\uff1a\u65b0\u8001\u6bd4\u8f83\u53ca\u5982\u4f55\u81ea\u5b9a\u4e49<\/a><\/p><\/blockquote>\n\n\n\n<ul><li><strong>SwiftUI \u96c6\u6210<\/strong><\/li><\/ul>\n\n\n\n<p>SwiftUI \u7684 Text \u7ec4\u4ef6\u63d0\u4f9b\u4e86\u5bf9 AttributedString \u7684\u539f\u751f\u652f\u6301\uff0c\u6539\u5584\u4e86\u4e00\u4e2a SwiftUI \u7684\u957f\u671f\u75db\u70b9\uff08\u4e0d\u8fc7 TextField\u3001TextEdit \u4ecd\u4e0d\u652f\u6301\uff09\u3002<\/p>\n\n\n\n<p>AttributedString \u540c\u65f6\u63d0\u4f9b\u4e86 SwiftUI\u3001UIKit\u3001AppKit \u4e09\u79cd\u6846\u67b6\u7684\u53ef\u7528\u5c5e\u6027\u3002UIKit \u6216 AppKit \u7684\u63a7\u4ef6\u540c\u6837\u53ef\u4ee5\u6e32\u67d3 AttributedString\uff08\u9700\u7ecf\u8fc7\u8f6c\u6362\uff09\u3002<\/p>\n\n\n\n<ul><li><strong>\u652f\u6301\u7684\u6587\u4ef6\u683c\u5f0f<\/strong><\/li><\/ul>\n\n\n\n<p>AttributedString \u76ee\u524d\u4ec5\u5177\u5907\u5bf9 Markdown \u683c\u5f0f\u6587\u672c\u8fdb\u884c\u89e3\u6790\u7684\u80fd\u529b\u3002\u540c NSAttributedString \u652f\u6301 Markdown\u3001rtf\u3001doc\u3001HTML \u76f8\u6bd4\u4ecd\u6709\u5f88\u5927\u5dee\u8ddd\u3002<\/p>\n\n\n\n<ul><li><strong>\u8f6c\u6362<\/strong><\/li><\/ul>\n\n\n\n<p>\u82f9\u679c\u4e3a AttributedString \u548c NSAttributedString \u63d0\u4f9b\u4e86\u76f8\u4e92\u8f6c\u6362\u7684\u80fd\u529b\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ AttributedString -> NSAttributedString\nlet nsString = NSMutableAttributedString(\"hello\")\nvar attributedString = AttributedString(nsString)\n\n\/\/ NSAttribuedString -> AttributedString\nvar attString = AttributedString(\"hello\")\nattString.uiKit.foregroundColor = .red\nlet nsString1 = NSAttributedString(attString)\n<\/pre>\n\n\n\n<p>\u5f00\u53d1\u8005\u53ef\u4ee5\u5145\u5206\u5229\u7528\u4e24\u8005\u5404\u81ea\u7684\u4f18\u52bf\u8fdb\u884c\u5f00\u53d1\u3002\u6bd4\u5982\uff1a<\/p>\n\n\n\n<ul><li>\u7528 NSAttributedString \u89e3\u6790 HTML\uff0c\u7136\u540e\u8f6c\u6362\u6210 AttributedString \u8c03\u7528<\/li><li>\u7528 AttributedString \u521b\u5efa\u7c7b\u578b\u5b89\u5168\u7684\u5b57\u7b26\u4e32\uff0c\u5728\u663e\u793a\u65f6\u8f6c\u6362\u6210 NSAttributedString<\/li><\/ul>\n\n\n\n<h5 class=\"wp-block-heading\">\u57fa\u7840<\/h5>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>\u672c\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u5bf9 AttributedString \u4e2d\u7684\u4e00\u4e9b\u91cd\u8981\u6982\u5ff5\u505a\u4ecb\u7ecd\uff0c\u5e76\u901a\u8fc7\u4ee3\u7801\u7247\u6bb5\u5c55\u793a AttributedString \u66f4\u591a\u7684\u7528\u6cd5\u3002<\/p>\n\n\n\n<ul><li><strong>AttributedStringKey<\/strong><\/li><\/ul>\n\n\n\n<p>AttributedStringKey \u5b9a\u4e49\u4e86 AttributedString \u5c5e\u6027\u540d\u79f0\u548c\u7c7b\u578b\u3002\u901a\u8fc7\u70b9\u8bed\u6cd5\u6216 KeyPath\uff0c\u5728\u4fdd\u8bc1\u7c7b\u578b\u5b89\u5168\u7684\u524d\u63d0\u8fdb\u884c\u5feb\u6377\u8bbf\u95ee\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var string = AttributedString(\"hello world\")\n\/\/ \u4f7f\u7528\u70b9\u8bed\u6cd5\nstring.font = .callout\nlet font = string.font \n\n\/\/ \u4f7f\u7528 KeyPath\nlet font = string[keyPath:\\.font] \n<\/pre>\n\n\n\n<p>\u9664\u4e86\u4f7f\u7528\u7cfb\u7edf\u9884\u7f6e\u7684\u5927\u91cf\u5c5e\u6027\u5916\uff0c\u6211\u4eec\u4e5f\u53ef\u4ee5\u521b\u5efa\u81ea\u5df1\u7684\u5c5e\u6027\u3002\u4f8b\u5982\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">enum OutlineColorAttribute : AttributedStringKey {\n    typealias Value = Color \/\/ \u5c5e\u6027\u7c7b\u578b\n    static let name = \"OutlineColor\" \/\/ \u5c5e\u6027\u540d\u79f0\n}\n\nstring.outlineColor = .blue\n<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u70b9\u8bed\u6cd5\u6216 KeyPath \u5bf9 AttributedString\u3001AttributedSubString\u3001AttributeContainer \u4ee5\u53ca AttributedString.Runs.Run \u7684\u5c5e\u6027\u8fdb\u884c\u8bbf\u95ee\u3002\u66f4\u591a\u7528\u6cd5\u53c2\u7167\u672c\u6587\u5176\u4ed6\u7684\u4ee3\u7801\u7247\u6bb5\u3002<\/p><\/blockquote>\n\n\n\n<ul><li><strong>AttributeContainer<\/strong><\/li><\/ul>\n\n\n\n<p>AttributeContainer \u662f\u5c5e\u6027\u5bb9\u5668\u3002\u901a\u8fc7\u914d\u7f6e container\uff0c\u6211\u4eec\u53ef\u4ee5\u4e00\u6b21\u6027\u5730\u4e3a\u5c5e\u6027\u5b57\u7b26\u4e32\uff08\u6216\u7247\u6bb5\uff09\u8bbe\u7f6e\u3001\u66ff\u6362\u3001\u5408\u5e76\u5927\u91cf\u7684\u5c5e\u6027\u3002<\/p>\n\n\n\n<p><strong><em>\u8bbe\u7f6e\u5c5e\u6027<\/em><\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var attributedString = AttributedString(\"Swift\")\nstring.foregroundColor = .red \n\nvar container = AttributeContainer()\ncontainer.inlinePresentationIntent = .strikethrough\ncontainer.font = .caption\ncontainer.backgroundColor = .pink\ncontainer.foregroundColor = .green \/\/\u5c06\u8986\u76d6\u539f\u6765\u7684 red\n\nattributedString.setAttributes(container) \/\/ attributdString \u6b64\u65f6\u62e5\u6709\u56db\u4e2a\u5c5e\u6027\u5185\u5bb9\n<\/pre>\n\n\n\n<p><strong><em>\u66ff\u6362\u5c5e\u6027<\/em><\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var container = AttributeContainer()\ncontainer.inlinePresentationIntent = .strikethrough\ncontainer.font = .caption\ncontainer.backgroundColor = .pink\ncontainer.foregroundColor = .green\nattributedString.setAttributes(container)\n\/\/ \u6b64\u65f6 attributedString \u6709\u56db\u4e2a\u5c5e\u6027\u5185\u5bb9 font\u3001backgroundColor\u3001foregroundColor\u3001inlinePresentationIntent\n\n\/\/ \u88ab\u66ff\u6362\u7684\u5c5e\u6027\nvar container1 = AttributeContainer()\ncontainer1.foregroundColor = .green\ncontainer1.font = .caption\n\n\/\/ \u5c06\u8981\u66ff\u6362\u7684\u5c5e\u6027\nvar container2 = AttributeContainer()\ncontainer2.link = URL(string: \"https:\/\/www.swift.org\")\n\n\/\/ \u88ab\u66ff\u6362\u5c5e\u6027 contianer1 \u7684\u5c5e\u6027\u952e\u503c\u5185\u5bb9\u5168\u90e8\u7b26\u5408\u624d\u53ef\u66ff\u6362\uff0c\u6bd4\u5982 continaer1 \u7684 foregroundColor \u4e3a\u3002red \u5c06\u4e0d\u8fdb\u884c\u66ff\u6362\nattributedString.replaceAttributes(container1, with: container2)\n\/\/ \u66ff\u6362\u540e attributedString \u6709\u4e09\u4e2a\u5c5e\u6027\u5185\u5bb9 backgroundColor\u3001inlinePresentationIntent\u3001link\n<\/pre>\n\n\n\n<p><strong><em>\u5408\u5e76\u5c5e\u6027<\/em><\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var container = AttributeContainer()\ncontainer.inlinePresentationIntent = .strikethrough\ncontainer.font = .caption\ncontainer.backgroundColor = .pink\ncontainer.foregroundColor = .green\nattributedString.setAttributes(container)\n\/\/ \u6b64\u65f6 attributedString \u6709\u56db\u4e2a\u5c5e\u6027\u5185\u5bb9 font\u3001backgroundColor\u3001foregroundColor\u3001inlinePresentationIntent\n\nvar container2 = AttributeContainer()\ncontainer2.foregroundColor = .red\ncontainer2.link = URL(string: \"www.swift.org\")\n\nattributedString.mergeAttributes(container2,mergePolicy: .keepNew)\n\/\/ \u5408\u5e76\u540e attributedString \u6709\u4e94\u4e2a\u5c5e\u6027 \uff0cfont\u3001backgroundColor\u3001foregroundColor\u3001inlinePresentationIntent \u53ca link \n\/\/ foreground \u4e3a\u3002red\n\/\/ \u5c5e\u6027\u51b2\u7a81\u65f6\uff0c\u901a\u8fc7 mergePolicy \u9009\u62e9\u5408\u5e76\u7b56\u7565 .keepNew\uff08\u9ed8\u8ba4\uff09 \u6216 .keepCurrent\n<\/pre>\n\n\n\n<ul><li><strong>AttributeScope<\/strong><\/li><\/ul>\n\n\n\n<p>\u5c5e\u6027\u8303\u56f4\u662f\u7cfb\u7edf\u6846\u67b6\u5b9a\u4e49\u7684\u5c5e\u6027\u96c6\u5408\uff0c\u5c06\u9002\u5408\u67d0\u4e2a\u7279\u5b9a\u57df\u4e2d\u7684\u5c5e\u6027\u5b9a\u4e49\u5728\u4e00\u4e2a\u8303\u56f4\u5185\uff0c\u4e00\u65b9\u9762\u4fbf\u4e8e\u7ba1\u7406\uff0c\u53e6\u4e00\u65b9\u9762\u4e5f\u89e3\u51b3\u4e86\u4e0d\u540c\u6846\u67b6\u4e0b\u76f8\u540c\u5c5e\u6027\u540d\u79f0\u5bf9\u5e94\u7c7b\u578b\u4e0d\u4e00\u81f4\u7684\u95ee\u9898\u3002<\/p>\n\n\n\n<p>\u76ee\u524d\uff0cAttributedString \u63d0\u4f9b\u4e86 5 \u4e2a\u9884\u7f6e\u7684 Scope\uff0c\u5206\u522b\u4e3a<\/p>\n\n\n\n<ul><li>foundation<\/li><\/ul>\n\n\n\n<p>\u5305\u542b\u6709\u5173 Formatter\u3001Markdown\u3001URL \u4ee5\u53ca\u8bed\u8a00\u53d8\u5f62\u65b9\u9762\u7684\u5c5e\u6027<\/p>\n\n\n\n<ul><li>swiftUI<\/li><\/ul>\n\n\n\n<p>\u53ef\u4ee5\u5728 SwiftUI \u4e0b\u88ab\u6e32\u67d3\u7684\u5c5e\u6027\uff0c\u4f8b\u5982 foregroundColor\u3001backgroundColor\u3001font \u7b49\u3002\u76ee\u524d\u652f\u6301\u7684\u5c5e\u6027\u660e\u663e\u5c11\u4e8e uiKit \u548c appKit\u3002\u4f30\u8ba1\u5f85\u65e5\u540e SwiftUI \u63d0\u4f9b\u66f4\u591a\u7684\u663e\u793a\u652f\u6301\u540e\u4f1a\u9010\u6b65\u8865\u4e0a\u5176\u4ed6\u6682\u4e0d\u652f\u6301\u7684\u5c5e\u6027\u3002<\/p>\n\n\n\n<ul><li>uiKit<\/li><\/ul>\n\n\n\n<p>\u53ef\u4ee5\u5728 UIKit \u4e0b\u88ab\u6e32\u67d3\u7684\u5c5e\u6027\u3002<\/p>\n\n\n\n<ul><li>appKit<\/li><\/ul>\n\n\n\n<p>\u53ef\u4ee5\u5728 AppKit \u4e0b\u88ab\u6e32\u67d3\u7684\u5c5e\u6027<\/p>\n\n\n\n<ul><li>accessibility<\/li><\/ul>\n\n\n\n<p>\u9002\u7528\u4e8e\u65e0\u969c\u788d\u7684\u5c5e\u6027\uff0c\u7528\u4e8e\u63d0\u9ad8\u5f15\u5bfc\u8bbf\u95ee\u7684\u53ef\u7528\u6027\u3002<\/p>\n\n\n\n<p>\u5728 swiftUI\u3001uiKit \u548c appKit \u4e09\u4e2a scope \u4e2d\u5b58\u5728\u5f88\u591a\u7684\u540c\u540d\u5c5e\u6027\uff08\u6bd4\u5982 foregroundColor\uff09\uff0c\u5728\u8bbf\u95ee\u65f6\u9700\u6ce8\u610f\u4ee5\u4e0b\u51e0\u70b9\uff1a<\/p>\n\n\n\n<ul><li>\u5f53 Xcode \u65e0\u6cd5\u6b63\u786e\u63a8\u65ad\u8be5\u9002\u7528\u54ea\u4e2a Scope \u4e2d\u7684\u5c5e\u6027\u65f6\uff0c\u8bf7\u663e\u5f0f\u6807\u660e\u5bf9\u5e94\u7684 AttributeScope<\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">uiKitString.uiKit.foregroundColor = .red \/\/UIColor\nappKitString.appKit.backgroundColor = .yellow \/\/NSColor<\/pre>\n\n\n\n<ul><li>\u4e09\u4e2a\u6846\u67b6\u7684\u540c\u540d\u5c5e\u6027\u5e76\u4e0d\u80fd\u4e92\u8f6c\uff0c\u5982\u60f3\u5b57\u7b26\u4e32\u540c\u65f6\u652f\u6301\u591a\u6846\u67b6\u663e\u793a\uff08\u4ee3\u7801\u590d\u7528\uff09\uff0c\u8bf7\u5206\u522b\u4e3a\u4e0d\u540c Scope \u7684\u540c\u540d\u5c5e\u6027\u8d4b\u503c<\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">attributedString.swiftUI.foregroundColor = .red\nattributedString.uiKit.foregroundColor = .red\nattributedString.appKit.foregroundColor = .red\n\n\/\/ \u8f6c\u6362\u6210 NSAttributedString\uff0c\u53ef\u4ee5\u53ea\u8f6c\u6362\u6307\u5b9a\u7684 Scope \u5c5e\u6027\nlet nsString = try! NSAttributedString(attributedString, including: \\.uiKit)\n<\/pre>\n\n\n\n<ul><li>\u4e3a\u4e86\u63d0\u9ad8\u517c\u5bb9\u6027\uff0c\u90e8\u5206\u529f\u80fd\u76f8\u540c\u7684\u5c5e\u6027\uff0c\u53ef\u4ee5\u5728 foundation \u4e2d\u8bbe\u7f6e\u3002<\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">attributedString.inlinePresentationIntent = .stronglyEmphasized \/\/\u76f8\u5f53\u4e8e bold\n<\/pre>\n\n\n\n<ul><li>swiftUI\u3001uiKit \u548c appKit \u4e09\u4e2a Scope \u5728\u5b9a\u4e49\u65f6\uff0c\u90fd\u5df2\u7ecf\u5206\u522b\u5305\u542b\u4e86 foundation \u548c accessibility\u3002\u56e0\u6b64\u5728\u8f6c\u6362\u65f6\u5373\u4f7f\u53ea\u6307\u5b9a\u5355\u4e00\u6846\u67b6\uff0cfoundation \u548c accessibility \u7684\u5c5e\u6027\u4e5f\u5747\u53ef\u6b63\u5e38\u8f6c\u6362\u3002\u6211\u4eec\u5728\u81ea\u5b9a\u4e49 Scope \u65f6\uff0c\u6700\u597d\u4e5f\u9075\u5b88\u8be5\u539f\u5219\u3002<\/li><\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">let nsString = try! NSAttributedString(attributedString, including: \\.appKit)\n\/\/ attributedString \u4e2d\u5c5e\u4e8e foundation \u548c accessibility \u7684\u5c5e\u6027\u4e5f\u5c06\u4e00\u5e76\u88ab\u8f6c\u6362<\/pre>\n\n\n\n<ul><li><strong>\u89c6\u56fe<\/strong><\/li><\/ul>\n\n\n\n<p>\u5728\u5c5e\u6027\u5b57\u7b26\u4e32\u4e2d\uff0c\u5c5e\u6027\u548c\u6587\u672c\u53ef\u4ee5\u88ab\u72ec\u7acb\u8bbf\u95ee\uff0cAttributedString \u63d0\u4f9b\u4e86\u4e09\u79cd\u89c6\u56fe\u65b9\u4fbf\u5f00\u53d1\u8005\u4ece\u53e6\u4e00\u4e2a\u7ef4\u5ea6\u8bbf\u95ee\u6240\u9700\u7684\u5185\u5bb9\u3002<\/p>\n\n\n\n<p id=\"Character_\u548c_unicodeScalar_\u89c6\u56fe\"><strong>Character \u548c unicodeScalar \u89c6\u56fe<\/strong><\/p>\n\n\n\n<p>\u8fd9\u4e24\u4e2a\u89c6\u56fe\u63d0\u4f9b\u4e86\u7c7b\u4f3c NSAttributedString \u7684 string \u5c5e\u6027\u7684\u529f\u80fd\uff0c\u8ba9\u5f00\u53d1\u8005\u53ef\u4ee5\u5728\u7eaf\u6587\u672c\u7684\u7ef4\u5ea6\u64cd\u4f5c\u6570\u636e\u3002\u4e24\u4e2a\u89c6\u56fe\u7684\u552f\u4e00\u533a\u522b\u662f\u7c7b\u578b\u4e0d\u540c\uff0c\u7b80\u5355\u6765\u8bf4\uff0c\u4f60\u53ef\u4ee5\u628a ChareacterView \u770b\u4f5c\u662f Charecter \u96c6\u5408\uff0c\u800c UnicodeScalarView \u770b\u4f5c\u662f Unicode \u6807\u91cf\u5408\u96c6\u3002<\/p>\n\n\n\n<p>\u5b57\u7b26\u4e32\u957f\u5ea6<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var attributedString = AttributedString(\"Swift\")\nattributedString.characters.count \/\/ 5\n<\/pre>\n\n\n\n<p>\u957f\u5ea6 2<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">let attributedString = AttributedString(\"hello \ud83d\udc69\ud83c\udffd\u200d\ud83e\uddb3\")\nattributedString.characters.count \/\/ 7\nattributedString.unicodeScalars.count \/\/ 10\n<\/pre>\n\n\n\n<p>\u8f6c\u6362\u6210\u5b57\u7b26\u4e32<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">String(attributedString.characters) \/\/ \"Swift\"\n<\/pre>\n\n\n\n<p>\u66ff\u6362\u5b57\u7b26\u4e32<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var attributedString = AttributedString(\"hello world\")\nlet range = attributedString.range(of: \"hello\")!\nattributedString.characters.replaceSubrange(range, with: \"good\")\n\/\/ good world , \u66ff\u6362\u540e\u7684 good \u4ecd\u4f1a\u4fdd\u7559 hello \u6240\u5728\u4f4d\u7f6e\u7684\u6240\u6709\u5c5e\u6027\n<\/pre>\n\n\n\n<ul><li><strong>Runs \u89c6\u56fe<\/strong><\/li><\/ul>\n\n\n\n<p>AttributedString \u7684\u5c5e\u6027\u89c6\u56fe\u3002\u6bcf\u4e2a Run \u5bf9\u5e94\u4e00\u4e2a\u5c5e\u6027\u5b8c\u5168\u4e00\u81f4\u7684\u5b57\u7b26\u4e32\u7247\u6bb5\u3002\u7528 for-in \u8bed\u6cd5\u6765\u8fed\u4ee3 AttributedString \u7684 runs \u5c5e\u6027\u3002<\/p>\n\n\n\n<p><strong><em>\u53ea\u6709\u4e00\u4e2a Run<\/em><\/strong><\/p>\n\n\n\n<p>\u6574\u4e2a\u5c5e\u6027\u5b57\u7b26\u4e32\u4e2d\u6240\u6709\u7684\u5b57\u7b26\u5c5e\u6027\u90fd\u4e00\u81f4<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">let attributedString = AttribuedString(\"Core Data\")\nprint(attributedString)\n\/\/ Core Data {}\nprint(attributedString.runs.count) \/\/ 1<\/pre>\n\n\n\n<p><strong><em>\u4e24\u4e2a Run<\/em><\/strong><\/p>\n\n\n\n<p>\u5c5e\u6027\u5b57\u7b26\u4e32<code>coreData<\/code>\uff0c<code>Core<\/code>\u548c<code>\u00a0Data<\/code>\u4e24\u4e2a\u7247\u6bb5\u7684\u5c5e\u6027\u4e0d\u76f8\u540c\uff0c\u56e0\u6b64\u4ea7\u751f\u4e86\u4e24\u4e2a Run<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var coreData = AttributedString(\"Core\")\ncoreData.font = .title\ncoreData.foregroundColor = .green\ncoreData.append(AttributedString(\" Data\"))\n\nfor run in coreData.runs { \/\/runs.count = 2\n    print(run)\n}\n\n\/\/ Core { \n\/\/      SwiftUI.Font = Font(provider: SwiftUI.(unknown context at $7fff5cd3a0a0).FontBox&lt;SwiftUI.Font.(unknown context at $7fff5cd66db0).TextStyleProvider>)\n\/\/      SwiftUI.ForegroundColor = green\n\/\/      }\n\/\/ Data {}<\/pre>\n\n\n\n<p><strong><em>\u591a\u4e2a Run<\/em><\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var multiRunString = AttributedString(\"The attributed runs of the attributed string, as a view into the underlying string.\")\nwhile let range = multiRunString.range(of: \"attributed\") {\n    multiRunString.characters.replaceSubrange(range, with: \"attributed\".uppercased())\n    multiRunString[range].inlinePresentationIntent = .stronglyEmphasized\n}\nvar n = 0\nfor run in multiRunString.runs {\n    n += 1\n}\n\/\/ n = 5\n<\/pre>\n\n\n\n<p>\u6700\u7ec8\u7ed3\u679c\uff1aThe\u00a0<strong>ATTRIBUTED<\/strong>\u00a0runs of the\u00a0<strong>ATTRIBUTED<\/strong>\u00a0string, as a view into the underlying string.<\/p>\n\n\n\n<p><strong><em>\u5229\u7528 Run \u7684 range \u8fdb\u884c\u5c5e\u6027\u8bbe\u7f6e<\/em><\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u7ee7\u7eed\u4f7f\u7528\u4e0a\u6587\u7684 multiRunString\n\/\/ \u5c06\u6240\u6709\u975e\u5f3a\u8c03\u5b57\u7b26\u8bbe\u7f6e\u4e3a\u9ec4\u8272\nfor run in multiRunString.runs {\n    guard run.inlinePresentationIntent != .stronglyEmphasized else {continue}\n    multiRunString[run.range].foregroundColor = .yellow\n}\n<\/pre>\n\n\n\n<p><strong><em>\u901a\u8fc7 Runs \u83b7\u53d6\u6307\u5b9a\u7684\u5c5e\u6027<\/em><\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u5c06\u989c\u8272\u4e3a\u9ec4\u8272\u4e14\u4e3a\u7c97\u4f53\u7684\u6587\u5b57\u6539\u6210\u7ea2\u8272\nfor (color,intent,range) in multiRunString.runs[\\.foregroundColor,\\.inlinePresentationIntent] {\n    if color == .yellow &amp;&amp; intent == .stronglyEmphasized {\n        multiRunString[range].foregroundColor = .red\n    }\n}<\/pre>\n\n\n\n<p><strong><em>\u901a\u8fc7 Run \u7684 attributes \u6536\u96c6\u6240\u6709\u4f7f\u7528\u5230\u7684\u5c5e\u6027<\/em><\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var totalKeysContainer = AttributeContainer()\nfor run in multiRunString.runs{\n    let container = run.attributes\n    totalKeysContainer.merge(container)\n}\n<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>\u4f7f\u7528 Runs \u89c6\u56fe\u53ef\u4ee5\u65b9\u4fbf\u7684\u4ece\u4f17\u591a\u5c5e\u6027\u4e2d\u83b7\u53d6\u5230\u9700\u8981\u7684\u4fe1\u606f<\/p><\/blockquote>\n\n\n\n<p><strong><em>\u4e0d\u4f7f\u7528 Runs \u89c6\u56fe\uff0c\u8fbe\u5230\u7c7b\u4f3c\u7684\u6548\u679c<\/em><\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">multiRunString.transformingAttributes(\\.foregroundColor,\\.font){ color,font in\n    if color.value == .yellow &amp;&amp; font.value == .title {\n        multiRunString[color.range].backgroundColor = .green\n    }\n}\n<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>\u5c3d\u7ba1\u6ca1\u6709\u76f4\u63a5\u8c03\u7528 Runs \u89c6\u56fe\uff0c\u4e0d\u8fc7 transformingAttributes \u95ed\u5305\u7684\u8c03\u7528\u65f6\u673a\u540c Runs \u7684\u65f6\u673a\u662f\u4e00\u81f4\u7684\u3002transformingAttributes \u6700\u591a\u652f\u6301\u83b7\u53d6 5 \u4e2a\u5c5e\u6027\u3002<\/p><\/blockquote>\n\n\n\n<ul><li><strong>Range<\/strong><\/li><\/ul>\n\n\n\n<p>\u5728\u672c\u6587\u4e4b\u524d\u7684\u4ee3\u7801\u4e2d\uff0c\u5df2\u7ecf\u591a\u6b21\u4f7f\u7528\u8fc7 Range \u6765\u5bf9\u5c5e\u6027\u5b57\u7b26\u4e32\u7684\u5185\u5bb9\u8fdb\u884c\u8bbf\u95ee\u6216\u4fee\u6539\u3002<\/p>\n\n\n\n<p>\u5bf9\u5c5e\u6027\u5b57\u7b26\u4e32\u4e2d\u5c40\u90e8\u5185\u5bb9\u7684\u5c5e\u6027\u8fdb\u884c\u4fee\u6539\u53ef\u4ee5\u4f7f\u7528\u4e24\u79cd\u65b9\u5f0f\uff1a<\/p>\n\n\n\n<ul><li>\u901a\u8fc7 Range<\/li><li>\u901a\u8fc7 AttributedContainer<\/li><\/ul>\n\n\n\n<p><strong><em>\u901a\u8fc7\u5173\u952e\u5b57\u83b7\u53d6 Range<\/em><\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u4ece\u5c5e\u6027\u5b57\u7b26\u4e32\u7684\u7ed3\u5c3e\u5411\u524d\u67e5\u627e\uff0c\u8fd4\u56de\u7b2c\u4e00\u4e2a\u6ee1\u8db3\u5173\u952e\u5b57\u7684 range\uff08\u5ffd\u7565\u5927\u5c0f\u5199\uff09\nif let range = multiRunString.range(of: \"Attributed\", options: [.backwards, .caseInsensitive]) {\n    multiRunString[range].link = URL(string: \"https:\/\/www.apple.com\")\n}<\/pre>\n\n\n\n<p><strong><em>\u4f7f\u7528 Runs \u6216 transformingAttributes \u83b7\u53d6 Range<\/em><\/strong><\/p>\n\n\n\n<p>\u4e4b\u524d\u7684\u4f8b\u5b50\u4e2d\u5df2\u53cd\u590d\u4f7f\u7528<\/p>\n\n\n\n<p><strong><em>\u901a\u8fc7\u672c\u6587\u89c6\u56fe\u83b7\u53d6 Range<\/em><\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">if let lowBound = multiRunString.characters.firstIndex(of: \"r\"),\n   let upperBound = multiRunString.characters.firstIndex(of: \",\"),\n   lowBound &lt; upperBound\n{\n    multiRunString[lowBound...upperBound].foregroundColor = .brown\n}<\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">\u672c\u5730\u5316<\/h5>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p id=\"\u521b\u5efa\u672c\u5730\u5316\u5c5e\u6027\u5b57\u7b26\u4e32\"><strong>\u521b\u5efa\u672c\u5730\u5316\u5c5e\u6027\u5b57\u7b26\u4e32<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Localizable Chinese\n\"hello\" = \"\u4f60\u597d\";\n\/\/ Localizable English\n\"hello\" = \"hello\";\n\nlet attributedString = AttributedString(localized: \"hello\")\n<\/pre>\n\n\n\n<p>\u5728\u82f1\u6587\u548c\u4e2d\u6587\u73af\u5883\u4e2d\uff0c\u5c06\u5206\u522b\u663e\u793a\u4e3a<code>hello<\/code>&nbsp;\u548c&nbsp;<code>\u4f60\u597d<\/code><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p><\/p><cite>\u76ee\u524d\u672c\u5730\u5316\u7684 AttributedString \u53ea\u80fd\u663e\u793a\u4e3a\u5f53\u524d\u7cfb\u7edf\u8bbe\u7f6e\u7684\u8bed\u8a00\uff0c\u5e76\u4e0d\u80fd\u6307\u5b9a\u6210\u67d0\u4e2a\u7279\u5b9a\u7684\u8bed\u8a00<br><\/cite><\/blockquote>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var hello = AttributedString(localized: \"hello\")\nif let range = hello.range(of: \"h\") {\n    hello[range].foregroundColor = .red\n}\n<\/pre>\n\n\n\n<p>\u672c\u5730\u5316\u5b57\u7b26\u4e32\u7684\u6587\u5b57\u5185\u5bb9\u5c06\u968f\u7cfb\u7edf\u8bed\u8a00\u800c\u53d8\u5316\uff0c\u4e0a\u9762\u7684\u4ee3\u7801\u5728\u4e2d\u6587\u73af\u5883\u4e0b\u5c06\u65e0\u6cd5\u83b7\u53d6\u5230 range\u3002\u9700\u9488\u5bf9\u4e0d\u540c\u7684\u8bed\u8a00\u505a\u8c03\u6574\u3002<\/p>\n\n\n\n<p><strong>replacementIndex<\/strong><\/p>\n\n\n\n<p>\u53ef\u4ee5\u4e3a\u672c\u5730\u5316\u5b57\u7b26\u4e32\u7684\u63d2\u503c\u5185\u5bb9\u8bbe\u5b9a index\uff08\u901a\u8fc7<code>applyReplacementIndexAttribute<\/code>\uff09, \u65b9\u4fbf\u5728\u672c\u5730\u5316\u5185\u5bb9\u4e2d\u67e5\u627e<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Localizable Chinese\n\"world %@ %@\" = \"%@ \u4e16\u754c %@\";\n\/\/ Localizable English\n\"world %@ %@\" = \"world %@ %@\";\n\nvar world = AttributedString(localized: \"world \\(\"\ud83d\udc4d\") \\(\"\ud83e\udd69\")\",options: .applyReplacementIndexAttribute) \/\/ \u521b\u5efa\u5c5e\u6027\u5b57\u7b26\u4e32\u65f6\uff0c\u5c06\u6309\u7167\u63d2\u503c\u987a\u5e8f\u8bbe\u5b9a index \uff0c\ud83d\udc4d index == 1 \ud83e\udd69 index == 2\n\nfor (index,range) in world.runs[\\.replacementIndex] {\n    switch index {\n        case 1:\n            world[range].baselineOffset = 20\n            world[range].font = .title\n        case 2:\n            world[range].backgroundColor = .blue\n        default:\n            world[range].inlinePresentationIntent = .strikethrough\n    }\n}\n<\/pre>\n\n\n\n<p>\u5728\u4e2d\u6587\u548c\u82f1\u6587\u73af\u5883\u4e2d\uff0c\u5206\u522b\u4e3a\uff1a<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2021\/12\/image-264-1024x602.png\" alt=\"\" class=\"wp-image-4804\" width=\"533\" height=\"312\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-264-1024x602.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-264-300x176.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-264-768x451.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-264-830x488.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-264-230x135.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-264-350x206.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-264-480x282.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-264.png 1154w\" sizes=\"(max-width: 533px) 100vw, 533px\" \/><\/figure><\/div>\n\n\n\n<p id=\"\u4f7f\u7528_locale_\u8bbe\u5b9a\u5b57\u7b26\u4e32\u63d2\u503c\u4e2d\u7684_Formatter\"><strong>\u4f7f\u7528 locale \u8bbe\u5b9a\u5b57\u7b26\u4e32\u63d2\u503c\u4e2d\u7684 Formatter<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> AttributedString(localized: \"\\(Date.now, format: Date.FormatStyle(date: .long))\", locale: Locale(identifier: \"zh-cn\"))\n\/\/ \u5373\u4f7f\u5728\u82f1\u6587\u73af\u5883\u4e2d\u4e5f\u4f1a\u663e\u793a 2021 \u5e74 10 \u6708 7 \u65e5\n<\/pre>\n\n\n\n<p id=\"\u7528_Formatter_\u751f\u6210\u5c5e\u6027\u5b57\u7b26\u4e32\"><strong>\u7528 Formatter \u751f\u6210\u5c5e\u6027\u5b57\u7b26\u4e32<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">    var dateString = Date.now.formatted(.dateTime.year().month().day().attributed)\n        dateString.transformingAttributes(\\.dateField) { dateField in\n            switch dateField.value {\n            case .month:\n                dateString[dateField.range].foregroundColor = .red\n            case .day:\n                dateString[dateField.range].foregroundColor = .green\n            case .year:\n                dateString[dateField.range].foregroundColor = .blue\n            default:\n                break\n            }\n        }<\/pre>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2021\/12\/image-265-1024x186.png\" alt=\"\" class=\"wp-image-4805\" width=\"564\" height=\"102\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-265-1024x186.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-265-300x54.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-265-768x139.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-265-830x150.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-265-230x42.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-265-350x63.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-265-480x87.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-265.png 1126w\" sizes=\"(max-width: 564px) 100vw, 564px\" \/><\/figure><\/div>\n\n\n\n<p><strong>Markdown \u7b26\u53f7<\/strong><\/p>\n\n\n\n<p>\u4ece SwiftUI 3.0 \u5f00\u59cb\uff0cText \u5df2\u7ecf\u5bf9\u90e8\u5206 Markdown \u6807\u7b7e\u63d0\u4f9b\u4e86\u652f\u6301\u3002\u5728\u672c\u5730\u5316\u7684\u5c5e\u6027\u5b57\u7b26\u4e32\u4e2d\uff0c\u4e5f\u63d0\u4f9b\u4e86\u7c7b\u4f3c\u7684\u529f\u80fd\uff0c\u5e76\u4e14\u4f1a\u5728\u5b57\u7b26\u4e32\u4e2d\u8bbe\u7f6e\u5bf9\u5e94\u7684\u5c5e\u6027\u3002\u63d0\u4f9b\u4e86\u66f4\u9ad8\u7684\u7075\u6d3b\u6027\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var markdownString = AttributedString(localized: \"**Hello** ~world~ _!_\")\nfor (inlineIntent,range) in markdownString.runs[\\.inlinePresentationIntent] {\n    guard let inlineIntent = inlineIntent else {continue}\n    switch inlineIntent{\n        case .stronglyEmphasized:\n            markdownString[range].foregroundColor = .red\n        case .emphasized:\n            markdownString[range].foregroundColor = .green\n        case .strikethrough:\n            markdownString[range].foregroundColor = .blue\n        default:\n            break\n    }\n}\n<\/pre>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2021\/12\/image-266-1024x140.png\" alt=\"\" class=\"wp-image-4806\" width=\"533\" height=\"72\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-266-1024x140.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-266-300x41.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-266-768x105.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-266-830x114.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-266-230x31.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-266-350x48.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-266-480x66.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2021\/12\/image-266.png 1126w\" sizes=\"(max-width: 533px) 100vw, 533px\" \/><\/figure><\/div>\n\n\n\n<p><strong>Markdown \u89e3\u6790<\/strong><\/p>\n\n\n\n<p>AttributedString \u4e0d\u4ec5\u53ef\u4ee5\u5728\u672c\u5730\u5316\u5b57\u7b26\u4e32\u4e2d\u652f\u6301\u90e8\u5206\u7684 Markdown \u6807\u7b7e\uff0c\u5e76\u4e14\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5b8c\u6574\u7684 Markdown \u89e3\u6790\u5668\u3002<\/p>\n\n\n\n<p>\u652f\u6301\u4ece String\u3001Data \u6216 URL \u4e2d\u89e3\u6790 Markdown \u6587\u672c\u5185\u5bb9\u3002<\/p>\n\n\n\n<p>\u6bd4\u5982\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">let mdString = try! AttributedString(markdown: \"# Title\\n**hello**\\n\")\nprint(mdString)\n\n\/\/ \u89e3\u6790\u7ed3\u679c\nTitle {\n    NSPresentationIntent = [header 1 (id 1)]\n}\nhello {\n    NSInlinePresentationIntent = NSInlinePresentationIntent(rawValue: 2)\n    NSPresentationIntent = [paragraph (id 2)]\n}<\/pre>\n\n\n\n<p>\u89e3\u6790\u540e\u4f1a\u5c06\u6587\u5b57\u98ce\u683c\u548c\u6807\u7b7e\u8bbe\u7f6e\u5728<code>inlinePresentationIntent<\/code>\u548c<code>presentationIntent<\/code>\u4e2d\u3002<\/p>\n\n\n\n<ul><li>inlinePresentationIntent<\/li><\/ul>\n\n\n\n<p>\u5b57\u7b26\u6027\u8d28\uff1a\u6bd4\u5982\u7c97\u4f53\u3001\u659c\u4f53\u3001\u4ee3\u7801\u3001\u5f15\u7528\u7b49<\/p>\n\n\n\n<ul><li>presentationIntent<\/li><\/ul>\n\n\n\n<p>\u6bb5\u843d\u5c5e\u6027\uff1a\u6bd4\u5982\u6bb5\u843d\u3001\u8868\u683c\u3001\u5217\u8868\u7b49\u3002\u4e00\u4e2a Run \u4e2d\uff0cpresentationIntent \u53ef\u80fd\u4f1a\u6709\u591a\u4e2a\u5185\u5bb9\uff0c\u7528 component \u6765\u83b7\u53d6\u3002<\/p>\n\n\n\n<p>README.md<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#  Hello \n\n## Header2\n\nhello **world**\n\n* first\n* second\n\n> test `print(\"hello world\")`\n\n| row1 | row2 |\n| ---- | ---- |\n| 34   | 135  |\n\n[\u65b0 Formatter \u4ecb\u7ecd](\/posts\/newFormatter\/)<\/pre>\n\n\n\n<p>\u89e3\u6790\u4ee3\u7801\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">let url = Bundle.main.url(forResource: \"README\", withExtension: \"md\")!\nvar markdownString = try! AttributedString(contentsOf: url,baseURL: URL(string: \"https:\/\/www.fatbobman.com\"))\n<\/pre>\n\n\n\n<p>\u89e3\u6790\u540e\u7ed3\u679c\uff08\u8282\u9009\uff09\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Hello {\n    NSPresentationIntent = [header 1 (id 1)]\n}\nHeader2 {\n    NSPresentationIntent = [header 2 (id 2)]\n}\nfirst {\n    NSPresentationIntent = [paragraph (id 6), listItem 1 (id 5), unorderedList (id 4)]\n}\n\ntest  {\n    NSPresentationIntent = [paragraph (id 10), blockQuote (id 9)]\n}\nprint(\"hello world\") {\n    NSPresentationIntent = [paragraph (id 10), blockQuote (id 9)]\n    NSInlinePresentationIntent = NSInlinePresentationIntent(rawValue: 4)\n}\nrow1 {\n    NSPresentationIntent = [tableCell 0 (id 13), tableHeaderRow (id 12), table [Foundation.PresentationIntent.TableColumn(alignment: Foundation.PresentationIntent.TableColumn.Alignment.left), Foundation.PresentationIntent.TableColumn(alignment: Foundation.PresentationIntent.TableColumn.Alignment.left)] (id 11)]\n}\nrow2 {\n    NSPresentationIntent = [tableCell 1 (id 14), tableHeaderRow (id 12), table [Foundation.PresentationIntent.TableColumn(alignment: Foundation.PresentationIntent.TableColumn.Alignment.left), Foundation.PresentationIntent.TableColumn(alignment: Foundation.PresentationIntent.TableColumn.Alignment.left)] (id 11)]\n}\n\u65b0 Formatter \u4ecb\u7ecd {\n    NSPresentationIntent = [paragraph (id 18)]\n    NSLink = \/posts\/newFormatter\/ -- https:\/\/www.fatbobman.com\n}\n<\/pre>\n\n\n\n<p>\u89e3\u6790\u540e\u7684\u5185\u5bb9\u5305\u62ec\u6bb5\u843d\u5c5e\u6027\u3001\u6807\u9898\u53f7\u3001\u8868\u683c\u5217\u6570\u3001\u884c\u6570\u3001\u5bf9\u9f50\u65b9\u5f0f\u7b49\u3002\u7f29\u7d27\u3001\u6807\u53f7\u7b49\u5176\u4ed6\u4fe1\u606f\u53ef\u4ee5\u5728\u4ee3\u7801\u4e2d\u53ef\u4ee5\u901a\u8fc7\u679a\u4e3e\u5173\u8054\u503c\u6765\u5904\u7406\u3002<\/p>\n\n\n\n<p>\u5927\u81f4\u7684\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">for run in markdownString.runs {\n    if let inlinePresentationIntent = run.inlinePresentationIntent {\n        switch inlinePresentationIntent {\n        case .strikethrough:\n            print(\"\u5220\u9664\u7ebf\")\n        case .stronglyEmphasized:\n            print(\"\u7c97\u4f53\")\n        default:\n            break\n        }\n    }\n    if let presentationIntent = run.presentationIntent {\n        for component in presentationIntent.components {\n            switch component.kind{\n                case .codeBlock(let languageHint):\n                    print(languageHint)\n                case .header(let level):\n                    print(level)\n                case .paragraph:\n                    let paragraphID = component.identity\n                default:\n                    break\n            }\n        }\n    }\n}<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>SwiftUI \u5e76\u4e0d\u652f\u6301 presentationIntent \u9644\u52a0\u4fe1\u606f\u7684\u6e32\u67d3\u3002\u5982\u679c\u60f3\u83b7\u5f97\u7406\u60f3\u7684\u663e\u793a\u6548\u679c\uff0c\u8bf7\u81ea\u884c\u7f16\u5199\u89c6\u89c9\u98ce\u683c\u8bbe\u7f6e\u4ee3\u7801\u3002<\/p><\/blockquote>\n\n\n\n<h5 class=\"wp-block-heading\">\u81ea\u5b9a\u4e49\u5c5e\u6027<\/h5>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>\u4f7f\u7528\u81ea\u5b9a\u4e49\u5c5e\u6027\uff0c\u4e0d\u4ec5\u6709\u5229\u4e8e\u5f00\u53d1\u8005\u521b\u5efa\u66f4\u7b26\u5408\u81ea\u8eab\u8981\u6c42\u7684\u5c5e\u6027\u5b57\u7b26\u4e32\uff0c\u800c\u4e14\u901a\u8fc7\u5728 Markdown \u6587\u672c\u4e2d\u6dfb\u52a0\u81ea\u5b9a\u4e49\u5c5e\u6027\u4fe1\u606f\uff0c\u8fdb\u4e00\u6b65\u964d\u4f4e\u4fe1\u606f\u548c\u4ee3\u7801\u7684\u8026\u5408\u5ea6\uff0c\u63d0\u9ad8\u7075\u6d3b\u5ea6\u3002<\/p>\n\n\n\n<p>\u81ea\u5b9a\u4e49\u5c5e\u6027\u7684\u57fa\u672c\u6d41\u7a0b\u4e3a\uff1a<\/p>\n\n\n\n<ul><li>\u521b\u5efa\u81ea\u5b9a\u4e49 AttributedStringKey<\/li><\/ul>\n\n\n\n<p>\u4e3a\u6bcf\u4e2a\u9700\u8981\u6dfb\u52a0\u7684\u5c5e\u6027\u521b\u5efa\u4e00\u4e2a\u7b26\u5408 Attributed \u534f\u8bae\u7684\u6570\u636e\u7c7b\u578b\u3002<\/p>\n\n\n\n<ul><li>\u521b\u5efa\u81ea\u5b9a\u4e49 AttributeScope \u5e76\u6269\u5c55 AttributeScopes<\/li><\/ul>\n\n\n\n<p>\u521b\u5efa\u81ea\u5df1\u7684 Scope\uff0c\u5e76\u5728\u5176\u4e2d\u6dfb\u52a0\u6240\u6709\u7684\u81ea\u5b9a\u4e49\u5c5e\u6027\u3002\u4e3a\u4e86\u65b9\u4fbf\u81ea\u5b9a\u4e49\u5c5e\u6027\u96c6\u88ab\u7528\u4e8e\u9700\u8981\u6307\u5b9a Scope \u7684\u573a\u5408\uff0c\u5728\u81ea\u5b9a\u4e49 Scope \u4e2d\u63a8\u8350\u5d4c\u5957\u5165\u9700\u8981\u7684\u7cfb\u7edf\u6846\u67b6 Scope\uff08swiftUI\u3001uiKit\u3001appKit\uff09\u3002\u5e76\u5728 AttributeScopes \u4e2d\u6dfb\u52a0\u4e0a\u81ea\u5b9a\u4e49\u7684 Scope\u3002<\/p>\n\n\n\n<ul><li>\u6269\u5c55 AttributeDynamicLookup\uff08\u652f\u6301\u70b9\u8bed\u6cd5\uff09<\/li><\/ul>\n\n\n\n<p>\u5728 AttributeDynamicLookup \u4e2d\u521b\u5efa\u7b26\u5408\u81ea\u5b9a\u4e49 Scope \u7684\u4e0b\u6807\u65b9\u6cd5\u3002\u4e3a\u70b9\u8bed\u6cd5\u3001KeyPath \u63d0\u4f9b\u52a8\u6001\u652f\u6301\u3002<\/p>\n\n\n\n<p id=\"\u5b9e\u4f8b_1\uff1a\u521b\u5efa_id_\u5c5e\u6027\"><strong>\u5b9e\u4f8b 1\uff1a\u521b\u5efa id \u5c5e\u6027<\/strong><\/p>\n\n\n\n<p>\u672c\u4f8b\u4e2d\u6211\u4eec\u5c06\u521b\u5efa\u4e00\u4e2a\u540d\u79f0\u4e3a id \u7684\u5c5e\u6027\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">struct MyIDKey:AttributedStringKey {\n    typealias Value = Int \/\/ \u5c5e\u6027\u5185\u5bb9\u7684\u7c7b\u578b\u3002\u7c7b\u578b\u9700\u8981\u7b26\u5408 Hashable\n    static var name: String = \"id\" \/\/ \u5c5e\u6027\u5b57\u7b26\u4e32\u5185\u90e8\u4fdd\u5b58\u7684\u540d\u79f0\n}\n\nextension AttributeScopes{\n    public struct MyScope:AttributeScope{\n        let id:MyIDKey  \/\/ \u70b9\u8bed\u6cd5\u8c03\u7528\u7684\u540d\u79f0\n        let swiftUI:SwiftUIAttributes \/\/ \u5728\u6211\u7684 Scope \u4e2d\u5c06\u7cfb\u7edf\u6846\u67b6 swiftUI \u4e5f\u6dfb\u52a0\u8fdb\u6765\n    }\n\n    var myScope:MyScope.Type{\n        MyScope.self\n    }\n}\n\nextension AttributeDynamicLookup{\n    subscript&lt;T>(dynamicMember keyPath:KeyPath&lt;AttributeScopes.MyScope,T>) -> T where T:AttributedStringKey {\n        self[T.self]\n    }\n}<\/pre>\n\n\n\n<p>\u8c03\u7528<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var attribtedString = AttributedString(\"hello world\")\nattribtedString.id = 34\nprint(attribtedString)\n\n\/\/ Output\nhello world {\n    id = 34\n}<\/pre>\n\n\n\n<p id=\"\u5b9e\u4f8b_2\uff1a\u521b\u5efa\u679a\u4e3e\u5c5e\u6027\uff0c\u5e76\u652f\u6301_Markdown_\u89e3\u6790\"><strong>\u5b9e\u4f8b 2\uff1a\u521b\u5efa\u679a\u4e3e\u5c5e\u6027\uff0c\u5e76\u652f\u6301 Markdown \u89e3\u6790<\/strong><\/p>\n\n\n\n<p>\u5982\u679c\u6211\u4eec\u5e0c\u671b\u81ea\u5df1\u521b\u5efa\u7684\u5c5e\u6027\u53ef\u4ee5\u5728 Markdown \u6587\u672c\u4e2d\u88ab\u89e3\u6790\uff0c\u9700\u8981\u8ba9\u81ea\u5b9a\u4e49\u7684\u5c5e\u6027\u7b26\u5408<code>CodeableAttributedStringKey<\/code>\u4ee5\u53ca<code>MarkdownDecodableAttributedStringKye<\/code><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u81ea\u5b9a\u4e49\u5c5e\u6027\u7684\u6570\u636e\u7c7b\u578b\u4e0d\u9650\uff0c\u53ea\u8981\u6ee1\u8db3\u9700\u8981\u7684\u534f\u8bae\u5373\u53ef\nenum PriorityKey:CodableAttributedStringKey,MarkdownDecodableAttributedStringKey{\n    public enum Priority:String,Codable{ \/\/\u5982\u9700\u5728 Markdown \u4e2d\u89e3\u6790\uff0c\u9700\u8981\u5c06 raw \u7c7b\u578b\u8bbe\u7f6e\u4e3a String, \u5e76\u7b26\u5408 Codable\n        case low\n        case normal\n        case high\n    }\n\n    static var name: String = \"priority\"\n    typealias Value = Priority\n}\n\nextension AttributeScopes{\n    public struct MyScope:AttributeScope{\n        let id:MyIDKey\n        let priority:PriorityKey \/\/ \u5c06\u65b0\u521b\u5efa\u7684 Key \u4e5f\u6dfb\u52a0\u5230\u81ea\u5b9a\u4e49\u7684 Scope \u4e2d\n        let swiftUI:SwiftUIAttributes\n    }\n\n    var myScope:MyScope.Type{\n        MyScope.self\n    }\n}\n<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>\u5728 Markdown \u4e2d\u4f7f\u7528<code>^[text](\u5c5e\u6027\u540d\u79f0\uff1a\u5c5e\u6027\u503c)<\/code>\u6765\u6807\u8bb0\u81ea\u5b9a\u4e49\u5c5e\u6027<\/p><\/blockquote>\n\n\n\n<p>\u8c03\u7528<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u5728 Markdown \u6587\u672c\u4e2d\u89e3\u6790\u81ea\u5b9a\u4e49\u5c5e\u6027\u65f6\uff0c\u9700\u6307\u660e Scope\u3002\nvar attributedString = AttributedString(localized: \"^[hello world](priority:'low')\",including: \\.myScope)\nprint(attributedString)\n\n\/\/ Output\nhello world {\n    priority = low\n    NSLanguage = en\n}\n<\/pre>\n\n\n\n<p id=\"\u5b9e\u4f8b_3\uff1a\u521b\u5efa\u591a\u53c2\u6570\u7684\u5c5e\u6027\"><strong>\u5b9e\u4f8b 3\uff1a\u521b\u5efa\u591a\u53c2\u6570\u7684\u5c5e\u6027<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">enum SizeKey:CodableAttributedStringKey,MarkdownDecodableAttributedStringKey{\n    public struct Size:Codable,Hashable{\n        let width:Double\n        let height:Double\n    }\n\n    static var name: String = \"size\"\n    typealias Value = Size\n}\n\n\/\/ \u5728 Scope \u4e2d\u6dfb\u52a0\nlet size:SizeKey\n<\/pre>\n\n\n\n<p>\u8c03\u7528<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u591a\u53c2\u6570\u5728{}\u5185\u6dfb\u52a0\nlet attributedString = AttributedString(localized: \"^[hello world](size:{width:343.3,height:200.3},priority:'high')\",including: \\.myScope)\nprint(attributedString)\n\n\/\/ Output\nello world {\n    priority = high\n    size = Size(width: 343.3, height: 200.3)\n    NSLanguage = en\n}<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>\u5728&nbsp;<a href=\"https:\/\/www.fatbobman.com\/posts\/newFormatter\/\">WWDC 2021 \u65b0 Formatter API<\/a>&nbsp;\u4e00\u6587\u4e2d\uff0c\u8fd8\u6709\u5728 Formatter \u4e2d\u4f7f\u7528\u81ea\u5b9a\u4e49\u5c5e\u6027\u7684\u6848\u4f8b<\/p><\/blockquote>\n\n\n\n<h5 class=\"wp-block-heading\">\u603b\u7ed3<\/h5>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>\u5728 AttributedString \u4e4b\u524d\uff0c\u591a\u6570\u5f00\u53d1\u8005\u5c06\u5c5e\u6027\u5b57\u7b26\u4e32\u4e3b\u8981\u7528\u4e8e\u6587\u672c\u7684\u663e\u793a\u6837\u5f0f\u63cf\u8ff0\uff0c\u968f\u7740\u53ef\u4ee5\u5728 Markdown \u6587\u672c\u4e2d\u6dfb\u52a0\u81ea\u5b9a\u4e49\u5c5e\u6027\uff0c\u76f8\u4fe1\u5f88\u5feb\u5c31\u4f1a\u6709\u5f00\u53d1\u8005\u6269\u5c55 AttributedString \u7684\u7528\u9014\uff0c\u5c06\u5176\u5e94\u7528\u5230\u66f4\u591a\u7684\u573a\u666f\u4e2d\u3002<\/p>\n\n\n\n<p>\u5e0c\u671b\u672c\u6587\u80fd\u591f\u5bf9\u4f60\u6709\u6240\u5e2e\u52a9\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5728 WWDC 2021 \u4e0a\uff0c\u82f9\u679c\u4e3a\u5f00\u53d1\u8005\u5e26\u6765\u4e86\u6709\u4e00\u4e2a\u671f\u5f85\u5df2\u4e45\u7684\u529f\u80fd\u2014\u2014AttributedString\uff0c\u8fd9\u610f\u5473 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"_links":{"self":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/4783"}],"collection":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4783"}],"version-history":[{"count":14,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/4783\/revisions"}],"predecessor-version":[{"id":4807,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/4783\/revisions\/4807"}],"wp:attachment":[{"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4783"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4783"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4783"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}