<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Skytoup Blog</title><link>https://blog.skytoup.com/post/</link><description>Recent content in Posts on Skytoup Blog</description><generator>Hugo -- gohugo.io</generator><language>cn-zh</language><lastBuildDate>Sun, 05 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.skytoup.com/post/index.xml" rel="self" type="application/rss+xml"/><item><title>Apple Assets Car 文件</title><link>https://blog.skytoup.com/p/apple-assets-car-%E6%96%87%E4%BB%B6/</link><pubDate>Sun, 05 Apr 2026 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/apple-assets-car-%E6%96%87%E4%BB%B6/</guid><description>&lt;ul&gt;
&lt;li&gt;2021年不知道发什么神经, 开始研究&lt;code&gt;xcassets&lt;/code&gt;文件解析, 用&lt;code&gt;Python&lt;/code&gt;把&lt;code&gt;BOM&lt;/code&gt;和&lt;code&gt;car&lt;/code&gt;的结构初步解析出来.&lt;/li&gt;
&lt;li&gt;2025年又开始发神经, 将2021年的&lt;code&gt;Python&lt;/code&gt;代码用&lt;code&gt;Rust&lt;/code&gt;重写. 写着写着发神经, 想把&lt;code&gt;car&lt;/code&gt;的内容提取出来. 被&lt;code&gt;Deepmap2&lt;/code&gt;解码卡住, 无奈中断.&lt;/li&gt;
&lt;li&gt;2026年碰上&lt;code&gt;AI+Agent&lt;/code&gt;, 想起来这货, 于是拿来练手.&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;本文全部由&lt;code&gt;Agent&lt;/code&gt;分析代码总结的文件结构、流程.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如有审核不足, 可在评论区指出错漏的地方.&lt;/p&gt;
&lt;p&gt;代码有空整理再放出来吧🕊️🕊️🕊️&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h1 id="apple-assets-car-file-format"&gt;Apple Assets (.car) File Format
&lt;/h1&gt;&lt;p&gt;Apple 的 &lt;code&gt;.car&lt;/code&gt; (Compiled Asset Catalog) 文件是 Xcode 在编译 Asset Catalog (&lt;code&gt;.xcassets&lt;/code&gt;) 时生成的二进制文件。它采用三层嵌套结构：&lt;strong&gt;BOM 容器&lt;/strong&gt; 包裹 &lt;strong&gt;CAR 元数据与索引&lt;/strong&gt;，CAR 索引指向 &lt;strong&gt;CSI 渲染数据&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="整体架构"&gt;整体架构
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;graph TB
 subgraph "Assets.car 文件"
 BOM["BOM 容器层&lt;br/&gt;(Bill of Materials)"]
 BOM --&gt; VarStore["变量表 (VariableStore)&lt;br/&gt;命名入口: CARHEADER, RENDITIONS, ..."]
 BOM --&gt; IdxStore["索引表 (IndexStore)&lt;br/&gt;Block 偏移/长度表"]
 BOM --&gt; Blocks["数据块 (Blocks)&lt;br/&gt;实际二进制数据"]

 VarStore --&gt; |"name → index"| IdxStore
 IdxStore --&gt; |"offset + len"| Blocks

 subgraph "CAR 层 (Named Trees)"
 CARHEADER["CARHEADER&lt;br/&gt;文件头元数据"]
 KEYFORMAT["KEYFORMAT&lt;br/&gt;属性类型定义"]
 FACETKEYS["FACETKEYS&lt;br/&gt;资源名称 → 属性"]
 RENDITIONS["RENDITIONS&lt;br/&gt;属性组合 → CSI 数据"]
 APPEARANCEKEYS["APPEARANCEKEYS&lt;br/&gt;外观模式"]
 EXTMETA["EXTENDED_METADATA&lt;br/&gt;构建工具信息"]
 end

 Blocks --&gt; CARHEADER
 Blocks --&gt; KEYFORMAT
 Blocks --&gt; FACETKEYS
 Blocks --&gt; RENDITIONS
 Blocks --&gt; APPEARANCEKEYS
 Blocks --&gt; EXTMETA
 end

 style BOM fill:#4a9eff,color:#fff
 style RENDITIONS fill:#ff6b6b,color:#fff
 style FACETKEYS fill:#51cf66,color:#fff&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="1-bom-容器层"&gt;1. BOM 容器层
&lt;/h2&gt;&lt;p&gt;BOM (Bill of Materials) 是 Apple 通用的二进制容器格式，&lt;code&gt;.car&lt;/code&gt; 文件以此为底层封装。&lt;strong&gt;所有 BOM 结构使用大端序 (Big-Endian)&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="11-文件布局"&gt;1.1 文件布局
&lt;/h3&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;block-beta
 columns 1
 A["StoreHeader (Magic: 'BOMStore' + 元数据)"]
 B["... (480 字节填充) ..."]
 C["IndexStore (Block 偏移/长度数组)"]
 D["VariableStore (命名变量 → Index 映射)"]
 E["Block Data (散布在文件各处)"]

 style A fill:#4a9eff,color:#fff
 style C fill:#ffd43b,color:#333
 style D fill:#51cf66,color:#fff
 style E fill:#ff6b6b,color:#fff&lt;/pre&gt;&lt;h3 id="12-storeheader"&gt;1.2 StoreHeader
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;偏移&lt;/th&gt;
 &lt;th&gt;大小&lt;/th&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;0x00&lt;/td&gt;
 &lt;td&gt;8B&lt;/td&gt;
 &lt;td&gt;magic&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;quot;BOMStore&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x08&lt;/td&gt;
 &lt;td&gt;4B&lt;/td&gt;
 &lt;td&gt;version&lt;/td&gt;
 &lt;td&gt;固定为 &lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x0C&lt;/td&gt;
 &lt;td&gt;4B&lt;/td&gt;
 &lt;td&gt;block_count&lt;/td&gt;
 &lt;td&gt;非空 Block 数量&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x10&lt;/td&gt;
 &lt;td&gt;4B&lt;/td&gt;
 &lt;td&gt;index_offset&lt;/td&gt;
 &lt;td&gt;IndexStore 的文件偏移&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x14&lt;/td&gt;
 &lt;td&gt;4B&lt;/td&gt;
 &lt;td&gt;index_len&lt;/td&gt;
 &lt;td&gt;IndexStore 长度&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x18&lt;/td&gt;
 &lt;td&gt;4B&lt;/td&gt;
 &lt;td&gt;var_offset&lt;/td&gt;
 &lt;td&gt;VariableStore 的文件偏移&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x1C&lt;/td&gt;
 &lt;td&gt;4B&lt;/td&gt;
 &lt;td&gt;var_len&lt;/td&gt;
 &lt;td&gt;VariableStore 长度&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x20&lt;/td&gt;
 &lt;td&gt;480B&lt;/td&gt;
 &lt;td&gt;(padding)&lt;/td&gt;
 &lt;td&gt;保留填充&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="13-indexstore-block-索引表"&gt;1.3 IndexStore (Block 索引表)
&lt;/h3&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;packet-beta
 0-31: "count: u32"
 32-63: "Index[0] (offset + len)"
 64-95: "Index[1] (offset + len)"
 96-127: "... Index[N]"&lt;/pre&gt;&lt;p&gt;每个 &lt;code&gt;Index&lt;/code&gt; 条目 (8 字节)：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;大小&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;offset&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;Block 数据的文件绝对偏移&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;len&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;Block 数据长度&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="14-variablestore-命名变量表"&gt;1.4 VariableStore (命名变量表)
&lt;/h3&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;packet-beta
 0-31: "count: u32"
 32-79: "Variable[0] (index + len + name)"
 80-127: "... Variable[N] (变长)"&lt;/pre&gt;&lt;p&gt;每个 &lt;code&gt;Variable&lt;/code&gt; (变长)：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;大小&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;index&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;指向 IndexStore 的索引&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;len&lt;/td&gt;
 &lt;td&gt;u8&lt;/td&gt;
 &lt;td&gt;名称长度&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;name&lt;/td&gt;
 &lt;td&gt;[u8; len]&lt;/td&gt;
 &lt;td&gt;变量名 (如 &lt;code&gt;&amp;quot;CARHEADER&amp;quot;&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="15-b-tree-结构"&gt;1.5 B-Tree 结构
&lt;/h3&gt;&lt;p&gt;BOM 中的树用于存储键值对集合，CAR 的各命名树均采用此结构。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;graph TD
 TH["TreeHeader&lt;br/&gt;magic: 'tree'&lt;br/&gt;version: 1&lt;br/&gt;block_size: 4096&lt;br/&gt;path_count: N"]
 TH --&gt; INT["内部节点 (is_leaf=0)&lt;br/&gt;indices[0].val → 子节点"]
 INT --&gt; LEAF1["叶节点 (is_leaf≠0)&lt;br/&gt;count 个 key/value 对"]
 INT --&gt; LEAF2["叶节点&lt;br/&gt;count 个 key/value 对"]
 LEAF1 --&gt; |"forward"| LEAF2
 LEAF2 --&gt; |"backward"| LEAF1

 style TH fill:#4a9eff,color:#fff
 style LEAF1 fill:#51cf66,color:#fff
 style LEAF2 fill:#51cf66,color:#fff&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;TreeHeader&lt;/strong&gt; (位于命名 Block 中)：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;大小&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;magic&lt;/td&gt;
 &lt;td&gt;4B&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;quot;tree&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;version&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;固定为 &lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;index&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;根节点在 IndexStore 中的索引&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;block_size&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;固定为 &lt;code&gt;4096&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;path_count&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;叶节点中的 key/value 对总数&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;unknown&lt;/td&gt;
 &lt;td&gt;u8&lt;/td&gt;
 &lt;td&gt;未知&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;TreePaths&lt;/strong&gt; (树节点)：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;大小&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;is_leaf&lt;/td&gt;
 &lt;td&gt;u16&lt;/td&gt;
 &lt;td&gt;0=内部节点, 非0=叶节点&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;count&lt;/td&gt;
 &lt;td&gt;u16&lt;/td&gt;
 &lt;td&gt;子项数量&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;forward&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;下一个兄弟节点的 Block 索引&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;backward&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;上一个兄弟节点的 Block 索引&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;indices&lt;/td&gt;
 &lt;td&gt;[TreePathIndex; count]&lt;/td&gt;
 &lt;td&gt;key/value 对&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;TreePathIndex&lt;/strong&gt; (每条 8 字节)：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;大小&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;val&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;value Block 在 IndexStore 中的索引&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;key&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;key Block 在 IndexStore 中的索引&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="16-寻址流程"&gt;1.6 寻址流程
&lt;/h3&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;sequenceDiagram
 participant Caller as 调用者
 participant VS as VariableStore
 participant IS as IndexStore
 participant File as 文件数据

 Caller-&gt;&gt;VS: 查找变量名 "RENDITIONS"
 VS--&gt;&gt;Caller: Variable { index: 42, ... }
 Caller-&gt;&gt;IS: 读取 IndexStore[42]
 IS--&gt;&gt;Caller: Index { offset: 0x1A00, len: 8192 }
 Caller-&gt;&gt;File: 读取 offset=0x1A00, len=8192
 File--&gt;&gt;Caller: Block 数据 (TreeHeader + ...)&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="2-car-层-asset-catalog"&gt;2. CAR 层 (Asset Catalog)
&lt;/h2&gt;&lt;p&gt;CAR 层建立在 BOM 容器之上，通过 6 个命名 BOM Tree 组织资源数据。&lt;strong&gt;CAR 层结构使用小端序 (Little-Endian)&lt;/strong&gt;（ExtendedMetadata 除外）。&lt;/p&gt;
&lt;h3 id="21-命名树一览"&gt;2.1 命名树一览
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;树名&lt;/th&gt;
 &lt;th&gt;类型&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;KEYFORMAT&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;单值&lt;/td&gt;
 &lt;td&gt;属性类型定义 (KeyFmt)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;CARHEADER&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;单值&lt;/td&gt;
 &lt;td&gt;文件头元数据 (Header)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;EXTENDED_METADATA&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;单值&lt;/td&gt;
 &lt;td&gt;构建工具信息 (大端序)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;APPEARANCEKEYS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;键值树&lt;/td&gt;
 &lt;td&gt;外观模式映射&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FACETKEYS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;键值树&lt;/td&gt;
 &lt;td&gt;资源名称 → 属性 Token&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;RENDITIONS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;键值树&lt;/td&gt;
 &lt;td&gt;属性组合 → CSI 渲染数据&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="22-解析流程"&gt;2.2 解析流程
&lt;/h3&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR
 A["Car::new(path)"] --&gt; B["BOM::new_with_file&lt;br/&gt;(mmap 打开)"]
 B --&gt; C["解析 KEYFORMAT&lt;br/&gt;(属性格式定义)"]
 C --&gt; D["解析 APPEARANCEKEYS"]
 D --&gt; E["解析 EXTENDED_METADATA"]
 E --&gt; F["解析 CARHEADER"]
 F --&gt; G["解析 FACETKEYS&lt;br/&gt;(资源名称索引)"]
 G --&gt; H["解析 RENDITIONS&lt;br/&gt;(渲染数据库)"]
 H --&gt; I["构建 MultiMap&amp;lt;u16, CSIItem&amp;gt;&lt;br/&gt;按 Identifier 索引"]

 style A fill:#4a9eff,color:#fff
 style I fill:#ff6b6b,color:#fff&lt;/pre&gt;&lt;h3 id="23-carheader-文件头"&gt;2.3 CARHEADER (文件头)
&lt;/h3&gt;&lt;p&gt;Magic: &lt;code&gt;&amp;quot;RATC&amp;quot;&lt;/code&gt; (小端序)&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;类型&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;coreui_version&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;CoreUI 版本&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;storage_version&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;存储格式版本&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;storage_timestamp&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;存储时间戳&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;rendition_count&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;渲染项总数&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;main_version_string&lt;/td&gt;
 &lt;td&gt;String(128B)&lt;/td&gt;
 &lt;td&gt;主版本字符串&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;version_string&lt;/td&gt;
 &lt;td&gt;String(256B)&lt;/td&gt;
 &lt;td&gt;版本字符串&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;uuid&lt;/td&gt;
 &lt;td&gt;[u8; 16]&lt;/td&gt;
 &lt;td&gt;唯一标识符&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;associated_checksum&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;关联校验和&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;schema_version&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;Schema 版本&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;color_space&lt;/td&gt;
 &lt;td&gt;ColorSpace&lt;/td&gt;
 &lt;td&gt;默认色彩空间&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;key_semantics&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;键语义&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="24-keyformat-键格式"&gt;2.4 KEYFORMAT (键格式)
&lt;/h3&gt;&lt;p&gt;Magic: &lt;code&gt;&amp;quot;tmfk&amp;quot;&lt;/code&gt; (小端序)&lt;/p&gt;
&lt;p&gt;KeyFmt 定义了 RENDITIONS 树中键的属性类型序列，决定了每个渲染项的键如何被解析。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;packet-beta
 0-31: "'tmfk' (magic)"
 32-63: "version: u32"
 64-95: "max_count: u32"
 96-111: "AttrType[0]: u16"
 112-127: "(2B padding)"
 128-143: "AttrType[1]: u16"
 144-159: "(2B padding)"
 160-191: "... AttrType[N] + pad"&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;AttributeType 枚举&lt;/strong&gt; (u16)：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;值&lt;/th&gt;
 &lt;th&gt;名称&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;td&gt;ThemeLook&lt;/td&gt;
 &lt;td&gt;主题外观&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;Element&lt;/td&gt;
 &lt;td&gt;UI 元素类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;Part&lt;/td&gt;
 &lt;td&gt;部件&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;Size&lt;/td&gt;
 &lt;td&gt;尺寸类别&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;Direction&lt;/td&gt;
 &lt;td&gt;布局方向&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;6&lt;/td&gt;
 &lt;td&gt;Value&lt;/td&gt;
 &lt;td&gt;值&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;7&lt;/td&gt;
 &lt;td&gt;ThemeAppearance&lt;/td&gt;
 &lt;td&gt;主题外观模式&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;8-9&lt;/td&gt;
 &lt;td&gt;Dimension1/2&lt;/td&gt;
 &lt;td&gt;维度&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10&lt;/td&gt;
 &lt;td&gt;State&lt;/td&gt;
 &lt;td&gt;状态&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;11&lt;/td&gt;
 &lt;td&gt;Layer&lt;/td&gt;
 &lt;td&gt;图层&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;12&lt;/td&gt;
 &lt;td&gt;Scale&lt;/td&gt;
 &lt;td&gt;缩放比例 (@1x/@2x/@3x)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;13&lt;/td&gt;
 &lt;td&gt;Localization&lt;/td&gt;
 &lt;td&gt;本地化&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;15&lt;/td&gt;
 &lt;td&gt;Idiom&lt;/td&gt;
 &lt;td&gt;设备类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;16&lt;/td&gt;
 &lt;td&gt;Subtype&lt;/td&gt;
 &lt;td&gt;子类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;17&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;Identifier&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;资源标识符 (用于索引渲染数据库)&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;20-21&lt;/td&gt;
 &lt;td&gt;H/V SizeClass&lt;/td&gt;
 &lt;td&gt;水平/垂直尺寸类别&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;24&lt;/td&gt;
 &lt;td&gt;DisplayGamut&lt;/td&gt;
 &lt;td&gt;显示色域&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;25&lt;/td&gt;
 &lt;td&gt;DeploymentTarget&lt;/td&gt;
 &lt;td&gt;部署目标&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="25-facetkeys-资源名称索引"&gt;2.5 FACETKEYS (资源名称索引)
&lt;/h3&gt;&lt;p&gt;FACETKEYS 是一个 &lt;code&gt;HashMap&amp;lt;String, KeyToken&amp;gt;&lt;/code&gt; 的树，将资源名称映射到属性集合。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;graph LR
 FN["资源名称&lt;br/&gt;'AppIcon'"] --&gt; KT["KeyToken&lt;br/&gt;x, y&lt;br/&gt;attrs: [Attribute]"]
 KT --&gt; A1["Attribute&lt;br/&gt;name: Scale&lt;br/&gt;val: 2"]
 KT --&gt; A2["Attribute&lt;br/&gt;name: Idiom&lt;br/&gt;val: 1 (Phone)"]
 KT --&gt; A3["Attribute&lt;br/&gt;name: Identifier&lt;br/&gt;val: 0x42"]
 A3 --&gt; |"用此值查询&lt;br/&gt;rendition_db"| RDB["MultiMap&amp;lt;u16, CSIItem&amp;gt;"]

 style FN fill:#51cf66,color:#fff
 style A3 fill:#ff6b6b,color:#fff
 style RDB fill:#ff6b6b,color:#fff&lt;/pre&gt;&lt;h3 id="26-renditions-树键值结构"&gt;2.6 RENDITIONS 树键值结构
&lt;/h3&gt;&lt;p&gt;RENDITIONS 树是 &lt;code&gt;.car&lt;/code&gt; 文件的核心数据存储。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;键结构&lt;/strong&gt;：按 KEYFORMAT 定义的属性类型序列，每个属性值为 u16 (小端序)。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Key: [ThemeLook:u16][Element:u16][Part:u16]...[Identifier:u16]...
 ← 按 KEYFORMAT 中的顺序排列 →
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;值结构&lt;/strong&gt;：CSIHeader + TLV 元数据 + 可选渲染数据 (详见第 3 节)。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;查找流程&lt;/strong&gt;：&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;sequenceDiagram
 participant App as 应用程序
 participant FK as FACETKEYS
 participant RDB as Rendition DB
 participant CSI as CSIItem

 App-&gt;&gt;FK: 查找 "AppIcon"
 FK--&gt;&gt;App: KeyToken { attrs: [..., Identifier=0x42] }
 App-&gt;&gt;RDB: rendition_db.get(0x42)
 RDB--&gt;&gt;App: Vec&lt;CSIItem&gt; (多个渲染变体)
 App-&gt;&gt;CSI: 按 Scale/Idiom 等筛选
 CSI--&gt;&gt;App: 目标 CSIItem (含图像数据)&lt;/pre&gt;&lt;h3 id="27-extended_metadata"&gt;2.7 EXTENDED_METADATA
&lt;/h3&gt;&lt;p&gt;Magic: &lt;code&gt;&amp;quot;META&amp;quot;&lt;/code&gt; (&lt;strong&gt;大端序&lt;/strong&gt; - 唯一的大端序 CAR 结构)&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;大小&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;thinning_args&lt;/td&gt;
 &lt;td&gt;256B&lt;/td&gt;
 &lt;td&gt;Thinning 参数&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;deployment_platform_version&lt;/td&gt;
 &lt;td&gt;256B&lt;/td&gt;
 &lt;td&gt;部署平台版本&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;deployment_platform&lt;/td&gt;
 &lt;td&gt;256B&lt;/td&gt;
 &lt;td&gt;部署平台&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;authoring_tool&lt;/td&gt;
 &lt;td&gt;256B&lt;/td&gt;
 &lt;td&gt;构建工具信息&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="3-csi-层-core-structured-image"&gt;3. CSI 层 (Core Structured Image)
&lt;/h2&gt;&lt;p&gt;CSI 是单个渲染项的完整数据结构，包含元数据、TLV 扩展信息和实际渲染数据。&lt;/p&gt;
&lt;h3 id="31-csiheader-布局"&gt;3.1 CSIHeader 布局
&lt;/h3&gt;&lt;p&gt;Magic: &lt;code&gt;&amp;quot;ISTC&amp;quot;&lt;/code&gt; (小端序)&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;block-beta
 columns 1
 A["CSIHeader 固定部分 (56 字节)"]
 B["CSIMetadata (name: 128 字节)"]
 C["TLV 数据 (tlv_length 字节)"]
 D["Rendition 数据 (rendition_length 字节, 可选)"]

 style A fill:#4a9eff,color:#fff
 style B fill:#ffd43b,color:#333
 style C fill:#51cf66,color:#fff
 style D fill:#ff6b6b,color:#fff&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;固定部分&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;类型&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;magic&lt;/td&gt;
 &lt;td&gt;[u8; 4]&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;quot;ISTC&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;version&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;CSI 版本&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;flags&lt;/td&gt;
 &lt;td&gt;Flags&lt;/td&gt;
 &lt;td&gt;位域标志 (32位)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;width&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;图像宽度&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;height&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;图像高度&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;scale_factor&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;缩放因子 (100=@1x, 200=@2x, 300=@3x)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;encoding&lt;/td&gt;
 &lt;td&gt;Encoding&lt;/td&gt;
 &lt;td&gt;像素编码格式&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;color_model&lt;/td&gt;
 &lt;td&gt;ColorModel&lt;/td&gt;
 &lt;td&gt;色彩模型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;CSIMetadata&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;类型&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;modification_time&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;修改时间&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;layout_type&lt;/td&gt;
 &lt;td&gt;LayoutType&lt;/td&gt;
 &lt;td&gt;布局类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;name&lt;/td&gt;
 &lt;td&gt;String(128B)&lt;/td&gt;
 &lt;td&gt;渲染项名称&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;BitmapList&lt;/strong&gt; (紧跟 CSIMetadata 之后)：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;类型&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;bitmap_count&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;位图数量 (通常为 1)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;zero&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;保留 (通常为 0)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;rendition_length&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;Rendition 数据长度&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="32-flags-位域"&gt;3.2 Flags 位域
&lt;/h3&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;packet-beta
 0-0: "H"
 1-1: "E"
 2-2: "V"
 3-3: "O"
 4-7: "BmpEnc"
 8-8: "O"
 9-9: "F"
 10-10: "T"
 11-11: "P"
 12-31: "reserved (20 bits)"&lt;/pre&gt;
 &lt;blockquote&gt;
 &lt;p&gt;H=is_header_flagged_fpo, E=is_excluded_from_contrast_filter, V=is_vector_based, O=is_opaque, BmpEnc=bitmap_encoding(4bit), O=opt_out_of_thinning, F=is_flippable, T=is_tintable, P=preserved_vector_representation&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;位&lt;/th&gt;
 &lt;th&gt;标志&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;td&gt;is_header_flagged_fpo&lt;/td&gt;
 &lt;td&gt;FPO 标记&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;is_excluded_from_contrast_filter&lt;/td&gt;
 &lt;td&gt;排除对比度滤镜&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;is_vector_based&lt;/td&gt;
 &lt;td&gt;矢量图&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;is_opaque&lt;/td&gt;
 &lt;td&gt;不透明&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4-7&lt;/td&gt;
 &lt;td&gt;bitmap_encoding&lt;/td&gt;
 &lt;td&gt;位图编码子类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;8&lt;/td&gt;
 &lt;td&gt;opt_out_of_thinning&lt;/td&gt;
 &lt;td&gt;不参与 Thinning&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;9&lt;/td&gt;
 &lt;td&gt;is_flippable&lt;/td&gt;
 &lt;td&gt;可翻转&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10&lt;/td&gt;
 &lt;td&gt;is_tintable&lt;/td&gt;
 &lt;td&gt;可着色&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;11&lt;/td&gt;
 &lt;td&gt;preserved_vector_representation&lt;/td&gt;
 &lt;td&gt;保留矢量表示&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;12-31&lt;/td&gt;
 &lt;td&gt;reserved&lt;/td&gt;
 &lt;td&gt;保留位&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="33-encoding-像素编码"&gt;3.3 Encoding (像素编码)
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Tag (4字节)&lt;/th&gt;
 &lt;th&gt;枚举值&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;\0\0\0\0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;None&lt;/td&gt;
 &lt;td&gt;无像素数据&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;BGRA&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;ARGB&lt;/td&gt;
 &lt;td&gt;BGRA 字节序 → RGBA (交换 R/B)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;ATAD&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Data&lt;/td&gt;
 &lt;td&gt;原始数据&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;YARG&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;GRAY&lt;/td&gt;
 &lt;td&gt;灰度 8位&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;GEPJ&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;JPEG&lt;/td&gt;
 &lt;td&gt;JPEG 压缩&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;_FDP&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;PDF&lt;/td&gt;
 &lt;td&gt;PDF 矢量&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;PBEW&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;WEBP&lt;/td&gt;
 &lt;td&gt;WebP 压缩&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;WBGR&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;ARGB16&lt;/td&gt;
 &lt;td&gt;16位 BGRA&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;61AG&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;GA16&lt;/td&gt;
 &lt;td&gt;灰度+Alpha 16位&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;_8AG&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;GA8&lt;/td&gt;
 &lt;td&gt;灰度+Alpha 8位&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;5BGR&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;RGB5&lt;/td&gt;
 &lt;td&gt;XRGB1555 格式&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;_GVS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;SVG&lt;/td&gt;
 &lt;td&gt;SVG 矢量&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FIEH&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;HEIF&lt;/td&gt;
 &lt;td&gt;HEIF 压缩&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="34-colormodel--colorspace"&gt;3.4 ColorModel / ColorSpace
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;ColorModel&lt;/strong&gt; (u32)：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;值&lt;/th&gt;
 &lt;th&gt;名称&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;td&gt;None&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;RGB&lt;/td&gt;
 &lt;td&gt;RGB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;Monochrome&lt;/td&gt;
 &lt;td&gt;单色&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;RGB0&lt;/td&gt;
 &lt;td&gt;RGB (变体)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;RGBP3&lt;/td&gt;
 &lt;td&gt;Display P3&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;ColorSpace&lt;/strong&gt; (u32)：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;值&lt;/th&gt;
 &lt;th&gt;名称&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;sRGB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;GrayGamma2.2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;Display P3&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;Extended Range sRGB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;5&lt;/td&gt;
 &lt;td&gt;Extended Linear sRGB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;6&lt;/td&gt;
 &lt;td&gt;Extended Gray&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;257&lt;/td&gt;
 &lt;td&gt;System sRGB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="35-tlv-元数据-renditiontype"&gt;3.5 TLV 元数据 (RenditionType)
&lt;/h3&gt;&lt;p&gt;TLV (Tag-Length-Value) 格式存储附加元数据，紧跟在 BitmapList 之后。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;packet-beta
 0-31: "tag: u32"
 32-63: "len: u32"
 64-127: "data: [u8; len]"&lt;/pre&gt;
 &lt;blockquote&gt;
 &lt;p&gt;以上为单个 TLV 条目，CSI 中连续存放 N 个 TLV。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Tag&lt;/th&gt;
 &lt;th&gt;名称&lt;/th&gt;
 &lt;th&gt;数据内容&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;1001&lt;/td&gt;
 &lt;td&gt;Slices&lt;/td&gt;
 &lt;td&gt;九宫格切片信息 (x, y, w, h) × N&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1003&lt;/td&gt;
 &lt;td&gt;Metrics&lt;/td&gt;
 &lt;td&gt;上右内边距 + 下左内边距 + 图像尺寸&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1004&lt;/td&gt;
 &lt;td&gt;BlendModeAndOpacity&lt;/td&gt;
 &lt;td&gt;blend_mode: u32 + opacity: f32&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1005&lt;/td&gt;
 &lt;td&gt;UTI&lt;/td&gt;
 &lt;td&gt;统一类型标识符 (如 &lt;code&gt;&amp;quot;public.png&amp;quot;&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1006&lt;/td&gt;
 &lt;td&gt;EXIFOrientation&lt;/td&gt;
 &lt;td&gt;EXIF 旋转方向 (0-8)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1007&lt;/td&gt;
 &lt;td&gt;BytesPerRow&lt;/td&gt;
 &lt;td&gt;行字节步长 (stride)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1010&lt;/td&gt;
 &lt;td&gt;Reference&lt;/td&gt;
 &lt;td&gt;内部引用 (magic &lt;code&gt;&amp;quot;INLK&amp;quot;&lt;/code&gt; + 坐标 + 键)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="36-rendition-数据类型"&gt;3.6 Rendition 数据类型
&lt;/h3&gt;&lt;p&gt;Rendition 是 CSI 中的实际载荷数据，按 magic 标识区分类型：&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;graph TD
 R["Rendition (可选)"]
 R --&gt; |"magic: RLOC"| COLOR["Color&lt;br/&gt;色彩空间 + 分量值 (f64[])"]
 R --&gt; |"magic: DWAR"| RAW["RawData&lt;br/&gt;原始二进制数据"]
 R --&gt; |"magic: MLEC"| CBCK["ThemeCBCK&lt;br/&gt;图像数据 (最常见)"]
 R --&gt; |"magic: SISM"| MSIS["MultisizeImageSet&lt;br/&gt;多尺寸图集"]

 CBCK --&gt; V0["v0/v2: 单块数据"]
 CBCK --&gt; V1["v1/v3: 多块数据&lt;br/&gt;(ThemePartHeader)"]

 style R fill:#4a9eff,color:#fff
 style CBCK fill:#ff6b6b,color:#fff&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;RenditionColor&lt;/strong&gt; (&lt;code&gt;RLOC&lt;/code&gt;)：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;类型&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;version&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;版本&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;color_space&lt;/td&gt;
 &lt;td&gt;ColorSpace&lt;/td&gt;
 &lt;td&gt;色彩空间&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;components&lt;/td&gt;
 &lt;td&gt;Vec&amp;lt;f64&amp;gt;&lt;/td&gt;
 &lt;td&gt;颜色分量&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;RenditionThemeCBCK&lt;/strong&gt; (&lt;code&gt;MLEC&lt;/code&gt; - 最常见)：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;类型&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;version&lt;/td&gt;
 &lt;td&gt;u32&lt;/td&gt;
 &lt;td&gt;版本 (0-3)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;compression_type&lt;/td&gt;
 &lt;td&gt;CompressionType&lt;/td&gt;
 &lt;td&gt;压缩类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;raw_datas&lt;/td&gt;
 &lt;td&gt;Vec&amp;lt;Vec&amp;lt;u8&amp;gt;&amp;gt;&lt;/td&gt;
 &lt;td&gt;压缩数据块&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="37-compressiontype"&gt;3.7 CompressionType
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;值&lt;/th&gt;
 &lt;th&gt;名称&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;td&gt;Uncompressed&lt;/td&gt;
 &lt;td&gt;未压缩&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;Rle&lt;/td&gt;
 &lt;td&gt;行程编码&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;Zip&lt;/td&gt;
 &lt;td&gt;Zip 压缩&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;Lzvn&lt;/td&gt;
 &lt;td&gt;LZVN 压缩&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;Lzfse&lt;/td&gt;
 &lt;td&gt;LZFSE 压缩&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;5&lt;/td&gt;
 &lt;td&gt;JpegLzfse&lt;/td&gt;
 &lt;td&gt;JPEG + LZFSE&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;6&lt;/td&gt;
 &lt;td&gt;Blurred&lt;/td&gt;
 &lt;td&gt;模糊处理&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;7&lt;/td&gt;
 &lt;td&gt;Astc&lt;/td&gt;
 &lt;td&gt;ASTC 纹理压缩&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;8&lt;/td&gt;
 &lt;td&gt;PaletteImg&lt;/td&gt;
 &lt;td&gt;调色板图像&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;9&lt;/td&gt;
 &lt;td&gt;HEVC&lt;/td&gt;
 &lt;td&gt;HEVC 视频帧&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10&lt;/td&gt;
 &lt;td&gt;DeepmapLzfse&lt;/td&gt;
 &lt;td&gt;Deepmap + LZFSE&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;11&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;Deepmap2&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;Deepmap2 格式 (见第 4 节)&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="38-layouttype"&gt;3.8 LayoutType
&lt;/h3&gt;&lt;p&gt;布局类型决定了渲染项的用途和展示方式：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;范围&lt;/th&gt;
 &lt;th&gt;类别&lt;/th&gt;
 &lt;th&gt;示例&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;6-9&lt;/td&gt;
 &lt;td&gt;特效&lt;/td&gt;
 &lt;td&gt;Gradient(6), Effect(7), Vector(9)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10-12&lt;/td&gt;
 &lt;td&gt;单部件&lt;/td&gt;
 &lt;td&gt;FixedSize(10), Tile(11), Scale(12)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;20-25&lt;/td&gt;
 &lt;td&gt;三段式&lt;/td&gt;
 &lt;td&gt;H-Tile(20), H-Scale(21), V-Tile(23)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;30-34&lt;/td&gt;
 &lt;td&gt;九宫格&lt;/td&gt;
 &lt;td&gt;Tile(30), Scale(31), EdgesOnly(34)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;40&lt;/td&gt;
 &lt;td&gt;六段式&lt;/td&gt;
 &lt;td&gt;SixPart&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;50&lt;/td&gt;
 &lt;td&gt;动画&lt;/td&gt;
 &lt;td&gt;AnimationFilmstrip&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1000-1014&lt;/td&gt;
 &lt;td&gt;语义类型&lt;/td&gt;
 &lt;td&gt;Data, ExternalLink, Color, Texture&amp;hellip;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="39-idiom-设备类型"&gt;3.9 Idiom (设备类型)
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;值&lt;/th&gt;
 &lt;th&gt;名称&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;td&gt;Universal&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;Phone (iPhone)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;Pad (iPad)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;TV (Apple TV)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;Car (CarPlay)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;5&lt;/td&gt;
 &lt;td&gt;Watch (Apple Watch)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;6&lt;/td&gt;
 &lt;td&gt;Marketing&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="4-deepmap2-图像编码"&gt;4. Deepmap2 图像编码
&lt;/h2&gt;&lt;p&gt;Deepmap2 是 Apple 的专有图像编码格式，支持 4 种解码模式：原始像素、有损预测压缩 (YCoCg)、无损压缩和调色板索引。&lt;/p&gt;
&lt;h3 id="41-deepmap2header"&gt;4.1 Deepmap2Header
&lt;/h3&gt;&lt;p&gt;Magic: &lt;code&gt;&amp;quot;dmp2&amp;quot;&lt;/code&gt; (小端序)&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;偏移&lt;/th&gt;
 &lt;th&gt;大小&lt;/th&gt;
 &lt;th&gt;字段&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;0x00&lt;/td&gt;
 &lt;td&gt;4B&lt;/td&gt;
 &lt;td&gt;magic&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;quot;dmp2&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x04&lt;/td&gt;
 &lt;td&gt;1B&lt;/td&gt;
 &lt;td&gt;decode_type&lt;/td&gt;
 &lt;td&gt;解码类型 (1-4)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x05&lt;/td&gt;
 &lt;td&gt;1B&lt;/td&gt;
 &lt;td&gt;version&lt;/td&gt;
 &lt;td&gt;色度缩放标志&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x06&lt;/td&gt;
 &lt;td&gt;1B&lt;/td&gt;
 &lt;td&gt;predictor_type&lt;/td&gt;
 &lt;td&gt;辅助标志&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x07&lt;/td&gt;
 &lt;td&gt;1B&lt;/td&gt;
 &lt;td&gt;pixel_format&lt;/td&gt;
 &lt;td&gt;像素格式 (1-4)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x08&lt;/td&gt;
 &lt;td&gt;2B&lt;/td&gt;
 &lt;td&gt;width&lt;/td&gt;
 &lt;td&gt;图像宽度&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x0A&lt;/td&gt;
 &lt;td&gt;2B&lt;/td&gt;
 &lt;td&gt;height&lt;/td&gt;
 &lt;td&gt;图像高度&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x0C&lt;/td&gt;
 &lt;td&gt;2B&lt;/td&gt;
 &lt;td&gt;palette_size&lt;/td&gt;
 &lt;td&gt;调色板条目数 (仅 Palette 类型)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x0E&lt;/td&gt;
 &lt;td&gt;2B&lt;/td&gt;
 &lt;td&gt;palette_type&lt;/td&gt;
 &lt;td&gt;调色板类型 (仅 Palette 类型)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;0x10&lt;/td&gt;
 &lt;td&gt;N×4B&lt;/td&gt;
 &lt;td&gt;palette&lt;/td&gt;
 &lt;td&gt;调色板数据 BGRA (仅 Palette 类型)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;DecodeType&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;值&lt;/th&gt;
 &lt;th&gt;名称&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;None&lt;/td&gt;
 &lt;td&gt;原始未压缩像素&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;Default&lt;/td&gt;
 &lt;td&gt;LZFSE + Zigzag + 预测 + YCoCg&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;Lossless&lt;/td&gt;
 &lt;td&gt;LZFSE 压缩 (无预测)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;Palette&lt;/td&gt;
 &lt;td&gt;调色板索引&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;PixelFormat&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;值&lt;/th&gt;
 &lt;th&gt;名称&lt;/th&gt;
 &lt;th&gt;每像素字节&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;G8&lt;/td&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;灰度&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;GA88&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;灰度 + Alpha&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;Rgb888&lt;/td&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;RGB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;Rgba8888&lt;/td&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;RGBA&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="42-解码流程总览"&gt;4.2 解码流程总览
&lt;/h3&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TD
 INPUT["输入数据"] --&gt; MAGIC{检测 Magic}
 MAGIC --&gt; |"'dmp2'"| DMP2["解析 Deepmap2Header"]
 MAGIC --&gt; |"'KCBC'"| KCBC["KCBC 分块容器"]

 DMP2 --&gt; PAYLOAD["提取 Payload"]
 PAYLOAD --&gt; TYPE{decode_type?}

 TYPE --&gt; |"1: None"| NONE["直接读取原始像素"]
 TYPE --&gt; |"2: Default"| DEFAULT["LZFSE 解压缩"]
 TYPE --&gt; |"3: Lossless"| LOSSLESS["LZFSE 解压缩"]
 TYPE --&gt; |"4: Palette"| PALETTE["LZFSE 解压缩"]

 DEFAULT --&gt; MULTI["解析多流布局&lt;br/&gt;[alpha][predictors][high][low]"]
 MULTI --&gt; ZIGZAG["Zigzag 解码&lt;br/&gt;(合并高低字节流)"]
 ZIGZAG --&gt; PRED["应用预测器&lt;br/&gt;(还原差分)"]
 PRED --&gt; YCOCG["YCoCg → RGB 转换"]
 YCOCG --&gt; RGBA1["RGBA 输出"]

 LOSSLESS --&gt; DIRECT["直接像素格式转换"]
 NONE --&gt; DIRECT
 DIRECT --&gt; RGBA2["RGBA 输出"]

 PALETTE --&gt; PLOOKUP["调色板查表"]
 PLOOKUP --&gt; RGBA3["RGBA 输出"]

 KCBC --&gt; TILES["解析分块&lt;br/&gt;(col, row, dmp2 子数据)"]
 TILES --&gt; EACH["逐块独立解码 dmp2"]
 EACH --&gt; GRID["按网格拼合"]
 GRID --&gt; RGBA4["RGBA 输出"]

 style INPUT fill:#4a9eff,color:#fff
 style RGBA1 fill:#51cf66,color:#fff
 style RGBA2 fill:#51cf66,color:#fff
 style RGBA3 fill:#51cf66,color:#fff
 style RGBA4 fill:#51cf66,color:#fff
 style DEFAULT fill:#ff6b6b,color:#fff&lt;/pre&gt;&lt;h3 id="43-default-解码-type-2-详解"&gt;4.3 Default 解码 (Type 2) 详解
&lt;/h3&gt;&lt;p&gt;这是最复杂的解码路径，使用 LZFSE 压缩 + 多流分离 + Zigzag 编码 + 空间预测 + YCoCg 色彩模型。&lt;/p&gt;
&lt;h4 id="431-lzfse-解压后的内存布局"&gt;4.3.1 LZFSE 解压后的内存布局
&lt;/h4&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;block-beta
 columns 1
 A["Alpha 平面 — width x height 字节 (仅 has_alpha)"]
 B["预测器字节 — height 字节 (每行一个预测器类型)"]
 C["High 字节流 — width x height x components 字节"]
 D["Low 字节流 — width x height x components 字节"]

 style A fill:#ffd43b,color:#333
 style B fill:#51cf66,color:#fff
 style C fill:#4a9eff,color:#fff
 style D fill:#ff6b6b,color:#fff&lt;/pre&gt;&lt;p&gt;其中 &lt;code&gt;components&lt;/code&gt; = 3 (彩色, YCoCg 三通道) 或 1 (灰度)。&lt;/p&gt;
&lt;h4 id="432-zigzag-解码"&gt;4.3.2 Zigzag 解码
&lt;/h4&gt;&lt;p&gt;将分离的高低字节流合并为有符号 16 位值：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;combined = (lo as u16) | ((hi as u16) &amp;lt;&amp;lt; 8)
magnitude = combined &amp;gt;&amp;gt; 1
value = if (combined &amp;amp; 1) != 0 { -magnitude } else { magnitude }
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="433-预测器算法"&gt;4.3.3 预测器算法
&lt;/h4&gt;&lt;p&gt;每行可独立选择预测器，有 5 种类型：&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;graph LR
 subgraph "预测器类型"
 P0["0: None&lt;br/&gt;无预测&lt;br/&gt;直接输出"]
 P1["1: Paeth&lt;br/&gt;vImage Paeth&lt;br/&gt;选择 left 或 up"]
 P2["2: Left&lt;br/&gt;左邻预测&lt;br/&gt;累加和"]
 P3["3: Up&lt;br/&gt;上邻预测&lt;br/&gt;逐元素加"]
 P4["4: Mean&lt;br/&gt;均值预测&lt;br/&gt;(left+up+1)/2"]
 end

 style P1 fill:#ff6b6b,color:#fff
 style P2 fill:#ffd43b,color:#333
 style P3 fill:#51cf66,color:#fff
 style P4 fill:#4a9eff,color:#fff&lt;/pre&gt;&lt;p&gt;所有预测器以 3 个分量为一组 (PREDICTOR_GROUP_SIZE=3) 进行处理，对应 YCoCg 的 Y、Co、Cg 三通道。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Paeth 预测器&lt;/strong&gt; (简化版)：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;对每组 3 个分量:
 dist_left = |up[0] - up_left[0]|
 dist_up = |left[0] - up_left[0]|
 若 dist_left &amp;lt;= dist_up: 整组使用 left
 否则: 整组使用 up
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="434-ycocg--rgb-转换"&gt;4.3.4 YCoCg → RGB 转换
&lt;/h4&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;co_scaled = Co &amp;lt;&amp;lt; chroma_scale
cg_scaled = Cg &amp;lt;&amp;lt; chroma_scale
temp = Y - trunc_div2(cg_scaled)

R = clamp(temp + co_scaled - trunc_div2(co_scaled), 0, 255)
G = clamp(temp + cg_scaled, 0, 255)
B = clamp(temp - trunc_div2(co_scaled), 0, 255)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;其中 &lt;code&gt;chroma_scale&lt;/code&gt; = 1 (header.version ≠ 0) 或 0。&lt;/p&gt;
&lt;h3 id="44-palette-解码-type-4"&gt;4.4 Palette 解码 (Type 4)
&lt;/h3&gt;&lt;p&gt;调色板模式使用索引查表，支持两种子类型：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;palette_type&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;th&gt;Payload 布局&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;Alpha + 索引&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;[alpha × pixel_count][index × pixel_count]&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;仅索引&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;[index × pixel_count]&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;调色板条目格式：u32 LE BGRA → 转换为 RGBA 输出。&lt;/p&gt;
&lt;h3 id="45-kcbc-分块容器"&gt;4.5 KCBC 分块容器
&lt;/h3&gt;&lt;p&gt;大图像可使用 KCBC 容器将图像分块存储，每块独立编码。&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;packet-beta
 0-31: "'KCBC' (magic)"
 32-63: "col: u32"
 64-95: "row: u32"
 96-127: "rows: u32"
 128-159: "len: u32"
 160-287: "dmp2 子数据 (len 字节)"&lt;/pre&gt;
 &lt;blockquote&gt;
 &lt;p&gt;以上为单个 KCBC Block，文件中连续存放多个 Block。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;解码后按 (row, col) 网格拼合为完整图像。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="5-端到端数据流"&gt;5. 端到端数据流
&lt;/h2&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TB
 subgraph "1. 文件打开"
 FILE["Assets.car"] --&gt; MMAP["内存映射 (mmap)"]
 MMAP --&gt; BOM_PARSE["解析 BOM 容器&lt;br/&gt;(大端序)"]
 end

 subgraph "2. 索引构建"
 BOM_PARSE --&gt; KF["读取 KEYFORMAT&lt;br/&gt;确定属性类型序列"]
 KF --&gt; FK["读取 FACETKEYS&lt;br/&gt;构建名称→属性映射"]
 FK --&gt; RD["遍历 RENDITIONS 树&lt;br/&gt;解析每个 CSI"]
 RD --&gt; DB["构建 MultiMap&amp;lt;u16, CSIItem&amp;gt;&lt;br/&gt;按 Identifier 索引"]
 end

 subgraph "3. 资源查找"
 QUERY["查询 'AppIcon'"] --&gt; FACET["FACETKEYS 查表&lt;br/&gt;→ Identifier=0x42"]
 FACET --&gt; LOOKUP["rendition_db.get(0x42)&lt;br/&gt;→ 多个渲染变体"]
 LOOKUP --&gt; FILTER["按 Scale/Idiom 等筛选"]
 end

 subgraph "4. 图像解码"
 FILTER --&gt; CSI_ITEM["CSIItem"]
 CSI_ITEM --&gt; COMP{压缩类型?}
 COMP --&gt; |"Lzfse"| LZFSE_DEC["LZFSE 解压缩"]
 COMP --&gt; |"Deepmap2"| DMP2_DEC["Deepmap2 解码&lt;br/&gt;(预测+YCoCg)"]
 COMP --&gt; |"Uncompressed"| UNCOMP["直接读取"]
 COMP --&gt; |"JPEG/WebP"| IMG_DEC["图像库解码"]
 LZFSE_DEC --&gt; PIXEL["像素格式转换&lt;br/&gt;→ RGBA"]
 DMP2_DEC --&gt; PIXEL
 UNCOMP --&gt; PIXEL
 IMG_DEC --&gt; PIXEL
 end

 PIXEL --&gt; OUTPUT["输出图像"]

 style FILE fill:#4a9eff,color:#fff
 style DB fill:#ff6b6b,color:#fff
 style OUTPUT fill:#51cf66,color:#fff&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="6-magic-字节汇总"&gt;6. Magic 字节汇总
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Magic&lt;/th&gt;
 &lt;th&gt;字节序&lt;/th&gt;
 &lt;th&gt;层级&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;BOMStore&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;-&lt;/td&gt;
 &lt;td&gt;BOM&lt;/td&gt;
 &lt;td&gt;文件头标识&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;tree&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;-&lt;/td&gt;
 &lt;td&gt;BOM&lt;/td&gt;
 &lt;td&gt;B-Tree 头标识&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;RATC&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;LE&lt;/td&gt;
 &lt;td&gt;CAR&lt;/td&gt;
 &lt;td&gt;CARHEADER&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;ISTC&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;LE&lt;/td&gt;
 &lt;td&gt;CAR&lt;/td&gt;
 &lt;td&gt;CSIHeader&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;tmfk&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;LE&lt;/td&gt;
 &lt;td&gt;CAR&lt;/td&gt;
 &lt;td&gt;KeyFmt&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;META&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;BE&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;CAR&lt;/td&gt;
 &lt;td&gt;ExtendedMetadata&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;RLOC&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;LE&lt;/td&gt;
 &lt;td&gt;Rendition&lt;/td&gt;
 &lt;td&gt;Color 类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;DWAR&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;LE&lt;/td&gt;
 &lt;td&gt;Rendition&lt;/td&gt;
 &lt;td&gt;RawData 类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;MLEC&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;LE&lt;/td&gt;
 &lt;td&gt;Rendition&lt;/td&gt;
 &lt;td&gt;ThemeCBCK 类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;SISM&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;LE&lt;/td&gt;
 &lt;td&gt;Rendition&lt;/td&gt;
 &lt;td&gt;MultisizeImageSet&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;INLK&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;LE&lt;/td&gt;
 &lt;td&gt;TLV&lt;/td&gt;
 &lt;td&gt;Reference 引用&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;dmp2&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;LE&lt;/td&gt;
 &lt;td&gt;Deepmap2&lt;/td&gt;
 &lt;td&gt;Deepmap2 图像头&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;KCBC&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;LE&lt;/td&gt;
 &lt;td&gt;Deepmap2&lt;/td&gt;
 &lt;td&gt;分块容器头&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="7-字节序规则"&gt;7. 字节序规则
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;层级&lt;/th&gt;
 &lt;th&gt;字节序&lt;/th&gt;
 &lt;th&gt;例外&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;BOM 容器&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;大端序&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;CAR 结构&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;小端序&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;ExtendedMetadata (&lt;code&gt;META&lt;/code&gt;) 使用大端序&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;CSI / Rendition&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;小端序&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Deepmap2&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;小端序&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="参考链接"&gt;参考链接
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.timac.org/2018/1018-reverse-engineering-the-car-file-format/" target="_blank" rel="noopener"
 &gt;Reverse engineering the .car file format (compiled Asset Catalogs)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://dbg.re/posts/car-file-format/" target="_blank" rel="noopener"
 &gt;A Deep Dive into Apple&amp;rsquo;s .car File Format&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/vaguilar/carutil" target="_blank" rel="noopener"
 &gt;vaguilar/carutil&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/facebookarchive/xcbuild" target="_blank" rel="noopener"
 &gt;facebookarchive/xcbuild&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/iineva/bom" target="_blank" rel="noopener"
 &gt;iineva/bom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>ShortUUID - UUID生成对应缩短的字符</title><link>https://blog.skytoup.com/p/shortuuid-uuid%E7%94%9F%E6%88%90%E5%AF%B9%E5%BA%94%E7%BC%A9%E7%9F%AD%E7%9A%84%E5%AD%97%E7%AC%A6/</link><pubDate>Sun, 27 Jun 2021 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/shortuuid-uuid%E7%94%9F%E6%88%90%E5%AF%B9%E5%BA%94%E7%BC%A9%E7%9F%AD%E7%9A%84%E5%AD%97%E7%AC%A6/</guid><description>
 &lt;blockquote&gt;
 &lt;p&gt;这个库最开始是&lt;code&gt;python&lt;/code&gt;的版本&lt;a class="link" href="https://github.com/skorokithakis/shortuuid" target="_blank" rel="noopener"
 &gt;https://github.com/skorokithakis/shortuuid&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;后来还有一个&lt;code&gt;Go&lt;/code&gt;的版本&lt;a class="link" href="https://github.com/lithammer/shortuuid" target="_blank" rel="noopener"
 &gt;https://github.com/lithammer/shortuuid&lt;/a&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;UUID字符长度为32(去掉&lt;code&gt;-&lt;/code&gt;), ShortUUID默认生成字符长度为20, 所以在以前在&lt;code&gt;python&lt;/code&gt;项目中作为短的唯一标识生成, 趁着有空试试撸一个&lt;code&gt;swift&lt;/code&gt;的版本&lt;a class="link" href="https://github.com/skytoup/shortuuid" target="_blank" rel="noopener"
 &gt;https://github.com/skytoup/shortuuid&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;刚开始分析&lt;code&gt;python&lt;/code&gt;版的源码, 发现设计得还挺简单的。所有算法逻辑都在一个文件, 源码也就&lt;code&gt;141行&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="uuid简介"&gt;UUID简介
&lt;/h2&gt;&lt;p&gt;全称&lt;code&gt;Universally Unique Identifier&lt;/code&gt;, 是通用唯一识别码, 由128 bit(16 byte)的数值组成。&lt;/p&gt;
&lt;p&gt;具体介绍: &lt;a class="link" href="https://baike.baidu.com/item/UUID/5921266?fr=aladdin" target="_blank" rel="noopener"
 &gt;https://baike.baidu.com/item/UUID/5921266?fr=aladdin&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="算法大概流程"&gt;算法大概流程
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;ShortUUID&lt;/code&gt;包含一组字符&lt;code&gt;Alphabet&lt;/code&gt;用于生成&lt;code&gt;短UUID&lt;/code&gt;的字符, 以&lt;code&gt;ascii&lt;/code&gt;码小到大排序并且不重复。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;UUID&lt;/code&gt;转(encode)&lt;code&gt;short UUID&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;把&lt;code&gt;UUID&lt;/code&gt;作为数据不断整除&lt;code&gt;Alphabet&lt;/code&gt;的长度, 并以&lt;code&gt;余数&lt;/code&gt;作为索引选取&lt;code&gt;Alphabet&lt;/code&gt;的字符, 直至被除数为0, 最后组成的字符翻转。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;伪代码&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;while UUID &amp;gt; 0:
	UUID, rem = UUID / Alphabet.length, UUID % Alphabet.length
	`short uuid` += `Alphabet`[rem]

`short uuid`.reverse()
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;short UUID&lt;/code&gt;转(decode)&lt;code&gt;UUID&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;就是把&lt;code&gt;encode&lt;/code&gt;的算发反转, &lt;code&gt;UUID&lt;/code&gt;(初始为0)作为数据乘以&lt;code&gt;Alphabet&lt;/code&gt;的长度, 再加上&lt;code&gt;short UUID&lt;/code&gt;对应&lt;code&gt;Alphabet&lt;/code&gt;的索引位置。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;伪代码&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;UUID = 0
for char in `short UUID`:
	UUID * `Alphabet`.length + `Alphabet`.indexOf(char)
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="看似简单-实现起来还是有些难度"&gt;看似简单, 实现起来还是有些难度
&lt;/h2&gt;&lt;h3 id="大数运算"&gt;大数运算
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;UUID&lt;/code&gt;为&lt;code&gt;128 bit&lt;/code&gt;的数据, &lt;code&gt;python&lt;/code&gt;自带大数运算功能, 但&lt;code&gt;swift&lt;/code&gt;的最大位数&lt;code&gt;Int&lt;/code&gt;也只有&lt;code&gt;UInt64&lt;/code&gt;和&lt;code&gt;Int64&lt;/code&gt;, 即大&lt;strong&gt;正&lt;/strong&gt;整数运算只能用进行&lt;code&gt;64 bit&lt;/code&gt;进行运算。而且在标准库中暂未发现有大数运算的相关支持库, 所以只能写一个。&lt;/p&gt;
&lt;p&gt;这个算法仅用到&lt;code&gt;128 bit&lt;/code&gt;的运算有&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;除并且求余&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;乘&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;加&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;主要实现思路是只拆分为&lt;code&gt;32 bit&lt;/code&gt;的数据进行分别运算, 最后把拆分的运算结果组合为&lt;code&gt;128 bit&lt;/code&gt;运算结果(具体实现看源码)&lt;/p&gt;
&lt;h3 id="uuid5"&gt;UUID5
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;python&lt;/code&gt;标准库有相关实现, 但&lt;code&gt;swift&lt;/code&gt;没有。实现也比较简单, 主要流程是&lt;code&gt;namespace&lt;/code&gt;对应&lt;code&gt;UUID bytes&lt;/code&gt;拼上&lt;code&gt;input string&lt;/code&gt;再进行&lt;code&gt;SHA1&lt;/code&gt;(结果为&lt;code&gt;160 bit&lt;/code&gt;), 取前&lt;code&gt;128 bit&lt;/code&gt;修改部分数据即可。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;相关链接&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;python uuid源码: &lt;a class="link" href="https://github.com/python/cpython/blob/main/Lib/uuid.py" target="_blank" rel="noopener"
 &gt;https://github.com/python/cpython/blob/main/Lib/uuid.py&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;oc的uuid5源码: &lt;a class="link" href="https://gist.github.com/eliburke/1a55ed616bb15a7f908b" target="_blank" rel="noopener"
 &gt;https://gist.github.com/eliburke/1a55ed616bb15a7f908b&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>dsymutil 程序调试符号帮助工具</title><link>https://blog.skytoup.com/p/dsymutil-%E7%A8%8B%E5%BA%8F%E8%B0%83%E8%AF%95%E7%AC%A6%E5%8F%B7%E5%B8%AE%E5%8A%A9%E5%B7%A5%E5%85%B7/</link><pubDate>Tue, 22 Jun 2021 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/dsymutil-%E7%A8%8B%E5%BA%8F%E8%B0%83%E8%AF%95%E7%AC%A6%E5%8F%B7%E5%B8%AE%E5%8A%A9%E5%B7%A5%E5%85%B7/</guid><description>&lt;h3 id="简介"&gt;简介
&lt;/h3&gt;&lt;p&gt;操作归档的DWARF调试符号文件&lt;/p&gt;
&lt;h3 id="场景一"&gt;场景一
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;打包有开启&lt;code&gt;bitcode&lt;/code&gt;, 上传时没有勾选上传&lt;code&gt;符号文件&lt;/code&gt;。
结果iTunes后台处理完安装包后, 不会有&lt;code&gt;下载dSYM文件&lt;/code&gt;, 导致该安装包发生的闪退日志无法还原符号, 只能看到一堆地址。&lt;/p&gt;
&lt;p&gt;&lt;img alt="upload" class="gallery-image" data-flex-basis="405px" data-flex-grow="169" height="434" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/dsymutil-%E7%A8%8B%E5%BA%8F%E8%B0%83%E8%AF%95%E7%AC%A6%E5%8F%B7%E5%B8%AE%E5%8A%A9%E5%B7%A5%E5%85%B7/20210622_01.png" width="734"&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;解决方法&lt;/p&gt;
&lt;ol start="0"&gt;
&lt;li&gt;找到对应打包的的&lt;code&gt;***.xcarchive&lt;/code&gt;归档文件, 点击&lt;code&gt;右键&lt;/code&gt;选择&lt;code&gt;查看包内容(Show Package Contents)&lt;/code&gt;, 看到里面有两个符号表相关的文件夹, 分别是&lt;code&gt;BCSymbbolMaps&lt;/code&gt;和&lt;code&gt;dSYMs&lt;/code&gt;。
&lt;ul&gt;
&lt;li&gt;虽然这里有&lt;code&gt;dSYMs&lt;/code&gt;, 但是是隐藏了部分符号的, 直接使用会导致还原的堆栈信息显示很多&lt;code&gt;hidden&lt;/code&gt;符号。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;打开&lt;code&gt;终端&lt;/code&gt;并切换当前工作目录到你的&lt;code&gt;***.xcarchive&lt;/code&gt;(即&lt;code&gt;cd /....../***.xcarchive&lt;/code&gt;), 再输入命令&lt;code&gt;dsymutil --symbol-map BCSymbolMaps dSYMs/*&lt;/code&gt;, 即可把&lt;code&gt;BCSymbolMaps&lt;/code&gt;内的符号信息更新到&lt;code&gt;dSYMs&lt;/code&gt;目录下的对应文件&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="场景2"&gt;场景2
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;在开发周期内, 打的一些测试包没有上传符号文件, 后来这个安装包发生闪退的情况, 想还原堆栈时发现该打包的相关文件已经被清理。&lt;/p&gt;
&lt;p&gt;或者最近看到有些开发者说&lt;code&gt;bugly&lt;/code&gt;和&lt;code&gt;UMeng&lt;/code&gt;的线上闪退堆栈无法还原, 而且上传了对应的&lt;code&gt;dSYM&lt;/code&gt;, 可以先尝试到&lt;code&gt;iTunes&lt;/code&gt;后台下载对应包&lt;code&gt;dSYM&lt;/code&gt;上传试试, 还是不行可以往下看试试。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;解决方法&lt;/p&gt;
&lt;ol start="0"&gt;
&lt;li&gt;获取发生闪退的&lt;code&gt;ipa&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;已上线
&lt;ul&gt;
&lt;li&gt;打包后归档的文件里面, 有一个&lt;code&gt;***.ipa&lt;/code&gt;的文件&lt;/li&gt;
&lt;li&gt;越狱设备安装该线上包后, 进行脱壳提取&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;日常开发测试(上传到类似&lt;code&gt;fir&lt;/code&gt;、&lt;code&gt;pgyer&lt;/code&gt;的网址)
&lt;ul&gt;
&lt;li&gt;打包后归档的文件里面, 有一个&lt;code&gt;***.ipa&lt;/code&gt;的文件&lt;/li&gt;
&lt;li&gt;到对应地方下载安装的&lt;code&gt;***.ipa&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;解压&lt;code&gt;***.ipa&lt;/code&gt;, 对app的主二进制文件(&lt;code&gt;Payload/***.app/***&lt;/code&gt;)使用&lt;code&gt;restore-symbol&lt;/code&gt;(&lt;a class="link" href="https://github.com/tobefuturer/restore-symbol" target="_blank" rel="noopener"
 &gt;https://github.com/tobefuturer/restore-symbol&lt;/a&gt;)进行部分被裁的符号表还原
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;restore-symbol&lt;/code&gt;(&lt;a class="link" href="https://github.com/tobefuturer/restore-symbol" target="_blank" rel="noopener"
 &gt;https://github.com/tobefuturer/restore-symbol&lt;/a&gt;)的使用请参考该工具, 主要是根据&lt;code&gt;class-dump&lt;/code&gt;恢复&lt;code&gt;OC&lt;/code&gt;的对应符号信息更新到到&lt;code&gt;mach-o&lt;/code&gt;, 也有一些fork分支有实现恢复&lt;code&gt;swift&lt;/code&gt;的符号还原&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;终端执行命令&lt;code&gt;dsymutil {替换为上一步已还原符号的二进制文件路径} -o {替换为dSYMs输出的目录路径}&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;例如&lt;code&gt;dsymutil testBin -o ./dSYMs&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="参考链接"&gt;参考链接
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;dsymutil - man: &lt;a class="link" href="https://llvm.org/docs/CommandGuide/dsymutil.html" target="_blank" rel="noopener"
 &gt;https://llvm.org/docs/CommandGuide/dsymutil.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Apple Docs - Restore-Hidden-Symbols: &lt;a class="link" href="https://developer.apple.com/documentation/xcode/adding-identifiable-symbol-names-to-a-crash-report#Restore-Hidden-Symbols" target="_blank" rel="noopener"
 &gt;https://developer.apple.com/documentation/xcode/adding-identifiable-symbol-names-to-a-crash-report#Restore-Hidden-Symbols&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>2021 Cocoapods新手进阶指南之仓库源</title><link>https://blog.skytoup.com/p/2021-cocoapods%E6%96%B0%E6%89%8B%E8%BF%9B%E9%98%B6%E6%8C%87%E5%8D%97%E4%B9%8B%E4%BB%93%E5%BA%93%E6%BA%90/</link><pubDate>Wed, 28 Apr 2021 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/2021-cocoapods%E6%96%B0%E6%89%8B%E8%BF%9B%E9%98%B6%E6%8C%87%E5%8D%97%E4%B9%8B%E4%BB%93%E5%BA%93%E6%BA%90/</guid><description>
 &lt;blockquote&gt;
 &lt;p&gt;老鸟可略过&amp;hellip;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="仓库源"&gt;仓库源
&lt;/h3&gt;&lt;p&gt;在&lt;code&gt;Cocoapods&lt;/code&gt; &lt;code&gt;1.7.2&lt;/code&gt;版本前, 首次安装还需要初始化好几个&lt;code&gt;GB&lt;/code&gt;的&lt;code&gt;仓库源&lt;/code&gt;(git方式拉取, 源为&lt;code&gt;github&lt;/code&gt;), 拉起速度又慢, 而且改非常大。&lt;/p&gt;
&lt;p&gt;后来在&lt;code&gt;1.7.0&lt;/code&gt;提出一个实验性方案, 把&lt;code&gt;git方式的仓库源&lt;/code&gt;改为&lt;code&gt;CDN方式的仓库源&lt;/code&gt;, 最后在&lt;code&gt;1.7.2&lt;/code&gt;正式启用。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;旧的仓库源: &lt;code&gt;https://github.com/CocoaPods/Specs.git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;新的仓库源: &lt;code&gt;https://cdn.cocoapods.org/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cocoapods相关目录及结构"&gt;&lt;code&gt;Cocoapods&lt;/code&gt;相关目录及结构
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;${用户目录}/.cocoapods/repos/${源仓库名称}&lt;/code&gt; # 源仓库&lt;/li&gt;
&lt;li&gt;git源仓库结构
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;${三方库名称}/${版本号}/${spec文件}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CDN源仓库结构(主要结构)
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;all_pods.txt&lt;/code&gt; 所有库的版本号信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;all_pods_versions_${MD5[0]}_${MD5[1]}_${MD5[2]}.txt&lt;/code&gt; 按&lt;code&gt;MD5(库名称)[0...3]&lt;/code&gt;切分文件存储库的版本号信息
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;txt文件&lt;/code&gt;每行一个库, 格式&lt;code&gt;${库名称}/${版本号}/${版本号}/...&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="podfile源仓库三方库关系图"&gt;&lt;code&gt;Podfile&lt;/code&gt;&amp;amp;&lt;code&gt;源仓库&lt;/code&gt;&amp;amp;&lt;code&gt;三方库&lt;/code&gt;关系图
&lt;/h3&gt;&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="623px" data-flex-grow="259" height="382" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/2021-cocoapods%E6%96%B0%E6%89%8B%E8%BF%9B%E9%98%B6%E6%8C%87%E5%8D%97%E4%B9%8B%E4%BB%93%E5%BA%93%E6%BA%90/cp_01_202104_28_01.png" srcset="https://blog.skytoup.com/p/2021-cocoapods%E6%96%B0%E6%89%8B%E8%BF%9B%E9%98%B6%E6%8C%87%E5%8D%97%E4%B9%8B%E4%BB%93%E5%BA%93%E6%BA%90/cp_01_202104_28_01_hu_2ca899a1e19b8276.png 800w, https://blog.skytoup.com/p/2021-cocoapods%E6%96%B0%E6%89%8B%E8%BF%9B%E9%98%B6%E6%8C%87%E5%8D%97%E4%B9%8B%E4%BB%93%E5%BA%93%E6%BA%90/cp_01_202104_28_01.png 992w" width="992"&gt;&lt;/p&gt;
&lt;h3 id="pod-updateinstall的部分简略流程"&gt;&lt;code&gt;pod update/install&lt;/code&gt;的部分简略流程
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;本地源仓库&lt;/code&gt;同步&lt;code&gt;远程源仓库&lt;/code&gt;(&lt;strong&gt;强烈建议&lt;/strong&gt;命令后面添加参数&lt;code&gt;--no-repo-update&lt;/code&gt;略过这步, 有需要同步再手动更新&lt;code&gt;pod repo update&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;按库的名称在本地源仓库查找合适版本号的&lt;code&gt;spec&lt;/code&gt;(git和CDN的源查找方式不一样)&lt;/li&gt;
&lt;li&gt;根据&lt;code&gt;spec&lt;/code&gt;中的&lt;code&gt;source&lt;/code&gt;和其它相关参数下载(&lt;code&gt;git/svn/hg/http&lt;/code&gt;)仓库文件(这步之前还有个本地缓存查找的过程)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="库的名字查找spec"&gt;库的名字查找&lt;code&gt;spec&lt;/code&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;git仓库源
&lt;ul&gt;
&lt;li&gt;根据本地目录结构查找&lt;code&gt;spec文件&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CDN仓库源
&lt;ol&gt;
&lt;li&gt;三方库的名称进行&lt;code&gt;MD5(小写)&lt;/code&gt;, 结果取前&lt;strong&gt;3&lt;/strong&gt;位字母&lt;/li&gt;
&lt;li&gt;访问对应的本地文件(&lt;code&gt;all_pods_versions_${MD5[0]}_${MD5[1]}_${MD5[2]}.txt&lt;/code&gt;)查找合适的版本号&lt;/li&gt;
&lt;li&gt;通过链接&lt;code&gt;https://cdn.cocoapods.org/Specs/${MD5[0]}_${MD5[1]}_${MD5[2]}/${仓库名}/${版本号}/${仓库名}.podspec.json&lt;/code&gt;获取&lt;code&gt;spec文件&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;code&gt;rust&lt;/code&gt;写了个根据&lt;code&gt;podfile.lock&lt;/code&gt;检测库是否有新版本的小工具, 里面就是利用&lt;code&gt;CDN仓库源&lt;/code&gt;方式查找版本, 有兴趣可以去看看&lt;a class="link" href="https://github.com/skytoup/PodHelper" target="_blank" rel="noopener"
 &gt;https://github.com/skytoup/PodHelper&lt;/a&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="源仓库管理命令"&gt;源仓库管理命令
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pod repo&lt;/code&gt; # 列出添加的源&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pod repo add ${源仓库本地名称} ${源仓库链接}&lt;/code&gt; # 添加源&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pod repo remove ${源仓库本地名称} # 移除源, 也可以直接删除&lt;/code&gt;${用户目录}/.cocoapods/repos/${源仓库名称}`&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="相关链接"&gt;相关链接
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;1.7.2更新说明: &lt;a class="link" href="https://blog.cocoapods.org/CocoaPods-1.7.2/" target="_blank" rel="noopener"
 &gt;https://blog.cocoapods.org/CocoaPods-1.7.2/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;podspec.source doc: &lt;a class="link" href="https://guides.cocoapods.org/syntax/podspec.html#source" target="_blank" rel="noopener"
 &gt;https://guides.cocoapods.org/syntax/podspec.html#source&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>2021 Cocoapods新手入门指南</title><link>https://blog.skytoup.com/p/2021-cocoapods%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/</link><pubDate>Tue, 20 Apr 2021 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/2021-cocoapods%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/</guid><description>
 &lt;blockquote&gt;
 &lt;p&gt;老手可完全略过, 其它废话不多说&amp;hellip;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="一-安装"&gt;一. 安装
&lt;/h3&gt;&lt;p&gt;打开终端(&lt;code&gt;Terminal&lt;/code&gt;), 输入命令&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo gem install cocoapods&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;还是提示无法安装可尝试&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo gem install cocoapods --user&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="二-pod命令使用"&gt;二. &lt;code&gt;pod&lt;/code&gt;命令使用
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pod init&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;在项目的根目录运行, 生成一份&lt;code&gt;Podfile&lt;/code&gt;文件&lt;/li&gt;
&lt;li&gt;可自行创建&lt;code&gt;Podfile&lt;/code&gt;文件, 不使用此命令&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pod deintegrate&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;在项目根目录运行, 移除项目&lt;code&gt;cocoapods&lt;/code&gt;依赖管理相关的所有设置(&lt;code&gt;*.xcodeproj&lt;/code&gt;里面的&lt;code&gt;build setting&lt;/code&gt;相关设置), 一般用不到&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pod install&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;按照&lt;code&gt;Podfile&lt;/code&gt;的设置(版本号、仓库索引源&amp;hellip;)安装依赖库, 并且&lt;code&gt;生成&lt;/code&gt;/&lt;code&gt;更新&lt;/code&gt; &lt;code&gt;Podfile.lock&lt;/code&gt;(记录依赖库的依赖关系、版本号、仓库索引源&amp;hellip;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pod update&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;按照&lt;code&gt;Podfile&lt;/code&gt;的设置并结合&lt;code&gt;Podfile.lock&lt;/code&gt;(必须有)进行版本升级&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;一般使用&lt;/strong&gt;&lt;/p&gt;
&lt;ol start="0"&gt;
&lt;li&gt;&lt;code&gt;pod init # 初始化出一份Podfile文件&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Podfile&lt;/code&gt;文件内添加三方库&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pod install # 项目首次安装依赖库&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pod update # 日常根据Podfile设定的规则进行版本更新&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;小技巧&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pod init&lt;/code&gt;和&lt;code&gt;pod update&lt;/code&gt;每次运行都会先更新&lt;code&gt;仓库索引源&lt;/code&gt;数据, 略略费时间, 可以改为手动更新
&lt;ul&gt;
&lt;li&gt;可在后面增加参数&lt;code&gt;--no-repo-update&lt;/code&gt;, 可以&lt;code&gt;安装&lt;/code&gt;/&lt;code&gt;更新&lt;/code&gt;时不更新&lt;code&gt;仓库索引源&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pod install --no-repo-update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pod update --no-repo-update&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;手动更新&lt;code&gt;仓库索引源&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pod repo update&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="三-podfile"&gt;三. Podfile
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;pod init&lt;/code&gt;生成的模板&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# Uncomment the next line to define a global platform for your project
# platform :ios, &amp;#39;9.0&amp;#39;

target &amp;#39;iOSDemo&amp;#39; do
 # Comment the next line if you don&amp;#39;t want to use dynamic frameworks
 use_frameworks!

 # Pods for iOSDemo

end
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;platform&lt;/code&gt;: 设定项目兼容的平台和版本号&lt;/li&gt;
&lt;li&gt;&lt;code&gt;target&lt;/code&gt;: 某个&lt;code&gt;target&lt;/code&gt;依赖库安装配置
&lt;ul&gt;
&lt;li&gt;里面填写一些需要安装的依赖库和配置
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pod {依赖库的名称}&lt;/code&gt;, 比如&lt;code&gt;pod 'AFNetworking'&lt;/code&gt;, &lt;code&gt;pod 'AFNetworking', ~&amp;gt; 1.0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# Uncomment the next line to define a global platform for your project
# platform :ios, &amp;#39;9.0&amp;#39;

target &amp;#39;iOSDemo&amp;#39; do
 # Comment the next line if you don&amp;#39;t want to use dynamic frameworks
 use_frameworks!

 # Pods for iOSDemo
 pod &amp;#39;AFNetworking&amp;#39;
end
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;依赖库版本设置&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;= 0.1&lt;/code&gt; 0.1版本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt; 0.1&lt;/code&gt; 任何大于0.1版本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;= 0.1&lt;/code&gt; 任何大于或等于0.1版本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt; 0.1&lt;/code&gt; 任何小于0.1版本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;= 0.1&lt;/code&gt; 任何小于或等于0.1版本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~&amp;gt; 0.1.2&lt;/code&gt; 0.1.2(包括)到2.0.0(不包括)版本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~&amp;gt; 0.1.3-beta.0&lt;/code&gt; beta的0.1.3版本, 和release的0.1.3(包括)到2.0.0(不包括)版本&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;版本语义说明(有兴趣可以了解下)&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Semantic Versioning: &lt;a class="link" href="https://semver.org/lang/zh-CN/" target="_blank" rel="noopener"
 &gt;https://semver.org/lang/zh-CN/&lt;/a&gt;
RubyGems Versioning Policies: &lt;a class="link" href="https://guides.rubygems.org/patterns/#semantic-versioning" target="_blank" rel="noopener"
 &gt;https://guides.rubygems.org/patterns/#semantic-versioning&lt;/a&gt;&lt;/p&gt;

 &lt;/blockquote&gt;

 &lt;/blockquote&gt;
&lt;h3 id="参考链接"&gt;参考链接
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;官网: &lt;a class="link" href="https://cocoapods.org" target="_blank" rel="noopener"
 &gt;https://cocoapods.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>某某电商商城逆向分析之一, 首页基本布局结构</title><link>https://blog.skytoup.com/p/%E6%9F%90%E6%9F%90%E7%94%B5%E5%95%86%E5%95%86%E5%9F%8E%E9%80%86%E5%90%91%E5%88%86%E6%9E%90%E4%B9%8B%E4%B8%80-%E9%A6%96%E9%A1%B5%E5%9F%BA%E6%9C%AC%E5%B8%83%E5%B1%80%E7%BB%93%E6%9E%84/</link><pubDate>Sat, 23 May 2020 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/%E6%9F%90%E6%9F%90%E7%94%B5%E5%95%86%E5%95%86%E5%9F%8E%E9%80%86%E5%90%91%E5%88%86%E6%9E%90%E4%B9%8B%E4%B8%80-%E9%A6%96%E9%A1%B5%E5%9F%BA%E6%9C%AC%E5%B8%83%E5%B1%80%E7%BB%93%E6%9E%84/</guid><description>
 &lt;blockquote&gt;
 &lt;p&gt;不涉及逆向相关内容, 仅做分析功能&lt;/p&gt;
&lt;p&gt;仅作为技术研究, 如有侵权, 请及时联系删除&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="基本结构"&gt;基本结构
&lt;/h3&gt;&lt;p&gt;首页大概的样子&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;广告栏&lt;/li&gt;
&lt;li&gt;分类&lt;/li&gt;
&lt;li&gt;各种活动&amp;hellip;&lt;/li&gt;
&lt;li&gt;分类 + 瀑布流列表&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="首页" class="gallery-image" data-flex-basis="76px" data-flex-grow="31" height="1484" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/%E6%9F%90%E6%9F%90%E7%94%B5%E5%95%86%E5%95%86%E5%9F%8E%E9%80%86%E5%90%91%E5%88%86%E6%9E%90%E4%B9%8B%E4%B8%80-%E9%A6%96%E9%A1%B5%E5%9F%BA%E6%9C%AC%E5%B8%83%E5%B1%80%E7%BB%93%E6%9E%84/20200523_01.png" width="474"&gt;&lt;/p&gt;
&lt;p&gt;看到这样的首页, 首先想的是用&lt;code&gt;CollectionView&lt;/code&gt;实现, 实现起来也挺困难的, 多个&lt;code&gt;section&lt;/code&gt;, 布局也各不同。&lt;/p&gt;
&lt;p&gt;但是这个首页用的是&lt;code&gt;TableView&lt;/code&gt;实现, 单个&lt;code&gt;section&lt;/code&gt;, 各种不一样布局的Cell。&lt;/p&gt;
&lt;p&gt;总体操作流畅, 高速滑动有一点点掉帧(底下的瀑布流列表有圆角离屏渲染)。这么复杂的布局, 能有这样的体验, 挺不错的。&lt;/p&gt;
&lt;h3 id="基本实现分析"&gt;基本实现分析
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;TableView&lt;/code&gt;的数据管理抽离了&lt;code&gt;DataSource&lt;/code&gt;类, 实现&lt;code&gt;UITableViewDataSource&lt;/code&gt;和&lt;code&gt;UITableViewDelegate&lt;/code&gt;, 还负责加载和管理数据(或许还有其它功能, 暂时没有太关注)&lt;/p&gt;
&lt;p&gt;网络数据到cell的过程&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;DataSource&lt;/code&gt;获取网络数据&lt;/li&gt;
&lt;li&gt;&lt;code&gt;parser&lt;/code&gt;把&lt;code&gt;json&lt;/code&gt;解析为&lt;code&gt;cell item&lt;/code&gt;, 并计算&lt;code&gt;cell&lt;/code&gt;需要的&lt;code&gt;size&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DataSource&lt;/code&gt;把&lt;code&gt;cell item&lt;/code&gt;通过&lt;code&gt;cell factory&lt;/code&gt;生成不同的&lt;code&gt;cell&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;内置多种cell, 可以根据数据动态切换布局&lt;/p&gt;
&lt;p&gt;cell不使用&lt;code&gt;AutoLayout&lt;/code&gt;, 全部使用&lt;code&gt;frame&lt;/code&gt;布局, 可以为滑动流畅提供一定的保障。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="下部分商品瀑布流列表"&gt;下部分商品瀑布流列表
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;大家可能已经发现一个问题, &lt;code&gt;TableView&lt;/code&gt;怎么实现最下面的瀑布流列表？？？&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;下部分是&lt;code&gt;TableView&lt;/code&gt;的&lt;code&gt;FootView&lt;/code&gt;里面放了一个&lt;code&gt;CollectionView&lt;/code&gt; + &lt;code&gt;瀑布流Layout&lt;/code&gt;实现瀑布流商品列表。&lt;/p&gt;
&lt;p&gt;里面做了滑动手势冲突处理, 连续滑动不间断。&lt;/p&gt;</description></item><item><title>某某电商商城逆向分析之二, 首页列表点击的页面跳转管理简单分析</title><link>https://blog.skytoup.com/p/%E6%9F%90%E6%9F%90%E7%94%B5%E5%95%86%E5%95%86%E5%9F%8E%E9%80%86%E5%90%91%E5%88%86%E6%9E%90%E4%B9%8B%E4%BA%8C-%E9%A6%96%E9%A1%B5%E5%88%97%E8%A1%A8%E7%82%B9%E5%87%BB%E7%9A%84%E9%A1%B5%E9%9D%A2%E8%B7%B3%E8%BD%AC%E7%AE%A1%E7%90%86%E7%AE%80%E5%8D%95%E5%88%86%E6%9E%90/</link><pubDate>Sat, 23 May 2020 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/%E6%9F%90%E6%9F%90%E7%94%B5%E5%95%86%E5%95%86%E5%9F%8E%E9%80%86%E5%90%91%E5%88%86%E6%9E%90%E4%B9%8B%E4%BA%8C-%E9%A6%96%E9%A1%B5%E5%88%97%E8%A1%A8%E7%82%B9%E5%87%BB%E7%9A%84%E9%A1%B5%E9%9D%A2%E8%B7%B3%E8%BD%AC%E7%AE%A1%E7%90%86%E7%AE%80%E5%8D%95%E5%88%86%E6%9E%90/</guid><description>
 &lt;blockquote&gt;
 &lt;p&gt;不涉及逆向相关内容, 仅做分析功能&lt;/p&gt;
&lt;p&gt;仅作为技术研究, 如有侵权, 请及时联系删除&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;电商类应用列表布局、页面跳转复杂, 很难写push/present vc, 一般是通过类似web的route那样, 定义一套route参数来统一处理页面跳转。&lt;/p&gt;
&lt;h3 id="开始分析"&gt;开始分析
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;这里主要分析某某电商商城首页列表的点击页面跳转&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;上篇文章提到parser把json解析为cell item, 其中cell item还包含用于页面跳转的action数据。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;action数据因各个app的业务不一而定义, 比如login(是否需要登录)、modal(是否使用模态视图)、path(跳转路径)、className(vc类名)、extraDict(额外的数据)...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;列表上的item被点击之后, 调用delete的方法, 传递cell item(包含action数据), 最终到vc进行处理。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;action handler统一管理了页面跳转, 也是个log打点的好地方
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;action handler根据vc传递action数据处理各种页面跳转情况, 如push/present vc、scheme调用、打开网页(内部、外部)&amp;hellip;&lt;/p&gt;</description></item><item><title>SwiftUI小实践</title><link>https://blog.skytoup.com/p/swiftui%E5%B0%8F%E5%AE%9E%E8%B7%B5/</link><pubDate>Fri, 27 Mar 2020 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/swiftui%E5%B0%8F%E5%AE%9E%E8%B7%B5/</guid><description>&lt;h3 id="swiftui小实践---重写之前的authenticator"&gt;SwiftUI小实践 - 重写之前的Authenticator
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;对于之前做的一个TOTP两步验证器, 之前决定用SwiftUI重写一遍。后来工作忙, 一直拖到了过年时才完成。&lt;/p&gt;
&lt;p&gt;地址: &lt;a class="link" href="https://github.com/skytoup/Authenticator" target="_blank" rel="noopener"
 &gt;https://github.com/skytoup/Authenticator&lt;/a&gt;, 只为了把功能做出来, 还没怎么整理代码&lt;/p&gt;
&lt;p&gt;已上架AppStore, 可直接下载体验: &lt;a class="link" href="itms-apps://itunes.apple.com/app/id1509275023" &gt;itms-apps://itunes.apple.com/app/id1509275023&lt;/a&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="功能"&gt;功能
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;增、删、改、查、排序(double作为score)验证码&lt;/li&gt;
&lt;li&gt;相册、相机扫描二维码导入&lt;/li&gt;
&lt;li&gt;二维码导出&lt;/li&gt;
&lt;li&gt;watchOS同步数据, 生成动态码&lt;/li&gt;
&lt;li&gt;数据同步到个人iCloud(仅AppStore版本有, 因为需要开发者计划才能开启此功能)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="小经验"&gt;小经验
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;基本视图布局
&lt;ul&gt;
&lt;li&gt;对于&lt;code&gt;List&lt;/code&gt;的&lt;code&gt;Item&lt;/code&gt;添加&lt;code&gt;onTapGesture&lt;/code&gt;, 点击空白地方无法触发, 使用&lt;code&gt;.contentShape(Rectangle())&lt;/code&gt;可解决&lt;/li&gt;
&lt;li&gt;单独隐藏&lt;code&gt;List&lt;/code&gt;的分割线&lt;code&gt;ListSeparatorNoneViewModifier.swift&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;定时刷新生成的验证码
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MyTimer.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;Timer.publish&lt;/code&gt;发现很多奇奇怪怪的问题&lt;/li&gt;
&lt;li&gt;比如暂停和恢复, 实现出来的之后发现恢复会失败, 最后还是自定义一个&lt;code&gt;Timer&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;配合CoreData刷新数据
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CodeList.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;输入关键字查找功能, 使用&lt;code&gt;FetchRequest&lt;/code&gt;, 放在&lt;code&gt;View&lt;/code&gt;的属性里面, 在&lt;code&gt;View&lt;/code&gt;初始化时根据关键字生成&lt;code&gt;FetchRequest&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;UIViewController混用
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LBXScan.swift&lt;/code&gt;, &lt;code&gt;ImagePicker.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;还是比较简单, 新建一个Struct, 实现&lt;code&gt;UIViewControllerRepresentable&lt;/code&gt;即可&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;watchOS
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Watch Extension/CodeView.swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;对于&lt;code&gt;watchOS&lt;/code&gt;实在好, Storeboard很对UI都没法实现, 用了&lt;code&gt;SwiftUI&lt;/code&gt;发现UI的可定制型更高了&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实践的经验不算多, 希望对大家有帮助😄&lt;/p&gt;</description></item><item><title>便捷存储简单数据SimpleStoreData</title><link>https://blog.skytoup.com/p/%E4%BE%BF%E6%8D%B7%E5%AD%98%E5%82%A8%E7%AE%80%E5%8D%95%E6%95%B0%E6%8D%AEsimplestoredata/</link><pubDate>Wed, 18 Mar 2020 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/%E4%BE%BF%E6%8D%B7%E5%AD%98%E5%82%A8%E7%AE%80%E5%8D%95%E6%95%B0%E6%8D%AEsimplestoredata/</guid><description>
 &lt;blockquote&gt;
 &lt;p&gt;为啥不叫&lt;code&gt;SimpleStore&lt;/code&gt;??? 因为&lt;code&gt;Cocoapods&lt;/code&gt;已有同名, 临时在后面加个&lt;code&gt;Data&lt;/code&gt;😭, 实际使用还是&lt;code&gt;SimpleStore&lt;/code&gt;
下文&lt;code&gt;SimpleStore&lt;/code&gt;和&lt;code&gt;SimpleStoreData&lt;/code&gt;指的为同一样东西&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;两三年前, 公司需要&lt;code&gt;Swift&lt;/code&gt;开发&lt;code&gt;App&lt;/code&gt;, 从那时刚开始接触学习, 发现&lt;code&gt;struct&lt;/code&gt;的一些特性可以结合&lt;code&gt;UserDefault&lt;/code&gt;简化一些业务数据存储和读写, 于是就写出了&lt;code&gt;SimpleStore&lt;/code&gt;的雏形.&lt;/p&gt;
&lt;p&gt;随着&lt;code&gt;Swift 5.1&lt;/code&gt;的发布, 发布了一个&lt;code&gt;PropertyWrapper&lt;/code&gt;的新特性, 尝试把这个特性加到&lt;code&gt;SimpleStore&lt;/code&gt;的雏形里面, 发现使用起来还是更方便. 顺便还升级了功能, 一个&lt;code&gt;StoreItem&lt;/code&gt;由原本只支持单一类型存储, 改为支持多类型.&lt;/p&gt;
&lt;p&gt;最近对&lt;code&gt;SimpleStore&lt;/code&gt;的雏形进行了一番思考, 对其再次升级, 最后整理开源了&lt;code&gt;SimpleStore&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="设计思路"&gt;设计思路
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;核心
&lt;code&gt;SimpleStoreItem&lt;/code&gt;修改后, 触发&lt;code&gt;SimpleStore&lt;/code&gt;进行对数据存储&lt;/li&gt;
&lt;li&gt;基本结构
&lt;ul&gt;
&lt;li&gt;SimpleStore: 管理和存储&lt;code&gt;SimpleStoreItem&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;SimpleStoreItem: 存放数据&lt;/li&gt;
&lt;li&gt;Mapper: 辅助数据间转换(非必须)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;扩展性
&lt;ul&gt;
&lt;li&gt;可实现&lt;code&gt;SimpleStore&lt;/code&gt;协议可配合&lt;code&gt;SimpleStoreItem&lt;/code&gt;扩展更多存储方式(目前只有&lt;code&gt;UserDefault&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SimpleStoreDictItem&lt;/code&gt;实现了&lt;code&gt;SimpleStoreItem&lt;/code&gt;协议, 通过&lt;code&gt;Mapper&lt;/code&gt;提供&lt;code&gt;Item&lt;/code&gt;和&lt;code&gt;dict&lt;/code&gt;的转换, 为中间转存提供方便, 易于扩展更多存储方式&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="用法"&gt;用法
&lt;/h3&gt;&lt;p&gt;场景: 存储登录用户的数据(存储到UserDefault)&lt;/p&gt;
&lt;p&gt;定义一个用户性别的枚举, 因为&lt;code&gt;UserDefault&lt;/code&gt;不支持直接存储&lt;code&gt;enum&lt;/code&gt;, 所以需要实现&lt;code&gt;UDCoding&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;UserDefault&lt;/code&gt;支持的存储类型:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;String&lt;/li&gt;
&lt;li&gt;Int&lt;/li&gt;
&lt;li&gt;Float&lt;/li&gt;
&lt;li&gt;Double&lt;/li&gt;
&lt;li&gt;Bool&lt;/li&gt;
&lt;li&gt;Data&lt;/li&gt;
&lt;li&gt;Date&lt;/li&gt;
&lt;li&gt;URL&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Swift" data-lang="Swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;enum&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Gender&lt;/span&gt;: Int {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; unknown = &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; male
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; female
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/// 对于`UserDefault`不支持的存储类型提供数据转换&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;extension&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Gender&lt;/span&gt;: UDCoding {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;toUDAny&lt;/span&gt;() -&amp;gt; Any {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rawValue
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fromUDAny&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; any: Any?) -&amp;gt; Gender? {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;guard&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; any = any &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt;? Int &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; Gender(rawValue: any)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;定义存储用户数据的字段(&lt;strong&gt;重点提示: SimpleStoreItem必须使用struct实现&lt;/strong&gt;), 字段使用&lt;code&gt;UDMapperParam&lt;/code&gt;属性包装定义, 再实现&lt;code&gt;mapValue&lt;/code&gt;方法进行数据映射&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Swift" data-lang="Swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;/// **重点提示: SimpleStoreItem必须使用struct实现**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserStoreItem&lt;/span&gt;: SimpleStoreUDItem {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @UDMapperParam(key: &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @UDMapperParam(key: &lt;span style="color:#e6db74"&gt;&amp;#34;age&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; age
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @UDMapperParam(key: &lt;span style="color:#e6db74"&gt;&amp;#34;gender&amp;#34;&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;: Gender.unknown) &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; gender
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;mutating&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mapValue&lt;/span&gt;&amp;lt;Mapper&amp;gt;(&lt;span style="color:#66d9ef"&gt;_&lt;/span&gt; mapper: &lt;span style="color:#66d9ef"&gt;inout&lt;/span&gt; Mapper) &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; Mapper : DictMapper, UserStoreItem.Key == Mapper.Key, UserStoreItem.Value == Mapper.Value {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mapper &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; _name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mapper &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; _age
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mapper &lt;span style="color:#f92672"&gt;&amp;lt;-&lt;/span&gt; _gender
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;定义管理&lt;code&gt;StoreItem&lt;/code&gt;的管理类(此处简单使用单例, 可根据自己的业务进行调整, &lt;code&gt;manager&lt;/code&gt;也可定义更多业务方法)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Swift" data-lang="Swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserManager&lt;/span&gt;: SimpleStoreUD&amp;lt;UserStoreItem&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;static&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; shared = UserManager(udKey: &lt;span style="color:#e6db74"&gt;&amp;#34;__User__&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 这里可以添加一些业务方法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用演示, 修改item数据即可存自动储, 无需其它调用方法&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Swift" data-lang="Swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; userM = UserManager.shared
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 清空之前的数据&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;userM.ud.&lt;span style="color:#66d9ef"&gt;set&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;, forKey: userM.udKey)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 提示: 一次性更新多个字段最好是使用方法`batchUpdate`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;userM[&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;.name] = &lt;span style="color:#e6db74"&gt;&amp;#34;sky&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;&amp;#34;第一次修改 &lt;/span&gt;&lt;span style="color:#e6db74"&gt;\(&lt;/span&gt;userM.ud.dictionary&lt;span style="color:#e6db74"&gt;(&lt;/span&gt;forKey: userM.udKey&lt;span style="color:#e6db74"&gt;)&lt;/span&gt; ?? [:]&lt;span style="color:#e6db74"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 第一次修改 [&amp;#34;gender&amp;#34;: 0, &amp;#34;age&amp;#34;: 0, &amp;#34;name&amp;#34;: sky]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;userM[&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;.age] = &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;&amp;#34;第二次修改 &lt;/span&gt;&lt;span style="color:#e6db74"&gt;\(&lt;/span&gt;userM.ud.dictionary&lt;span style="color:#e6db74"&gt;(&lt;/span&gt;forKey: userM.udKey&lt;span style="color:#e6db74"&gt;)&lt;/span&gt; ?? [:]&lt;span style="color:#e6db74"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 第二次修改 [&amp;#34;name&amp;#34;: sky, &amp;#34;age&amp;#34;: 18, &amp;#34;gender&amp;#34;: 0]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;userM[&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;.gender] = .male
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;&amp;#34;第三次修改 &lt;/span&gt;&lt;span style="color:#e6db74"&gt;\(&lt;/span&gt;userM.ud.dictionary&lt;span style="color:#e6db74"&gt;(&lt;/span&gt;forKey: userM.udKey&lt;span style="color:#e6db74"&gt;)&lt;/span&gt; ?? [:]&lt;span style="color:#e6db74"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 第三次修改 [&amp;#34;age&amp;#34;: 18, &amp;#34;name&amp;#34;: sky, &amp;#34;gender&amp;#34;: 1]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 批量修改字段再存储&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;userM.batchUpdate { item &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; item.name = &lt;span style="color:#e6db74"&gt;&amp;#34;yks&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; item.age = &lt;span style="color:#ae81ff"&gt;81&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; item.gender = .female
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;&amp;#34;batchUpdate &lt;/span&gt;&lt;span style="color:#e6db74"&gt;\(&lt;/span&gt;userM.ud.dictionary&lt;span style="color:#e6db74"&gt;(&lt;/span&gt;forKey: userM.udKey&lt;span style="color:#e6db74"&gt;)&lt;/span&gt; ?? [:]&lt;span style="color:#e6db74"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// batchUpdate [&amp;#34;age&amp;#34;: 81, &amp;#34;name&amp;#34;: yks, &amp;#34;gender&amp;#34;: 2]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 相当于重置数据&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;userM.item = UserStoreItem()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;&amp;#34;重置数据 &lt;/span&gt;&lt;span style="color:#e6db74"&gt;\(&lt;/span&gt;userM.ud.dictionary&lt;span style="color:#e6db74"&gt;(&lt;/span&gt;forKey: userM.udKey&lt;span style="color:#e6db74"&gt;)&lt;/span&gt; ?? [:]&lt;span style="color:#e6db74"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 重置数据 [&amp;#34;age&amp;#34;: 0, &amp;#34;name&amp;#34;: , &amp;#34;gender&amp;#34;: 0]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="详情"&gt;详情
&lt;/h3&gt;&lt;p&gt;详情请参考github地址: &lt;a class="link" href="https://github.com/skytoup/SimpleStoreData" target="_blank" rel="noopener"
 &gt;https://github.com/skytoup/SimpleStoreData&lt;/a&gt;&lt;/p&gt;</description></item><item><title>CodeWars kata Conway's Game of Life - Unlimited Edition</title><link>https://blog.skytoup.com/p/codewars-kata-conways-game-of-life-unlimited-edition/</link><pubDate>Fri, 24 Jan 2020 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/codewars-kata-conways-game-of-life-unlimited-edition/</guid><description>&lt;p&gt;题目链接: &lt;a class="link" href="https://www.codewars.com/kata/52423db9add6f6fc39000354/c" target="_blank" rel="noopener"
 &gt;https://www.codewars.com/kata/52423db9add6f6fc39000354/c&lt;/a&gt;&lt;/p&gt;
&lt;h5 id="题目大概翻译999机翻"&gt;题目大概翻译(99.9%机翻😅):
&lt;/h5&gt;&lt;p&gt;给你一个二维数组 和 经过多少代, 模拟计算&lt;a class="link" href="http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life" target="_blank" rel="noopener"
 &gt;Conway&amp;rsquo;s_Game_of_Life&lt;/a&gt;的n个时间点&lt;/p&gt;
&lt;p&gt;游戏规则:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任何具有少于两个活邻居的活细胞都会死亡，好像是由于人口不足造成的。&lt;/li&gt;
&lt;li&gt;任何具有三个以上活邻居的活细胞都会死亡，就像人满为患一样。&lt;/li&gt;
&lt;li&gt;任何有两个或三个活邻居的活细胞都可以存活到下一代。&lt;/li&gt;
&lt;li&gt;具有正好三个活邻居的任何死单元将变为活单元。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每个单元的邻域是它周围的8个单元(即&lt;a class="link" href="https://en.wikipedia.org/wiki/Moore_neighborhood" target="_blank" rel="noopener"
 &gt;Moore邻域&lt;/a&gt;). 空间在x和y维度上都是无限的，并且所有单元格最初都是死的, 除了指定单元格为活的。返回值应该是围绕所有活细胞裁剪的二维数组。（如果没有活细胞，则返回[[]]。）&lt;/p&gt;
&lt;p&gt;出于说明目的，将0和1分别表示为░░和▓▓块（PHP，C：纯黑色和白色正方形）。您可以利用该htmlize功能来获取Universe的文本表示形式，例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;char&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;universe &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;htmlize&lt;/span&gt;(cells, rows, columns);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;printf&lt;/span&gt;(universe);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;free&lt;/span&gt;(universe);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在C语言中，GoL空间的初始尺寸通过指针和的引用传递到函数中。在扩展/收缩GoL空间时，请通过这两个变量(rowptr, colptr)来跟踪修改后的网格的尺寸。&lt;/p&gt;
&lt;h5 id="题目解析"&gt;题目解析
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;场景大概是有一个二维空间, 上面有一堆活或死的细胞, 每经过一代都根据游戏规则计算细胞的活/死&lt;/li&gt;
&lt;li&gt;输入
&lt;ul&gt;
&lt;li&gt;一个二维数组(0, 1), 代表每个细胞的 活/死 状态&lt;/li&gt;
&lt;li&gt;一个int, 代表经过多少代&lt;/li&gt;
&lt;li&gt;C语言才有: 两个尺寸的指针, 代表输入的二维数组的大小, 也是输出的二维数组的大小&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;输出一个二维数组(0, 1), 代表每个细胞的 活/死 状态&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="其它注意的点"&gt;其它注意的点
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;单元的邻域是指周围的8个单元格(上、下、左、右、左上、右上、左下、右下)&lt;/li&gt;
&lt;li&gt;空间是无限的, 没有边界, 即输入的二维数组大小和输出的二维数组大小不一定相同(已踩坑, 以为在输入的二维数组大小做计算就好了, 谁知道是二维数组是可扩展的&amp;hellip;)&lt;/li&gt;
&lt;li&gt;输出的空间是围绕着活细胞裁剪的二维数组, 即二维数组最外层四周至少有一个活细胞, 否则空间需要缩小&lt;/li&gt;
&lt;li&gt;输入的二维数组的数据需要深拷贝&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="思路苦逼的c语言解题"&gt;思路(苦逼的C语言解题&amp;hellip;)
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;一开始的想法
&lt;ul&gt;
&lt;li&gt;创建并初始化两个二维数组, 一个为现在这代的细胞状态(cur_cells), 另一个是下一代的细胞状态(next_cells)&lt;/li&gt;
&lt;li&gt;遍历&lt;code&gt;cur_cells&lt;/code&gt;, 根据游戏规则计算每个细胞的状态存到&lt;code&gt;next_cells&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;最后&lt;code&gt;cur_cells&lt;/code&gt;和&lt;code&gt;next_cells&lt;/code&gt;指针互换, 重置&lt;code&gt;next_cells&lt;/code&gt;数据为0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;一番思考之后🤔
&lt;ul&gt;
&lt;li&gt;遍历起来的时候, 重复访问了不少单元格&lt;/li&gt;
&lt;li&gt;可以把&lt;code&gt;next_cells&lt;/code&gt;改为&lt;code&gt;cal_cells&lt;/code&gt;, 作用是单元格周围有多少活细胞&lt;/li&gt;
&lt;li&gt;(其实不用两个数组也可以, 一个数组足够存储数据, 可分高4低4位存储, 由于太懒了, 没去弄&amp;hellip;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;优化之后😢
&lt;ul&gt;
&lt;li&gt;遍历&lt;code&gt;cur_cells&lt;/code&gt;, 如果是活细胞, 把对应的&lt;code&gt;cal_cells&lt;/code&gt;周边8个单元格数字+1&lt;/li&gt;
&lt;li&gt;遍历&lt;code&gt;cal_cells&lt;/code&gt;, 根据游戏规则计算每个细胞的状态存到&lt;code&gt;cur_cells&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;最后重置&lt;code&gt;cal_cells&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;采坑&amp;hellip;😂
&lt;ul&gt;
&lt;li&gt;代码提交上去, 简单测试通过了, 但是随机测试一直无法通过&lt;/li&gt;
&lt;li&gt;一番折腾之后, 发现边界是不限定的, 可无限扩张, 或者需要收缩&lt;/li&gt;
&lt;li&gt;由于用的是&lt;code&gt;C&lt;/code&gt;, 一开始考虑的是&lt;code&gt;realloc&lt;/code&gt;+&lt;code&gt;memmov&lt;/code&gt;方案, 后来发现随机测试的二维数组大小最大也就100 * 100这样子&lt;/li&gt;
&lt;li&gt;最后干脆创建150*150的二维数组用来计算, 初始数据存在数组中央位置(计算偏移位置); 然后每次计算状态之后, 再计算扩展边界; n代过去之后, 再计算收缩的偏移位置, 输出到新的二维数组返回&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Cocoapod二进制化实践</title><link>https://blog.skytoup.com/p/cocoapod%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%8C%96%E5%AE%9E%E8%B7%B5/</link><pubDate>Tue, 14 Jan 2020 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/cocoapod%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%8C%96%E5%AE%9E%E8%B7%B5/</guid><description>
 &lt;blockquote&gt;
 &lt;p&gt;2020-02-06
添加Swift 5.1开始, ABI稳定特性打包兼容说明&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;(&lt;code&gt;Carthage&lt;/code&gt;暂不考虑&amp;hellip;, 略过)&lt;/p&gt;
&lt;h3 id="简fei介hua"&gt;简(fei)介(hua)
&lt;/h3&gt;&lt;p&gt;随着越来越多方便的第三方组件, 现在开发App基本十多个第三方依赖以上. 没有&lt;code&gt;build cache&lt;/code&gt;或者打正式包的时候, 每次基本耗时10分钟以上.&lt;/p&gt;
&lt;p&gt;主要原因是需要编译大量源文件(大概分为app和Cocoapods依赖库), 所以把可抽离代码编译好, 再去引用就能减少源文件编译时间&lt;/p&gt;
&lt;p&gt;至于有没有其它更高级玩法, 暂时还不太清楚&lt;/p&gt;
&lt;h3 id="想法来自网络各种方法综合"&gt;想法(来自网络各种方法综合)
&lt;/h3&gt;&lt;p&gt;简单的平民解决方法: 建立私有二进制的&lt;code&gt;repo&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;app
&lt;ul&gt;
&lt;li&gt;抽离封装为一个库, 打包为二进制, 存到私有&lt;code&gt;Cocoapods repo&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cocoapods依赖
&lt;ul&gt;
&lt;li&gt;每个组件版本的源码打包为二进制, 存到私有&lt;code&gt;Cocoapods repo&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果公司或者你有足够资源, 可以弄&lt;code&gt;双私有源&lt;/code&gt;(两个私有&lt;code&gt;repo&lt;/code&gt;, 一个二进制, 一个源码), 不然就简单点, 弄个私有二进制的&lt;code&gt;repo&lt;/code&gt;也够用&lt;/p&gt;
&lt;h3 id="思路"&gt;思路
&lt;/h3&gt;&lt;p&gt;由于没机器和资源, 只实践了后面的&lt;code&gt;简(diao)单(si)版&lt;/code&gt;. 有条件最好是做一套自动化的, 我是没机器和资源, 打包还是各种脚本在自己机器上手动打包, 好惨&amp;hellip;&lt;/p&gt;
&lt;p&gt;简单版思路:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;打包第三方源码
&lt;ul&gt;
&lt;li&gt;每个tag打包二进制(只弄了打包&lt;code&gt;framework&lt;/code&gt;, 不知道别人的&lt;code&gt;static framework&lt;/code&gt;如何制作, 试了不成功)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;私有repo
&lt;ul&gt;
&lt;li&gt;其实就是一个&lt;code&gt;git&lt;/code&gt;仓库, 私有属性即可(虽然公有也行, 只是别人能看), 一般&lt;code&gt;github&lt;/code&gt;, &lt;code&gt;gitlab&lt;/code&gt;, &lt;code&gt;gitee&lt;/code&gt;或者&lt;code&gt;自建git&lt;/code&gt;创建一个仓库就可以了&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;二进制文件存放
&lt;ul&gt;
&lt;li&gt;打包出来的二进制文件, 需要找个地方提供下载, 有条件的话可以存CDN管理, 没的话在内网放个静态文件服务器存也行, 还有可以存&lt;code&gt;git&lt;/code&gt;(需要有&lt;code&gt;http(s)&lt;/code&gt;下载地址)&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="实践"&gt;实践
&lt;/h3&gt;&lt;p&gt;需要的一些辅助工具&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/tripleCC/cocoapods-bin" target="_blank" rel="noopener"
 &gt;https://github.com/tripleCC/cocoapods-bin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/tripleCC/binary-server" target="_blank" rel="noopener"
 &gt;https://github.com/tripleCC/binary-server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;步骤&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;打包第三方源码
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git clone&lt;/code&gt;各种组件源码库&lt;/li&gt;
&lt;li&gt;脚本打包
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tag&lt;/code&gt;拉分支, 并切换(打包之后删除, 再回去&lt;code&gt;master&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;pod gen&lt;/code&gt;根据&lt;code&gt;podsec&lt;/code&gt;创建工程&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xcodebuild&lt;/code&gt;打包&lt;code&gt;framework&lt;/code&gt;(真机和模拟器)&lt;/li&gt;
&lt;li&gt;合并真机和模拟器的&lt;code&gt;framework&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;看上去是这么简单, 实践的时候会发现有些库是不能通用一个脚本的&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;上传&lt;code&gt;framework&lt;/code&gt;(用了&lt;code&gt;binary-server&lt;/code&gt;管理)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;二进制的&lt;code&gt;podsec&lt;/code&gt;上传到私有的&lt;code&gt;repo&lt;/code&gt;
&lt;ol&gt;
&lt;li&gt;使用&lt;code&gt;pod bin spec create&lt;/code&gt;创建二进制版本的&lt;code&gt;podsec&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;有&lt;code&gt;subsec&lt;/code&gt;的会要求提供&lt;code&gt;template&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;某些平台要求版本会低于8, 因为是使用&lt;code&gt;framework&lt;/code&gt;, 需要平台版本需要改为8以上&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;上传生成的&lt;code&gt;podsec&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;使用
&lt;ul&gt;
&lt;li&gt;在&lt;code&gt;Podfile&lt;/code&gt;加上&lt;code&gt;source {你的私有repo}&lt;/code&gt;, 然后再加一个官方的repo(例如: &lt;code&gt;source 'https://cdn.cocoapods.org/'&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;官方的一定要加在后面, 有相同的库会根据&lt;code&gt;source&lt;/code&gt;的顺序获取依赖. 想切回源码注释私有库那一行就好了(因为只是简单的一个&lt;code&gt;私有二进制repo&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="某些坑"&gt;某些坑
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;不知道会有啥影响, &lt;code&gt;AppStore&lt;/code&gt;的打包还是老老实实的用源码build&lt;/li&gt;
&lt;li&gt;&lt;code&gt;modulemap&lt;/code&gt;记得要把真机和模拟器的合一起&lt;/li&gt;
&lt;li&gt;真机和模拟器的&lt;code&gt;DSYM&lt;/code&gt;文件保留(万一哪一天用上)&lt;/li&gt;
&lt;li&gt;有些第三方库是&lt;code&gt;*.podsec&lt;/code&gt;, 有些是&lt;code&gt;*.podsec.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pod bin spec create&lt;/code&gt;创建的二进制&lt;code&gt;podsec&lt;/code&gt;文件名是带加了&lt;code&gt;binary&lt;/code&gt;, 需要去除, 不然和&lt;code&gt;podsec&lt;/code&gt;的&lt;code&gt;name&lt;/code&gt;和&lt;code&gt;文件名&lt;/code&gt;对不上, 无法通过&lt;code&gt;pod spec lint&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pod repo push&lt;/code&gt;上传私有&lt;code&gt;spec&lt;/code&gt;的时候, 记得加&lt;code&gt;--use-json --allow-warnings&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;或许还有其它&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="其它"&gt;其它
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Swift 5.1开始, ABI已稳定, 可打包兼容多个不同swift版本打包可相互使用, 不需要重新打包&lt;code&gt;framework&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;开启地方位于项目的&lt;code&gt;build setting&lt;/code&gt; - &lt;code&gt;Build Option&lt;/code&gt; - &lt;code&gt;Build Libraries for Distribution&lt;/code&gt;改为YES&lt;/li&gt;
&lt;li&gt;&lt;code&gt;framework&lt;/code&gt;的&lt;code&gt;Modules&lt;/code&gt;里面会多生成一个类似源码的interface文件&lt;/li&gt;
&lt;li&gt;相关资料
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://developer.apple.com/videos/play/wwdc2019/402/" target="_blank" rel="noopener"
 &gt;https://developer.apple.com/videos/play/wwdc2019/402/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>SwiftUI初次体验</title><link>https://blog.skytoup.com/p/swiftui%E5%88%9D%E6%AC%A1%E4%BD%93%E9%AA%8C/</link><pubDate>Thu, 17 Oct 2019 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/swiftui%E5%88%9D%E6%AC%A1%E4%BD%93%E9%AA%8C/</guid><description>&lt;p&gt;前几天macOS 10.15正式版推出, 于是把电脑升级了, 顺便体验下SwiftUI&lt;/p&gt;
&lt;p&gt;经过一番基础学习, 计划把之前的项目(&lt;a class="link" href="https://github.com/skytoup/Authenticator" target="_blank" rel="noopener"
 &gt;https://github.com/skytoup/Authenticator&lt;/a&gt;)尝试使用SwiftUI实现, 发现List的坑挺多的&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;List相对于TableView提供的功能有点少, 还不太习惯, 而且问题也挺多的
&lt;ul&gt;
&lt;li&gt;配合CoreData使用是很爽, 但是发现编辑模式时, 选中功能不正常了, 勾选row和selection的数据无法匹配, 得自行实现选中逻辑和UI才能解决&lt;/li&gt;
&lt;li&gt;row左/右滑动菜单系统没有提供, TableView是提供了代理方法可简单实现该功能, 有人推荐使用ContextMenu(用起来也方便)替代
&lt;ul&gt;
&lt;li&gt;延伸另一个问题, ContextMenu的按钮文字、图标按钮没法改颜色&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;拖动row到上一行时, 把数据源交换之后, 动画很奇怪(拖动的row回到原位, 然后动画显示拖动的row到拖动目标的位置), 其它拖栋没发现问题(向下一/多行, 向上多行)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;暂时也只是发现这么多&lt;/p&gt;
&lt;p&gt;SwiftUI使用起来也是很舒服, 体验类似在写前端vue, 数据更新自动修改view, 省了很多更新代码, 还能实时预览和操作&lt;/p&gt;
&lt;p&gt;~~ 东西还没完成, 继续研究补坑去&amp;hellip; ~~
已用SwiftUI改写了所有界面: &lt;a class="link" href="https://github.com/skytoup/Authenticator" target="_blank" rel="noopener"
 &gt;https://github.com/skytoup/Authenticator&lt;/a&gt;&lt;/p&gt;</description></item><item><title>实现一个GoogleAuthenticator</title><link>https://blog.skytoup.com/p/%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AAgoogleauthenticator/</link><pubDate>Fri, 11 Oct 2019 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AAgoogleauthenticator/</guid><description>
 &lt;blockquote&gt;
 &lt;p&gt;GoogleAuthenticator TOTP部分实现的验证器(没有实现HOTP)&lt;/p&gt;
&lt;p&gt;已上架AppStore, 可直接下载体验: &lt;a class="link" href="itms-apps://itunes.apple.com/app/id1509275023" &gt;itms-apps://itunes.apple.com/app/id1509275023&lt;/a&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;由于GoogleAuthenticator没有导出功能, 而且在watch上也没有查看功能, 干脆自己实现一个&lt;/p&gt;
&lt;p&gt;纯Swift5.x实现, 操作体验良好, 界面极简&lt;/p&gt;
&lt;p&gt;另外增加相册二维码导入、二维码导出、watchOS同步查看&lt;/p&gt;
&lt;p&gt;详情请到: &lt;a class="link" href="https://github.com/skytoup/Authenticator" target="_blank" rel="noopener"
 &gt;https://github.com/skytoup/Authenticator&lt;/a&gt;&lt;/p&gt;
&lt;h4 id="部分截图"&gt;部分截图
&lt;/h4&gt;&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="110px" data-flex-grow="46" height="2688" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AAgoogleauthenticator/iOS_1.png" srcset="https://blog.skytoup.com/p/%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AAgoogleauthenticator/iOS_1_hu_ca76163e442c2ccb.png 800w, https://blog.skytoup.com/p/%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AAgoogleauthenticator/iOS_1.png 1242w" width="1242"&gt;
&lt;img class="gallery-image" data-flex-basis="197px" data-flex-grow="82" height="448" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AAgoogleauthenticator/watch_0.png" width="368"&gt;&lt;/p&gt;</description></item><item><title>GoogleAuthenticator的一次性密码生成算法</title><link>https://blog.skytoup.com/p/googleauthenticator%E7%9A%84%E4%B8%80%E6%AC%A1%E6%80%A7%E5%AF%86%E7%A0%81%E7%94%9F%E6%88%90%E7%AE%97%E6%B3%95/</link><pubDate>Tue, 08 Oct 2019 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/googleauthenticator%E7%9A%84%E4%B8%80%E6%AC%A1%E6%80%A7%E5%AF%86%E7%A0%81%E7%94%9F%E6%88%90%E7%AE%97%E6%B3%95/</guid><description>&lt;h3 id="googleauthenticator"&gt;GoogleAuthenticator
&lt;/h3&gt;&lt;p&gt;使用于二次验证的&lt;code&gt;动态密码&lt;/code&gt;生成工具, 一般用于登录验证、替代一些短信验证等&amp;hellip;&lt;/p&gt;
&lt;p&gt;其中&lt;code&gt;动态密码&lt;/code&gt;生成算法为&lt;code&gt;HOTP&lt;/code&gt;(HMAC-Based One-Time Passcode)和&lt;code&gt;TOTP&lt;/code&gt;(Time-based One-Time Passcode)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TOTP&lt;/code&gt;和&lt;code&gt;HOTP&lt;/code&gt;均基于&lt;code&gt;OTP&lt;/code&gt;(One-Time Passcode)&lt;/p&gt;
&lt;h3 id="otp"&gt;OTP
&lt;/h3&gt;&lt;p&gt;一次性密码生成基本公式: &lt;code&gt;OTP(K, C) = Truncate(EncryptionAlgorithm(K, C))&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;K
&lt;ul&gt;
&lt;li&gt;秘钥&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;C
&lt;ul&gt;
&lt;li&gt;一个8 byte数据&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Trucate
&lt;ul&gt;
&lt;li&gt;截取Hash数据组成验证码的函数&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;EncryptionAlgorithm
&lt;ul&gt;
&lt;li&gt;加密算法(对称加密算法, HASH, HMAC)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="hotp和totp"&gt;HOTP和TOTP
&lt;/h3&gt;&lt;p&gt;一次性密码生成公式变更为:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# HOTP
HOTP(K, C) = Truncate(HMAC-based(K, C))

# TOTP
TOTP(K, T) = Truncate(HMAC-based(K, T))
T = (CurrentUnixTime − T0) / X
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;HOTP参数变更:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;C
&lt;ul&gt;
&lt;li&gt;计数器&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;TOTP参数变更:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;T
&lt;ul&gt;
&lt;li&gt;时间点&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CurrentUnixTime
&lt;ul&gt;
&lt;li&gt;当前Unix时间戳&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;T0
&lt;ul&gt;
&lt;li&gt;初始时间戳&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;X
&lt;ul&gt;
&lt;li&gt;时间步长(秒), 相当于一次性密码变更, 默认为30&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;公共参数:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HMAC-based
&lt;ul&gt;
&lt;li&gt;使用HMAC算法进行Hash
&lt;ul&gt;
&lt;li&gt;HMAC-SHA1&lt;/li&gt;
&lt;li&gt;HMAC-SHA256&lt;/li&gt;
&lt;li&gt;HMAC-SHA512&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="truncate截取算法"&gt;Truncate截取算法:
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;取HMAC结果(20 byte)的最后一个字符的低4位&lt;code&gt;offset num&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;offset num&lt;/code&gt; % 16 计算出字符截取的初始位置&lt;code&gt;offset&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;HMAC结果的第&lt;code&gt;offset&lt;/code&gt;开始, 取4个byte组成一个32位int&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="digits参数"&gt;Digits参数
&lt;/h4&gt;&lt;p&gt;其中算法还有一个参数&lt;code&gt;Digits&lt;/code&gt;, 代表验证码的位数&lt;/p&gt;
&lt;p&gt;默认为6, 或者为8&lt;/p&gt;
&lt;h3 id="秘钥url"&gt;秘钥URL
&lt;/h3&gt;&lt;p&gt;GoogleAuthenticator添加秘钥时, 可扫描二维码添加, 其中二维码为一条链接(&lt;code&gt;otpauth://TYPE/LABEL?PARAMETERS&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;例如: otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&amp;amp;issuer=Example&lt;/p&gt;
&lt;p&gt;参数说明:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TYPE
&lt;ul&gt;
&lt;li&gt;秘钥计算的类型, &lt;code&gt;hotp&lt;/code&gt;或&lt;code&gt;totp&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Label
&lt;ul&gt;
&lt;li&gt;用于标识账号, 包括了账号名和标识内容&lt;/li&gt;
&lt;li&gt;&lt;code&gt;label = accountname / issuer (“:” / “%3A”) *”%20” accountname&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;PARAMETERS(URI query参数)
&lt;ul&gt;
&lt;li&gt;Secret
&lt;ul&gt;
&lt;li&gt;秘钥, base32编码&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Issuer
&lt;ul&gt;
&lt;li&gt;谁提供者此秘钥, 就是标识属于那个网站的验证&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Algorithm(可选)
&lt;ul&gt;
&lt;li&gt;HMAC使用哪种HASH算法
&lt;ul&gt;
&lt;li&gt;SHA1(默认)&lt;/li&gt;
&lt;li&gt;SHA256&lt;/li&gt;
&lt;li&gt;SHA512&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Digits(可选)
&lt;ul&gt;
&lt;li&gt;验证码位数
&lt;ul&gt;
&lt;li&gt;6(默认)&lt;/li&gt;
&lt;li&gt;8&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Counter(当type为hotp时为必需)
&lt;ul&gt;
&lt;li&gt;计算器初始值&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Period(当type为totp时为才需要, 可选)
&lt;ul&gt;
&lt;li&gt;时间步长(秒)
&lt;ul&gt;
&lt;li&gt;30(默认)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于GoogleAuthenticator, 很多参数会忽略掉, 均为其默认值&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Algorithm(SHA1)&lt;/li&gt;
&lt;li&gt;Digits(6)&lt;/li&gt;
&lt;li&gt;Period(30)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="在实现hotp时遇到的一些问题应该比较多人遇到吧"&gt;在实现HOTP时遇到的一些问题(应该比较多人遇到吧)
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;计算出的时间点需要转为8 byte数据&lt;/li&gt;
&lt;li&gt;输入的秘钥需要Base32解码之后, 才能进行作为秘钥传入HMAC&lt;/li&gt;
&lt;li&gt;Truncate函数最后取的4 byte数据, 需要转为32位的int&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="参考"&gt;参考
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;HOTP: An HMAC-Based One-Time Password Algorithm(rfc4226): &lt;a class="link" href="https://tools.ietf.org/html/rfc4226" target="_blank" rel="noopener"
 &gt;https://tools.ietf.org/html/rfc4226&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Key Uri Format: &lt;a class="link" href="https://github.com/google/google-authenticator/wiki/Key-Uri-Format" target="_blank" rel="noopener"
 &gt;https://github.com/google/google-authenticator/wiki/Key-Uri-Format&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;HOTP和TOTP算法图解: &lt;a class="link" href="https://www.jianshu.com/p/a7b900e8e50a" target="_blank" rel="noopener"
 &gt;https://www.jianshu.com/p/a7b900e8e50a&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Xcode11删除Storyboard</title><link>https://blog.skytoup.com/p/xcode11%E5%88%A0%E9%99%A4storyboard/</link><pubDate>Sun, 06 Oct 2019 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/xcode11%E5%88%A0%E9%99%A4storyboard/</guid><description>&lt;p&gt;iOS 13支持多窗口, 引入了Screen相关API。App的AppDelegate部分已经改变, 想把Storeboard删掉, 增加UIWindow已经不是在AppDelegate里面修改。&lt;/p&gt;
&lt;p&gt;整理出以下步骤(Xcode11 Swift5.1)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;删除Main.storyboard文件&lt;/li&gt;
&lt;li&gt;Info.plist删除 Application Scene Manifest - Scene Configuration - Application Session Role - 0 - Storyboard Name&lt;/li&gt;
&lt;li&gt;在ScreenDelegate添加window&lt;/li&gt;
&lt;/ol&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;	guard let scene = (scene as? UIWindowScene) else { return }
 
 self.window = UIWindow(windowScene: scene)
 self.window?.backgroundColor = .white
 
 let rootVC = UIViewController()
 let winRootVC = UINavigationController(rootViewController: rootVC)
 self.window?.rootViewController = winRootVC

 self.window?.makeKeyAndVisible()
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Python3官方库collections比较有用的部分</title><link>https://blog.skytoup.com/p/python3%E5%AE%98%E6%96%B9%E5%BA%93collections%E6%AF%94%E8%BE%83%E6%9C%89%E7%94%A8%E7%9A%84%E9%83%A8%E5%88%86/</link><pubDate>Sun, 21 Jul 2019 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/python3%E5%AE%98%E6%96%B9%E5%BA%93collections%E6%AF%94%E8%BE%83%E6%9C%89%E7%94%A8%E7%9A%84%E9%83%A8%E5%88%86/</guid><description>&lt;h3 id="collectionscounter"&gt;collections.Counter
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;简介&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Counter&lt;/code&gt;是&lt;code&gt;dict&lt;/code&gt;的子类, 用于可&lt;code&gt;hash&lt;/code&gt;的对象计数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;key&lt;/code&gt;按&lt;code&gt;dict&lt;/code&gt;的&lt;code&gt;key&lt;/code&gt;排序, 计数的值按&lt;code&gt;dict&lt;/code&gt;的&lt;code&gt;value&lt;/code&gt;排序&lt;/li&gt;
&lt;li&gt;计数的值为&lt;code&gt;整数&lt;/code&gt;, 可为&lt;code&gt;正负数&lt;/code&gt;和&lt;code&gt;0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;示例&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python3" data-lang="python3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; collections &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Counter
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 初始化, 可传 [None, Iterable, Mapping]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;counter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Counter() &lt;span style="color:#75715e"&gt;# None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;counter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Counter(&lt;span style="color:#e6db74"&gt;&amp;#39;12345&amp;#39;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# Iterable, 统计每个元素频率&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;counter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Counter({&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;}) &lt;span style="color:#75715e"&gt;# Mapping&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;counter &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Counter(a&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, b&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# Mapping&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 没有赋值过的元素不会触发KeyError&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;counter[&lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;] &lt;span style="color:#75715e"&gt;# 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;counter[&lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 也能移除元素(真实移除), 然后计数归0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;counter[&lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;del&lt;/span&gt; counter[&lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;counter[&lt;span style="color:#e6db74"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;] &lt;span style="color:#75715e"&gt;# 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 获取计数最大的元素排序list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;c &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Counter(&lt;span style="color:#e6db74"&gt;&amp;#39;1122234444449999999999&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;most_common() &lt;span style="color:#75715e"&gt;# [(&amp;#39;9&amp;#39;, 10), (&amp;#39;4&amp;#39;, 6), (&amp;#39;2&amp;#39;, 3), (&amp;#39;1&amp;#39;, 2), (&amp;#39;3&amp;#39;, 1)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 获取前n个&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;most_common(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# [(&amp;#39;9&amp;#39;, 10), (&amp;#39;4&amp;#39;, 6), (&amp;#39;2&amp;#39;, 3)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 比较特殊的操作&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;+&lt;/span&gt;c &lt;span style="color:#75715e"&gt;# 去除计数为0和负数的元素&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;c &lt;span style="color:#75715e"&gt;# 去除计数为0和正数的元素, 并把负数的元素取绝对值&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="collectionsdefaultdict"&gt;collections.defaultdict
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;简介&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dict&lt;/code&gt;的子类&lt;/li&gt;
&lt;li&gt;提供&lt;code&gt;默认值构造器&lt;/code&gt;传到内部, 可为不存在的key设置默认值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;默认值构造器&lt;/code&gt;为一个无参可调用的对象, 返回默认的数据&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;示例&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python3" data-lang="python3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; collections &lt;span style="color:#f92672"&gt;import&lt;/span&gt; defaultdict
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df_dict &lt;span style="color:#f92672"&gt;=&lt;/span&gt; defaultdict(list)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df_dict[&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df_dict[&lt;span style="color:#e6db74"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append(&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df_dict[&lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append(&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df_dict[&lt;span style="color:#e6db74"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;]&lt;span style="color:#f92672"&gt;.&lt;/span&gt;append(&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# {&amp;#39;a&amp;#39;: [1, 2], &amp;#39;b&amp;#39;: [3, 4]}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;df_dict &lt;span style="color:#f92672"&gt;=&lt;/span&gt; defaultdict(&lt;span style="color:#66d9ef"&gt;lambda&lt;/span&gt;: list()) &lt;span style="color:#75715e"&gt;# 使用lambda&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>centos7安装puppeteer依赖</title><link>https://blog.skytoup.com/p/centos7%E5%AE%89%E8%A3%85puppeteer%E4%BE%9D%E8%B5%96/</link><pubDate>Fri, 31 Aug 2018 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/centos7%E5%AE%89%E8%A3%85puppeteer%E4%BE%9D%E8%B5%96/</guid><description>&lt;p&gt;&lt;code&gt;python&lt;/code&gt;使用&lt;code&gt;request-html&lt;/code&gt;时, 发现&lt;code&gt;pyppeteer&lt;/code&gt;报了几个错误, 然后越来越多&lt;code&gt;chrome&lt;/code&gt;的进程&lt;/p&gt;
&lt;p&gt;查了下原因, 原来&lt;code&gt;pyppeteer&lt;/code&gt;只是下载了&lt;code&gt;chromium&lt;/code&gt;, 但是没有安装需要的依赖&lt;/p&gt;
&lt;p&gt;安装补上即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yum install pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXtst.x86_64 cups-libs.x86_64 libXScrnSaver.x86_64 libXrandr.x86_64 GConf2.x86_64 alsa-lib.x86_64 atk.x86_64 gtk3.x86_64 ipa-gothic-fonts xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-utils xorg-x11-fonts-cyrillic xorg-x11-fonts-Type1 xorg-x11-fonts-misc -y
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>pip install pycurl 小问题</title><link>https://blog.skytoup.com/p/pip-install-pycurl-%E5%B0%8F%E9%97%AE%E9%A2%98/</link><pubDate>Fri, 31 Aug 2018 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/pip-install-pycurl-%E5%B0%8F%E9%97%AE%E9%A2%98/</guid><description>&lt;p&gt;&lt;code&gt;pip install pycurl&lt;/code&gt;后, 使用&lt;code&gt;pycurl&lt;/code&gt;时, 出现了些错误:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	PycURL: ImportError: pycurl: libcurl link-time ssl backend (nss) is different from compile-time ssl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解决方法:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip uninstall pycurl
export PYCURL_SSL_LIBRARY=nss # 错误提示nss, 所有使用nss, 所有选项 openssl, gnutls, nss
pip install pycurl
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>python3分析Homebrew &amp; 清理无用软件</title><link>https://blog.skytoup.com/p/python3%E5%88%86%E6%9E%90homebrew-%E6%B8%85%E7%90%86%E6%97%A0%E7%94%A8%E8%BD%AF%E4%BB%B6/</link><pubDate>Wed, 27 Jun 2018 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/python3%E5%88%86%E6%9E%90homebrew-%E6%B8%85%E7%90%86%E6%97%A0%E7%94%A8%E8%BD%AF%E4%BB%B6/</guid><description>&lt;p&gt;Homebrew是MacOSX上的软件包管理工具, 可以方便安装各种Apple没有预装的东西。安装软件时, 还会自动安装依赖, 但是卸载时, 依赖不会被卸载。(本人有洁癖, 喜欢把没用的东西都清理掉)&lt;/p&gt;
&lt;h2 id="获取安装列表"&gt;获取安装列表
&lt;/h2&gt;&lt;p&gt;Homebrew有提供命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew deps --installed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后会出现一堆软件及其依赖, 例如:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;autoconf: 
automake: autoconf
carthage: 
cmake: 
python@2: gdbm openssl readline sqlite
readline: 
sqlite: readline
tree: 
usbmuxd: libplist libusb
watchman: gdbm openssl pcre python@2 readline sqlite
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数量少的话, 人工分析也是可以的, 然而平时乱装东西(安装是在方便)&amp;hellip;&lt;/p&gt;
&lt;h2 id="分析python3"&gt;分析(python3)
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;执行命令, 获取依赖列表&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# 代码均为片段, 完整代码请到下面的源码地址
with os.popen(&amp;#39;brew deps --installed&amp;#39;) as popen:
	dep_lines = popen.read().split(&amp;#39;\n&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解析列表&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# 代码均为片段, 完整代码请到下面的源码地址
class BrewPackage:
	def __init__(self, name: str):
		self.name = name
		self.deps = []
		self.is_dep = False

	def __repr__(self) -&amp;gt; str:
		return &amp;#39;{}: {}&amp;#39;.format(self.name, self.deps)


for line in dep_lines:
	if not line:
		continue

	result = line.split(&amp;#39;: &amp;#39;)
	name = result[0]
	deps_name = result[1].split(&amp;#39; &amp;#39;) if len(result) == 2 and result[1] else None

	package = BrewPackage(name)

	if not deps_name:
		continue
	for dep_name in deps_name:
		dep_package = BrewPackage(name)
		dep_package.id_dep = True
		package.deps.append(dep_package)
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据整理&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# 代码均为片段, 完整代码请到下面的源码地址
# 上面第二步, 把BrewPackage缓存起来(每一个name只存在一个BrewPackage), 然后数据就会变成一张单向图结构.

all_package_dict = {} # name -&amp;gt; package


def get_cache_package(package_name: str) -&amp;gt; BrewPackage:
 pkg = all_package_dict.get(package_name)
 if not pkg:
 pkg = BrewPackage(package_name)
 all_package_dict[package_name] = pkg
 return pkg

# 把第二部创建BrewPackage的部分, 换成get_cache_package即可
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;输出结果&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# 代码均为片段, 完整代码请到下面的源码地址
# 为了更好看的输出结果, BrewPackage重写__repr__方法

@classmethod
def _deps_str(cls, package, level: int = 0, need_deep: bool = True):
 ts = &amp;#39;\t&amp;#39; * (level + 1)
 s = &amp;#39;&amp;#39;
 for p in package.deps:
 s += &amp;#39;{}- {}\n&amp;#39;.format(ts, p.name)
 if need_deep and p.deps:
 s += cls._deps_str(p, level + 1)
 return s

def __repr__(self):
	return &amp;#39;{}:\n{}&amp;#39;.format(self.name, BrewPackage._deps_str(self))

-------------------------------------------------------------------------

# 输出所有软件包
print(&amp;#39;All package and deps&amp;#39;)
print(&amp;#39;--------------------&amp;#39;)
for package in all_package_dict:
	print(package)
print(&amp;#39;\n&amp;#39;)

# 这里print出来的包, 都没有被依赖, 看看那个不认识或不想要都可以卸载掉, 卸载完一遍后, 需要再次运行该程序分析
# 如此循环, 直到没有找到需要卸载的包, 这样就清理干净了
print(&amp;#39;Not dependent packages&amp;#39;)
print(&amp;#39;----------------------&amp;#39;)
not_dep_package = [p for p in all_package_dict.values() if not p.is_dep]
for p in not_dep_package:
	print(p.name)
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;完整地址:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/skytoup/brew_deps" target="_blank" rel="noopener"
 &gt;github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://gitee.com/skytoup/brew_deps" target="_blank" rel="noopener"
 &gt;gitee&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>MaxOSX安装Rust 及 入门</title><link>https://blog.skytoup.com/p/maxosx%E5%AE%89%E8%A3%85rust-%E5%8F%8A-%E5%85%A5%E9%97%A8/</link><pubDate>Sun, 24 Jun 2018 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/maxosx%E5%AE%89%E8%A3%85rust-%E5%8F%8A-%E5%85%A5%E9%97%A8/</guid><description>&lt;h2 id="安装"&gt;安装
&lt;/h2&gt;&lt;h3 id="第一步-安装rustup"&gt;第一步, 安装&lt;code&gt;rustup&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;打开终端, 输入命令:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl https://sh.rustup.rs -sSf | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tip:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;brew install rust&lt;/code&gt;感觉有点问题, 还是用官方推荐的命令比较好.&lt;/li&gt;
&lt;li&gt;安装有点慢, 第一步下载&lt;code&gt;setup-init&lt;/code&gt;时, 可以给&lt;code&gt;curl&lt;/code&gt;设置代理; 到了第二步, &lt;code&gt;setup-init&lt;/code&gt;会使用内部的&lt;code&gt;curl&lt;/code&gt;下载, 暂时没有找到设置代理的方法.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="第二步-安装rust及套件docs-std-cargo-rustc"&gt;第二步, 安装&lt;code&gt;rust&lt;/code&gt;及套件(docs, std, cargo, rustc)
&lt;/h3&gt;&lt;p&gt;终端继续输入命令:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rustup install nightly
rustup default nightly
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就算安装完成了.&lt;/p&gt;
&lt;p&gt;TIP:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更新&lt;code&gt;rust&lt;/code&gt;命令: &lt;code&gt;rustup update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;更新&lt;code&gt;rustup&lt;/code&gt;命令: &lt;code&gt;rustup self update&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简略说明:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;rustc: &lt;code&gt;rust&lt;/code&gt;编译器, &lt;code&gt;rs&lt;/code&gt;文件编译成二进制可执行文件&lt;/li&gt;
&lt;li&gt;rust-docs: rust的文档&lt;/li&gt;
&lt;li&gt;rust-std: rust的标准库&lt;/li&gt;
&lt;li&gt;cargo: rust项目构建工具&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="基本使用"&gt;基本使用
&lt;/h2&gt;&lt;h3 id="rustc一般都不用"&gt;rustc(一般都不用)
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;rustc main.rs
./main
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="cargo"&gt;cargo
&lt;/h3&gt;&lt;p&gt;创建项目&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cargo new &amp;lt;project_path&amp;gt; [--bin|lib] [--name]
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--bin&lt;/code&gt;是构建二进制可执行文件工程(默认), &lt;code&gt;--lib&lt;/code&gt;是构建库&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--name&lt;/code&gt;指定工程名, 默认为工程目录名&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;项目结构&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;src(源码目录)
	- main.rs 
Cargo.toml(项目配置文件)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;构建工程(终端当前路径为项目根目录)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cargo build # 构建工程
cargo run # 运行工程, 一般用这个就好, 源码修改后, 会自动构建
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="hello-world"&gt;Hello World
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;main.rs&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn main() {
	println!(&amp;quot;Hello World&amp;quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fn&lt;/code&gt;定义函数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;println!&lt;/code&gt;是一个宏, 打印字符串输出&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="参考"&gt;参考
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.rust-lang.org/zh-CN/install.html" target="_blank" rel="noopener"
 &gt;https://www.rust-lang.org/zh-CN/install.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/rust-lang-nursery/rustup.rs/blob/master/README.md" target="_blank" rel="noopener"
 &gt;https://github.com/rust-lang-nursery/rustup.rs/blob/master/README.md&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Objective-C消息转发探究</title><link>https://blog.skytoup.com/p/objective-c%E6%B6%88%E6%81%AF%E8%BD%AC%E5%8F%91%E6%8E%A2%E7%A9%B6/</link><pubDate>Tue, 08 May 2018 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/objective-c%E6%B6%88%E6%81%AF%E8%BD%AC%E5%8F%91%E6%8E%A2%E7%A9%B6/</guid><description>&lt;h1 id="概fei述hua"&gt;概(fei)述(hua)
&lt;/h1&gt;&lt;p&gt;&amp;hellip;(省略1024亿个byte)&lt;/p&gt;
&lt;h1 id="探究"&gt;探究
&lt;/h1&gt;&lt;p&gt;为了研究&lt;code&gt;Objective-C&lt;/code&gt;的消息转发，做了一系列测试&lt;/p&gt;
&lt;h2 id="test-0"&gt;Test 0
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;内容: 调用对象存的方法&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;步骤:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;定义一个&lt;code&gt;TestObject&lt;/code&gt;类，继承&lt;code&gt;NSObject&lt;/code&gt;, 重写的方法如下:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TestObject&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;BOOL&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;resolveClassMethod:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;SEL&lt;/span&gt;)sel {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;BOOL&lt;/span&gt; ret &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [super resolveClassMethod:sel];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;--&amp;gt;&amp;gt; %@ %p resolveClassMethod: %@, return: %d&amp;#34;&lt;/span&gt;, [self &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;], self, NSStringFromSelector(sel), ret);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ret;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;BOOL&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;respondsToSelector:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;SEL&lt;/span&gt;)aSelector {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;BOOL&lt;/span&gt; ret &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [super respondsToSelector:aSelector];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;--&amp;gt;&amp;gt; %@ %p respondsToSelector: %@, return: %d&amp;#34;&lt;/span&gt;, [self &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;], self, NSStringFromSelector(aSelector), ret);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ret;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;forwardingTargetForSelector:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;SEL&lt;/span&gt;)aSelector {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; ret &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [super forwardingTargetForSelector:aSelector];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;--&amp;gt;&amp;gt; %@ %p forwardingTargetForSelector: %@, return: %@&amp;#34;&lt;/span&gt;, [self &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;], self, NSStringFromSelector(aSelector), ret);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ret;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (NSMethodSignature &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;methodSignatureForSelector:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;SEL&lt;/span&gt;)aSelector {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSMethodSignature&lt;span style="color:#f92672"&gt;*&lt;/span&gt; ret &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [super methodSignatureForSelector:aSelector];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;--&amp;gt;&amp;gt; %@ %p methodSignatureForSelector: %@, return: %@&amp;#34;&lt;/span&gt;, [self &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;], self, NSStringFromSelector(aSelector), ret);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ret;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;forwardInvocation:&lt;/span&gt;(NSInvocation &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)anInvocation {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;--&amp;gt;&amp;gt; %@ %p forwardInvocation: %@&amp;#34;&lt;/span&gt;, [self &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;], self, anInvocation);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [super forwardInvocation:anInvocation];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
2. 代码

	```objc
	[[TestObject alloc] init];
	```
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结果: 什么都没有log&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结论: 调用存在的方法, 没有发生任何消息转发&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="test-1"&gt;Test 1
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;内容: 调用对象不存在的方法&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;步骤:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;代码&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TestObject&lt;span style="color:#f92672"&gt;*&lt;/span&gt; obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [[TestObject alloc] init];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj performSelector:NSSelectorFromString(&lt;span style="color:#e6db74"&gt;@&amp;#34;not exists sel&amp;#34;&lt;/span&gt;)];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结果: &lt;code&gt;TestObject&lt;/code&gt;调用了&lt;code&gt;forwardingTargetForSelector:&lt;/code&gt;(返回nil), 然后调用&lt;code&gt;methodSignatureForSelector:&lt;/code&gt;(返回nil), 最后log &lt;code&gt;unrecognized selector sent to instance&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结论: 调用不存在的方法, 发生了消息转发&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="test-2"&gt;Test 2
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;内容: &lt;code&gt;TestObject_1&lt;/code&gt;重写&lt;code&gt;forwardingTargetForSelector:&lt;/code&gt;(返回&lt;code&gt;TestObject&lt;/code&gt;对象), 调用它们都不存在的方法&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;步骤:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;定义&lt;code&gt;TestObject_1&lt;/code&gt;, 继承&lt;code&gt;TestObject&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TestObject_1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;forwardingTargetForSelector:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;SEL&lt;/span&gt;)aSelector {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; ret &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [[TestObject alloc] init];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;--&amp;gt;&amp;gt; %@ %p forwardingTargetForSelector: %@, return: %@&amp;#34;&lt;/span&gt;, [self &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;], self, NSStringFromSelector(aSelector), ret);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ret;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start="2"&gt;
&lt;li&gt;代码:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TestObject_2&lt;span style="color:#f92672"&gt;*&lt;/span&gt; obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [[TestObject_2 alloc] init];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj performSelector:NSSelectorFromString(&lt;span style="color:#e6db74"&gt;@&amp;#34;not exists sel&amp;#34;&lt;/span&gt;)];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结果: &lt;code&gt;TestObject_1&lt;/code&gt;对象先调用了&lt;code&gt;forwardingTargetForSelector:&lt;/code&gt;(返回TestObject对象), 然后&lt;code&gt;TestObject&lt;/code&gt;对象调用&lt;code&gt;forwardingTargetForSelector:&lt;/code&gt;(返回nil), 跟着调用&lt;code&gt;methodSignatureForSelector:&lt;/code&gt;(返回nil), 最后log &lt;code&gt;unrecognized selector sent to instance&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结论: 不存在的方法转发到了其它对象处理失败&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="test-3"&gt;Test 3
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;内容: &lt;code&gt;TestObject_2&lt;/code&gt;重写&lt;code&gt;forwardingTargetForSelector:&lt;/code&gt;(返回&lt;code&gt;TestObject_1&lt;/code&gt;), 调用&lt;code&gt;TestObject_2&lt;/code&gt;不存在, 但&lt;code&gt;TestObject_1&lt;/code&gt;存在的方法&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;步骤:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;定义&lt;code&gt;TestObject_2&lt;/code&gt;, 继承&lt;code&gt;TestObject&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TestObject_2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;id&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;forwardingTargetForSelector:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;SEL&lt;/span&gt;)aSelector {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;id&lt;/span&gt; ret &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [[TestObject_1 alloc] init];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;--&amp;gt;&amp;gt; %@ %p forwardingTargetForSelector: %@, return: %@&amp;#34;&lt;/span&gt;, [self &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;], self, NSStringFromSelector(aSelector), ret);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; ret;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start="2"&gt;
&lt;li&gt;TestObject_1, 添加方法&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;testObject_1ExistsMethod&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;--&amp;gt;&amp;gt; %@ %p I am exists&amp;#34;&lt;/span&gt;, [self &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;], self);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;}
```&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;3. 代码

```objc
TestObject_2* obj = [[TestObject_2 alloc] init];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;[obj performSelector:NSSelectorFromString(@&amp;ldquo;testObject_1ExistsMethod&amp;rdquo;)];
```&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;结果: &lt;code&gt;TestObject_2&lt;/code&gt;对象先调用了&lt;code&gt;forwardingTargetForSelector:&lt;/code&gt;(返回TestObject_1对象), 然后&lt;code&gt;TestObject_1&lt;/code&gt;对象调用了&lt;code&gt;testObject_1ExistsMethod&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;结论: 不存在的方法转发到了其它对象处理成功&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="test-4"&gt;Test 4
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;内容: &lt;code&gt;TestObject_3&lt;/code&gt;重写&lt;code&gt;methodSignatureForSelector:&lt;/code&gt;(不返回nil)和&lt;code&gt;forwardInvocation:&lt;/code&gt;, 调用不存在的方法&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;步骤:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;定义&lt;code&gt;TestObject_3&lt;/code&gt;, 继承&lt;code&gt;TestObject&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@implementation&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TestObject_3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (NSMethodSignature &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;methodSignatureForSelector:&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;SEL&lt;/span&gt;)aSelector {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;--&amp;gt;&amp;gt; %@ %p methodSignatureForSelector: %@&amp;#34;&lt;/span&gt;, [self &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;], self, NSStringFromSelector(aSelector));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; [NSObject methodSignatureForSelector:&lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(init)];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;forwardInvocation:&lt;/span&gt;(NSInvocation &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)anInvocation {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;--&amp;gt;&amp;gt; %@ %p forwardInvocation: %@&amp;#34;&lt;/span&gt;, [self &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;], self, anInvocation);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// [super forwardInvocation:anInvocation]; // will crash, because the method signature is not right
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start="2"&gt;
&lt;li&gt;代码&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TestObject_3&lt;span style="color:#f92672"&gt;*&lt;/span&gt; obj &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [[TestObject_3 alloc] init];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[obj performSelector:NSSelectorFromString(&lt;span style="color:#e6db74"&gt;@&amp;#34;not exists sel&amp;#34;&lt;/span&gt;)];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结果: 先调用了&lt;code&gt;forwardingTargetForSelector:&lt;/code&gt;, 然后&lt;code&gt;methodSignatureForSelector:&lt;/code&gt;, 最后&lt;code&gt;forwardInvocation:&lt;/code&gt;, 没发生崩溃&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结论: &lt;code&gt;TestObject_3&lt;/code&gt;自己处理了不存在方法&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="总结"&gt;总结
&lt;/h1&gt;&lt;p&gt;如下图
&lt;img alt="png" class="gallery-image" data-flex-basis="244px" data-flex-grow="101" height="886" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/objective-c%E6%B6%88%E6%81%AF%E8%BD%AC%E5%8F%91%E6%8E%A2%E7%A9%B6/MethodForwarding.png" srcset="https://blog.skytoup.com/p/objective-c%E6%B6%88%E6%81%AF%E8%BD%AC%E5%8F%91%E6%8E%A2%E7%A9%B6/MethodForwarding_hu_20aaf290d725d9a.png 800w, https://blog.skytoup.com/p/objective-c%E6%B6%88%E6%81%AF%E8%BD%AC%E5%8F%91%E6%8E%A2%E7%A9%B6/MethodForwarding.png 902w" width="902"&gt;&lt;/p&gt;
&lt;h1 id="测试代码"&gt;测试代码
&lt;/h1&gt;&lt;p&gt;TestMessageForwarding: &lt;a class="link" href="https://github.com/skytoup/TestMessageForwarding" target="_blank" rel="noopener"
 &gt;https://github.com/skytoup/TestMessageForwarding&lt;/a&gt;&lt;/p&gt;</description></item><item><title>NSHashTable和NSMapTable</title><link>https://blog.skytoup.com/p/nshashtable%E5%92%8Cnsmaptable/</link><pubDate>Sat, 28 Apr 2018 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/nshashtable%E5%92%8Cnsmaptable/</guid><description>&lt;p&gt;原文来自Apple官方文档:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NSHashTable: &lt;a class="link" href="https://developer.apple.com/documentation/foundation/nshashtable?language=objc" target="_blank" rel="noopener"
 &gt;https://developer.apple.com/documentation/foundation/nshashtable?language=objc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;NSMapTable: &lt;a class="link" href="https://developer.apple.com/documentation/foundation/nsmaptable?language=objc" target="_blank" rel="noopener"
 &gt;https://developer.apple.com/documentation/foundation/nsmaptable?language=objc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;NSPointerFunctions: &lt;a class="link" href="https://developer.apple.com/documentation/foundation/nspointerfunctions?language=objc" target="_blank" rel="noopener"
 &gt;https://developer.apple.com/documentation/foundation/nspointerfunctions?language=objc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;NSPointerFunctionsOptions: &lt;a class="link" href="https://developer.apple.com/documentation/foundation/nspointerfunctionsoptions?language=objc" target="_blank" rel="noopener"
 &gt;https://developer.apple.com/documentation/foundation/nspointerfunctionsoptions?language=objc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="nshashtable"&gt;NSHashTable
&lt;/h1&gt;&lt;p&gt;一个类似set的集合，但是它有更多的内存语义(*更自由定义集合元素的内存如何管理)。&lt;/p&gt;
&lt;h2 id="概述"&gt;概述
&lt;/h2&gt;&lt;p&gt;NSHashTable和NSSet不同之处：
- 它可以对它的元素保持弱引用。
- 它的元素可以在输入时拷贝副本 或 使用指针地址对比相同和哈希。
- 他可以存储任意指针(它的元素不限制是对象[*应该是指NSObject])&lt;/p&gt;
&lt;p&gt;你可以配置一个NSHashTable实例用于任意的指针，不限于是对象，显然你可以能够使用把C函数转为 void* 指针。它的基本API(如addObject:)将会不对非对象的指针进行类型转换。&lt;/p&gt;
&lt;p&gt;因为它的配置，NSHashTable不是一个Set，应为它们有不同之处(比如，如果配置了使用对比指针地址，则两个isEqual:的字符串都将被添加)&lt;/p&gt;
&lt;p&gt;当配置哈希表时，请注意只有在NSHashTableOptions列出的配置才能使API正常使用&amp;ndash;包括复制、归档和快速遍历。而其它NSPointerFunctions配置使用于某些配置，例如保持任意指针，单并非所有组合的配置都是有效的。对于谋学组合，哈希表可能无法正常工作，甚至无法正常初始化。&lt;/p&gt;
&lt;h1 id="nsmaptable"&gt;NSMapTable
&lt;/h1&gt;&lt;p&gt;一个类似字典的集合，但是它有更多的内存语义(*更自由定义集合元素的内存如何管理)。&lt;/p&gt;
&lt;h2 id="概述-1"&gt;概述
&lt;/h2&gt;&lt;p&gt;NSMapTable和NSDictionary不同之处：
- Key/Value 是可以配置保持弱引用，当对象被回收时就会被移除。
- Key/Value可以在输入时拷贝副本 或 使用指针地址对比相同和哈希。
- 他可以存储任意指针(它的元素不限制是对象[*应该是指NSObject])&lt;/p&gt;
&lt;p&gt;你可以配置一个NSMapTable实例去操作任意指针，不限于对象，显然你可以能够使用把C函数转为 void* 指针。它的基本API(如addObject:forKey:)将会不对非对象的指针进行类型转换。&lt;/p&gt;
&lt;p&gt;当配置MapTable时，请注意只有在NSMapTableOptions列出的配置才能使API正常使用&amp;ndash;包括复制、归档和快速遍历。而其它NSPointerFunctions配置使用于某些配置，例如保持任意指针，单并非所有组合的配置都是有效的。对于谋学组合，哈希表可能无法正常工作，甚至无法正常初始化。&lt;/p&gt;
&lt;h1 id="nspointerfunctions"&gt;NSPointerFunctions
&lt;/h1&gt;&lt;p&gt;一个NSPointerFunctions实例定义了调出函数用于管理如何保存指针。&lt;/p&gt;
&lt;h2 id="概述-2"&gt;概述
&lt;/h2&gt;&lt;p&gt;NSPointerFunctions实例所指定的函数被分为两个簇——定义一些“特性”的函数，如“object”或“C-string”，以及描述内存管理问题的函数，如内存分配函数。对于常见的特性和内存管理器的选择有一些常量(参见内存和特性选项)。&lt;/p&gt;
&lt;p&gt;NSHashTable，NSMapTable 和 NSPointerArray使用一个NSPointerFunctions对象定义指针的获取和存储。但是请注意，并不是所有的特性和内存管理的组合对这些集合都有效。指针集合对象在输出输入时复制NSPointerFunctions对象，	所以不能把NSPointerFunctions子类化。&lt;/p&gt;
&lt;h1 id="nspointerfunctionsoptions"&gt;NSPointerFunctionsOptions
&lt;/h1&gt;&lt;p&gt;对NSPointerFunction对象定义内存和特性的配置&lt;/p&gt;
&lt;h2 id="概述-3"&gt;概述
&lt;/h2&gt;&lt;p&gt;当指定一个值时，你只能使用内存选项的其中一个。&lt;/p&gt;
&lt;h2 id="配置选项"&gt;配置选项
&lt;/h2&gt;&lt;h3 id="memory-options这些选项是互斥的"&gt;Memory Options(这些选项是互斥的)
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;NSPointerFunctionsMachVirtualMemory
&lt;ul&gt;
&lt;li&gt;使用Mach内存&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NSPointerFunctionsMallocMemory
&lt;ul&gt;
&lt;li&gt;删除使用free()，复制使用calloc()&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NSPointerFunctionsOpaqueMemory
&lt;ul&gt;
&lt;li&gt;当指针被删除时，不要采取任何操作&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NSPointerFunctionsStrongMemory
&lt;ul&gt;
&lt;li&gt;使用强引用来存储，在复制时使用垃圾回收&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NSPointerFunctionsWeakMemory
&lt;ul&gt;
&lt;li&gt;对ARC和GC的读写使用弱引用。使用NSPointerFunctionsWeakMemory对象引用被释放后将在将会返回NULL&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="personality-options这些选项是互斥的"&gt;Personality Options(这些选项是互斥的)
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;NSPointerFunctionsCStringPersonality
&lt;ul&gt;
&lt;li&gt;使用字符串的哈希 和 比对；C-string使用‘%s’&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NSPointerFunctionsIntegerPersonality
&lt;ul&gt;
&lt;li&gt;使用未位移的值用于哈希和比对&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NSPointerFunctionsObjectPersonality
&lt;ul&gt;
&lt;li&gt;使用哈希 和 isEqual方法对比是否相同，使用description方法显示详情&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NSPointerFunctionsObjectPointerPersonality
&lt;ul&gt;
&lt;li&gt;使用移位指针进行哈希和直接对比相同，使用description方法显示详情&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NSPointerFunctionsOpaquePersonality
&lt;ul&gt;
&lt;li&gt;使用移位指针进行哈希和直接对比相同&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NSPointerFunctionsStructPersonality
&lt;ul&gt;
&lt;li&gt;使用内存的哈希 和 memcmp(使用sizeFunction).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>pypy3安装和基本使用</title><link>https://blog.skytoup.com/p/pypy3%E5%AE%89%E8%A3%85%E5%92%8C%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/</link><pubDate>Fri, 28 Jul 2017 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/pypy3%E5%AE%89%E8%A3%85%E5%92%8C%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/</guid><description>&lt;h2 id="安装"&gt;安装
&lt;/h2&gt;&lt;h3 id="macos"&gt;MacOS
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;先安装&lt;code&gt;brewhome&lt;/code&gt;, 官网: &lt;a class="link" href="https://brew.sh/" target="_blank" rel="noopener"
 &gt;brewhome&lt;/a&gt;(已安装的跳过)&lt;/li&gt;
&lt;li&gt;打开终端, 输入命令&lt;code&gt;brew install pypy3&lt;/code&gt;(没翻墙的可能比较慢)&lt;/li&gt;
&lt;li&gt;安装pypy的pip, 在终端输入&lt;code&gt;curl -O https://bootstrap.pypa.io/get-pip.py &amp;amp;&amp;amp; pypy3 get-pip.py&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="centos"&gt;CentOS
&lt;/h3&gt;&lt;p&gt;待测试&amp;hellip;&lt;/p&gt;
&lt;h2 id="基本使用"&gt;基本使用
&lt;/h2&gt;&lt;h3 id="基本命令"&gt;基本命令
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pypy3&lt;/code&gt;: 运行脚本, 相当于&lt;code&gt;python3&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pypy3 xxx.py&lt;/code&gt; # 运行脚本xxx.py&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pypy3 -m pip install xxx&lt;/code&gt; # 安装依赖xxx&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pypy3 -m venv xxx&lt;/code&gt; # 创建一个虚拟环境到xxx目录
&lt;ul&gt;
&lt;li&gt;切换到该虚拟环境: &lt;code&gt;source xxx/bin/activate&lt;/code&gt;, 退出虚拟环境: &lt;code&gt;deactivate&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pip_pypy3&lt;/code&gt;: 安装依赖库, 相当于 &lt;code&gt;pip3&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pip_pypy3 install xxx&lt;/code&gt; # 安装依赖xxx&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pip_pypy3 install -r requirement.txt&lt;/code&gt; # 递归安装requirement.txt里面的依赖&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;easy_install_pypy3&lt;/code&gt;: 安装依赖库, 相当于&lt;code&gt;easy_install3&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;easy_install_pypy3 xxx&lt;/code&gt; # 安装依赖xxx&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="测试性能"&gt;测试性能
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Python3" data-lang="Python3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# test.py&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; time &lt;span style="color:#f92672"&gt;import&lt;/span&gt; time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;times &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;start_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; t &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(times):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sum &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; st &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; &lt;span style="color:#f92672"&gt;**&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sum &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; i
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;: speed time: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(t, time()&lt;span style="color:#f92672"&gt;-&lt;/span&gt;st))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;total_time &lt;span style="color:#f92672"&gt;=&lt;/span&gt; time()&lt;span style="color:#f92672"&gt;-&lt;/span&gt;start_time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;&amp;#39;speed time avrage: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;, total: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(total_time &lt;span style="color:#f92672"&gt;/&lt;/span&gt; times, total_time))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;blockquote&gt;
 &lt;p&gt;python3 test.py&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="img" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px"&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0: speed time: 0.16138482093811035
1: speed time: 0.1585860252380371
2: speed time: 0.1659379005432129
3: speed time: 0.1676487922668457
4: speed time: 0.16137290000915527
5: speed time: 0.16071820259094238
6: speed time: 0.16538310050964355
7: speed time: 0.1611499786376953
8: speed time: 0.17231488227844238
9: speed time: 0.17661476135253906
speed time avrage: 0.165160608291626, total: 1.6516060829162598
&lt;/code&gt;&lt;/pre&gt;

 &lt;blockquote&gt;
 &lt;p&gt;pypy3 test.py&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="img" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px"&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0: speed time: 0.005280017852783203
1: speed time: 0.003924131393432617
2: speed time: 0.002089977264404297
3: speed time: 0.0024471282958984375
4: speed time: 0.0020821094512939453
5: speed time: 0.0025098323822021484
6: speed time: 0.002827882766723633
7: speed time: 0.0020329952239990234
8: speed time: 0.002518892288208008
9: speed time: 0.001984119415283203
speed time avrage: 0.002937006950378418, total: 0.02937006950378418
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;简单的测试来看, pypy比cpython快了好几倍&lt;/p&gt;</description></item><item><title>一个实现App在线下载、安装的工具</title><link>https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/</link><pubDate>Wed, 01 Mar 2017 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/</guid><description>&lt;h2 id="废话"&gt;废话
&lt;/h2&gt;&lt;p&gt;平时都在使用&lt;code&gt;fir&lt;/code&gt;, 但是公司网速有时候很蛋疼, 安装包体积一大, 就安装个10多分钟都搞不定。而且&lt;code&gt;fir&lt;/code&gt;开始有点点收费了, 所以干脆自己做一个简单的工具。断断续续地做了一个月, 终于完成了一些基本功能。&lt;/p&gt;
&lt;h2 id="效果图"&gt;效果图
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;首页&lt;/strong&gt;
&lt;img alt="pic" class="gallery-image" data-flex-basis="476px" data-flex-grow="198" height="1270" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/home.webp" srcset="https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/home_hu_64b3d489e85d6951.webp 800w, https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/home_hu_f018bc86d1d19145.webp 1600w, https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/home_hu_f00a104f28ad5ed9.webp 2400w, https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/home.webp 2520w" width="2520"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;上传App&lt;/strong&gt;
&lt;img alt="pic" class="gallery-image" data-flex-basis="665px" data-flex-grow="277" height="896" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/upload.webp" srcset="https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/upload_hu_76b396eaeafe1105.webp 800w, https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/upload_hu_cfed648bd6f7c608.webp 1600w, https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/upload_hu_d9ca0bf9dcc75759.webp 2400w, https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/upload.webp 2484w" width="2484"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;App详情页&lt;/strong&gt;
&lt;img alt="pic" class="gallery-image" data-flex-basis="591px" data-flex-grow="246" height="1016" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/app_detail.webp" srcset="https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/app_detail_hu_4ff81ba3781a870b.webp 800w, https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/app_detail_hu_3cf76b99f817d104.webp 1600w, https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/app_detail_hu_196bed2ab663e90e.webp 2400w, https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/app_detail.webp 2504w" width="2504"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;App编辑页&lt;/strong&gt;
&lt;img alt="pic" class="gallery-image" data-flex-basis="644px" data-flex-grow="268" height="928" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/app_edit.webp" srcset="https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/app_edit_hu_c5d2f8215e4f7adb.webp 800w, https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/app_edit_hu_53046c1062f63942.webp 1600w, https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/app_edit_hu_e407853f4ee0a286.webp 2400w, https://blog.skytoup.com/p/%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0app%E5%9C%A8%E7%BA%BF%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E7%9A%84%E5%B7%A5%E5%85%B7/app_edit.webp 2492w" width="2492"&gt;&lt;/p&gt;
&lt;h2 id="基本思路"&gt;基本思路
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;上传安装包, 然后区分&lt;code&gt;apk&lt;/code&gt;和&lt;code&gt;ipa&lt;/code&gt;安装包来进行解析, 获取各种包信息, 最后存到数据库&lt;/li&gt;
&lt;li&gt;&lt;code&gt;apk&lt;/code&gt;可以直接下载点击安装, &lt;code&gt;ipa&lt;/code&gt;则需要一个plist文件来在线安装(详情请参考: &lt;a class="link" href="http://help.apple.com/deployment/ios/#/apda0e3426d7" target="_blank" rel="noopener"
 &gt;http://help.apple.com/deployment/ios/#/apda0e3426d7&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;省略各种增删改查&amp;hellip;&amp;hellip;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="使用技术"&gt;使用技术
&lt;/h2&gt;&lt;h3 id="服务端"&gt;服务端
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;python&lt;/code&gt;3.5以上的版本&lt;/li&gt;
&lt;li&gt;选择了一个比较新的框架👉&lt;a class="link" href="https://github.com/channelcat/sanic" target="_blank" rel="noopener"
 &gt;Sanic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;数据库简单使用了&lt;code&gt;sqlite3&lt;/code&gt;, ORM使用了&lt;a class="link" href="https://github.com/zzzeek/sqlalchemy" target="_blank" rel="noopener"
 &gt;sqlalchemy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;源码传送门&lt;/strong&gt; 👉 &lt;a class="link" href="https://github.com/skytoup/AppServer" target="_blank" rel="noopener"
 &gt;AppServer&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="前端基本没做过-很简陋"&gt;前端(基本没做过, 很简陋)
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;直接选用了&lt;code&gt;React&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;看到&lt;a class="link" href="https://github.com/dvajs/dva" target="_blank" rel="noopener"
 &gt;dva&lt;/a&gt;这个&lt;code&gt;React&lt;/code&gt;框架比较简单, 就选了这个&lt;/li&gt;
&lt;li&gt;在&lt;code&gt;dva&lt;/code&gt;哪里看到&lt;a class="link" href="https://github.com/ant-design/ant-design" target="_blank" rel="noopener"
 &gt;antd&lt;/a&gt;这个UI框架, 感觉还不错&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;源码传送门&lt;/strong&gt; 👉 &lt;a class="link" href="https://github.com/skytoup/AppServerHTML" target="_blank" rel="noopener"
 &gt;AppServerHTML&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;喜欢的就给两个start吧😁
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Python3的虚拟环境</title><link>https://blog.skytoup.com/p/python3%E7%9A%84%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83/</link><pubDate>Sun, 28 Aug 2016 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/python3%E7%9A%84%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83/</guid><description>&lt;h1 id="背景"&gt;背景
&lt;/h1&gt;&lt;p&gt;Python安装第三方模块的时候, 是安装到系统全局的环境。当你的多个项目里面用到了同一个库, 但是版本却不一样, 这样就会产生冲突了。&lt;/p&gt;
&lt;h1 id="pyvenv还有一个比较好的非官方工具virtualenv就不介绍了"&gt;pyvenv(还有一个比较好的非官方工具Virtualenv就不介绍了)
&lt;/h1&gt;&lt;p&gt;pyvenv是Python3安装时自带的创建一个虚拟环境工具(tip: Python3.4版本前的pyven创建的虚拟环境不带pip)&lt;/p&gt;
&lt;p&gt;用这个工具就能创建出多个Python的虚拟环境, 把第三方模块安装到不同的虚拟环境, 就能让不同的项目使用不同的Python环境, 互相不会受到影响。&lt;/p&gt;
&lt;h1 id="基本使用maclinux-win很久没用了"&gt;基本使用(Mac、Linux, Win很久没用了)
&lt;/h1&gt;&lt;p&gt;创建虚拟环境命令:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pyvenv /path/to/new/virtual/environment
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;激活虚拟环境命令:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;source /path/to/virtual/environment/bin/activate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;退出虚拟环境命令:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;deactivate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例子:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pyvenv py_1-evn # 当前目录创建一个虚拟环境叫py_1-evn
source py_1-evn/bin/activate # 在本终端激活这个虚拟环境(没有激活虚拟环境时是使用全局的环境)
pip install 。。。。 # 可以安装各种第三方模块, 都会安装到激活的虚拟环境
python xxx.py # 在激活的虚拟环境运行py脚本
deactivate # 退出激活的虚拟环境
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id="更高级的使用python-api"&gt;更高级的使用(Python API)
&lt;/h1&gt;&lt;p&gt;请参考官方文档: &lt;a class="link" href="https://docs.python.org/3/library/venv.html" target="_blank" rel="noopener"
 &gt;https://docs.python.org/3/library/venv.html&lt;/a&gt;&lt;/p&gt;</description></item><item><title>iOS自动化打包上传的踩坑记</title><link>https://blog.skytoup.com/p/ios%E8%87%AA%E5%8A%A8%E5%8C%96%E6%89%93%E5%8C%85%E4%B8%8A%E4%BC%A0%E7%9A%84%E8%B8%A9%E5%9D%91%E8%AE%B0/</link><pubDate>Tue, 31 May 2016 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/ios%E8%87%AA%E5%8A%A8%E5%8C%96%E6%89%93%E5%8C%85%E4%B8%8A%E4%BC%A0%E7%9A%84%E8%B8%A9%E5%9D%91%E8%AE%B0/</guid><description>&lt;pre&gt;&lt;code&gt;2016-09-11:
1.添加使用Python封装打包命令的开源库(最下面~)
2016-06-06:
1.经过一轮测试之后, 发现文章有点错漏, 小修改一下, 增加命令四
&lt;/code&gt;&lt;/pre&gt;

 &lt;blockquote&gt;
 &lt;p&gt;每次要出包的时候, 总要打开&lt;code&gt;XCode&lt;/code&gt;, 然后点击&lt;code&gt;Product-Archive&lt;/code&gt;, 等待好几分钟的各种build, 然后还要手动上传到&lt;code&gt;AppStore&lt;/code&gt;, 甚至还要上传到&lt;code&gt;蒲公英&lt;/code&gt;、&lt;code&gt;fir&lt;/code&gt;等&amp;hellip;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;很久以前就看了很多关于&lt;code&gt;iOS&lt;/code&gt;自动打包&lt;code&gt;ipa&lt;/code&gt;的文章, 看着感觉很简单, 但是因为一直没有&lt;code&gt;AppleDeveloper&lt;/code&gt;账号可以给我用, 到了真的要搞自动打包的时候, 才发现到处都是坑。&lt;/p&gt;
&lt;h1 id="基本命令"&gt;基本命令
&lt;/h1&gt;&lt;ol&gt;
&lt;li&gt;xcedebuild: 生成&lt;code&gt;Archive&lt;/code&gt;、导出&lt;code&gt;ipa&lt;/code&gt;, 还有其它功能&amp;hellip;&lt;/li&gt;
&lt;li&gt;xcrun: 把&lt;code&gt;*.app&lt;/code&gt;打包成&lt;code&gt;ipa&lt;/code&gt;, 还有其它功能&amp;hellip;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="基本使用"&gt;基本使用
&lt;/h1&gt;&lt;p&gt;一. &lt;code&gt;xcedebuild&lt;/code&gt;打包&lt;code&gt;Archive&lt;/code&gt;文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xcedebuild -workspace ${path to *.xcworkspace} -scheme ${scheme} -destination generic/platform=iOS archive -configuration Release ONLY_ACTIVE_ARCH=NO -archivePath ${export path *.xcarichive}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;-workspace 你的&lt;code&gt;*.xcworkspace&lt;/code&gt;文件&lt;/li&gt;
&lt;li&gt;-scheme 项目文件里面的&lt;code&gt;scheme&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;-archivePath 生成的&lt;code&gt;*.xcarichive&lt;/code&gt;文件路径&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;二. &lt;code&gt;xcedebuild&lt;/code&gt;从&lt;code&gt;*.xcarchive&lt;/code&gt;导出&lt;code&gt;ipa&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xcodebuild -exportArchive -exportFormat IPA -archivePath ${path to *.xcarchive} -exportPath ${export path *.ipa} -exportProvisioningProfile ${ProvisioningProfileName}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;-archivePath 你的&lt;code&gt;*.xcarchive&lt;/code&gt;文件, 可以使用上一个命令导出&lt;/li&gt;
&lt;li&gt;-exportPath 导出的&lt;code&gt;ipa&lt;/code&gt;路径&lt;/li&gt;
&lt;li&gt;exportProvisioningProfile 你的Distribution发布证书的名称(只需要名称)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;三. &lt;code&gt;xcrun&lt;/code&gt;打包&lt;code&gt;ipa&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xcrun -sdk iphoneos PackageApplication -v ${path to *.app} -o ${package path *.ipa}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;-v 你的&lt;code&gt;*.app&lt;/code&gt;文件, 生成的&lt;code&gt;*.xcarchive&lt;/code&gt;里面有&lt;/li&gt;
&lt;li&gt;-o 打包生成的&lt;code&gt;*.ipa&lt;/code&gt;文件路径, 注意！！！这里是不能填相对路径, 因为这里的路径环境变量不是当前执行命令的路径了&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;四. 最新的正确&lt;code&gt;xcodebuild&lt;/code&gt;导出ipa&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xcodebuild -exportArchive -archivePath ${path to *.xcarchive} -exportPath ${export path to dir} -exportOptionsPlist ${path to export options *.plist}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;-archivePath 你的&lt;code&gt;*.xcarchive&lt;/code&gt;文件, 可以使用第二个命令导出&lt;/li&gt;
&lt;li&gt;-exportPath 导出的&lt;code&gt;ipa&lt;/code&gt;目录, ipa的名称好像是scheme的名称&lt;/li&gt;
&lt;li&gt;-exportOptionsPlist 导出plist格式的配置文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;exportOptionPlist: 新建一个plist文件, 里面是一个Dictionary, key-value如下, 都是可选值, 不需要全部填上&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;ol&gt;
&lt;li&gt;compileBitcode: Bool&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;For non-App Store exports, should Xcode re-compile the app from bitcode? Defaults to YES.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ol start="2"&gt;
&lt;li&gt;embedOnDemandResourcesAssetPacksInBundle : Bool&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;For non-App Store exports, if the app uses On Demand Resources and this is YES, asset packs are embedded in the app bundle so that the app can be tested without a server to host asset packs. Defaults to YES unless onDemandResourcesAssetPacksBaseURL is specified.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ol start="3"&gt;
&lt;li&gt;iCloudContainerEnvironment&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;For non-App Store exports, if the app is using CloudKit, this configures the &amp;ldquo;com.apple.developer.icloud-container-environment&amp;rdquo; entitlement. Available options: Development and Production. Defaults to Development.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ol start="4"&gt;
&lt;li&gt;manifest : Dictionary&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;For non-App Store exports, users can download your app over the web by opening your distribution manifest file in a web browser. To generate a distribution manifest, the value of this key should be a dictionary with three sub-keys: appURL, displayImageURL, fullSizeImageURL. The additional sub-key assetPackManifestURL is required when using on demand resources.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ol start="5"&gt;
&lt;li&gt;method : String&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Describes how Xcode should export the archive. Available options: app-store, ad-hoc, package, enterprise, development, and developer-id. The list of options varies based on the type of archive. Defaults to development.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ol start="6"&gt;
&lt;li&gt;onDemandResourcesAssetPacksBaseURL : String&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;For non-App Store exports, if the app uses On Demand Resources and embedOnDemandResourcesAssetPacksInBundle isn&amp;rsquo;t YES, this should be a base URL specifying where asset packs are going to be hosted. This configures the app to download asset packs from the specified URL.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ol start="7"&gt;
&lt;li&gt;teamID : String&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;The Developer Portal team to use for this export. Defaults to the team used to build the archive.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ol start="8"&gt;
&lt;li&gt;thinning : String&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;For non-App Store exports, should Xcode thin the package for one or more device variants? Available options: &lt;!-- raw HTML omitted --&gt; (Xcode produces a non-thinned universal app), &lt;!-- raw HTML omitted --&gt; (Xcode produces a universal app and all available thinned variants), or a model identifier for a specific device (e.g. &amp;ldquo;iPhone7,1&amp;rdquo;). Defaults to &lt;!-- raw HTML omitted --&gt;.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ol start="9"&gt;
&lt;li&gt;uploadBitcode : Bool&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;For App Store exports, should the package include bitcode? Defaults to YES.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ol start="10"&gt;
&lt;li&gt;uploadSymbols : Bool&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;For App Store exports, should the package include symbols? Defaults to YES.&lt;/p&gt;

 &lt;/blockquote&gt;

 &lt;/blockquote&gt;
&lt;h1 id="踩坑"&gt;踩坑
&lt;/h1&gt;&lt;h2 id="坑一"&gt;坑一
&lt;/h2&gt;&lt;p&gt;使用第一个命令前, 需要确保你的项目的签名配置好, 证书下好最新的&lt;/p&gt;
&lt;h2 id="坑二"&gt;坑二
&lt;/h2&gt;&lt;p&gt;第二个命令的&lt;code&gt;-exportProvisioningProfile&lt;/code&gt;填的只是你的发布证书的名称, 不是那一串&lt;code&gt;id&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="坑三"&gt;坑三
&lt;/h2&gt;&lt;p&gt;第二个命令打包出来的&lt;code&gt;*.ipa&lt;/code&gt;不能用来上传到&lt;code&gt;AppStore&lt;/code&gt;, 一直报CocoaPods里面的第三方库签名错误&lt;/p&gt;
&lt;h2 id="坑四"&gt;坑四
&lt;/h2&gt;&lt;p&gt;打包出来的&lt;code&gt;*.ipa&lt;/code&gt;需要上传到&lt;code&gt;AppSotre&lt;/code&gt;的话, 可以使用第三个命令, &lt;code&gt;xcrun&lt;/code&gt;那一个&lt;/p&gt;
&lt;h2 id="坑五"&gt;坑五
&lt;/h2&gt;&lt;p&gt;使用第三个命令打包出来的&lt;code&gt;*.ipa&lt;/code&gt;, 上传到&lt;code&gt;AppStore&lt;/code&gt;之后, 登录到&lt;code&gt;iTunes Connect-APP-所有构建版本&lt;/code&gt;查看到上传的&lt;code&gt;*.ipa&lt;/code&gt;正在构建。但是过了一会儿, &lt;code&gt;AppleDeveloper&lt;/code&gt;账号的邮箱就会收到一封报错的邮件, 大概是说你的&lt;code&gt;*.ipa&lt;/code&gt;包里面, 缺少了一个&lt;code&gt;SwiftSupport&lt;/code&gt;文件夹&lt;/p&gt;
&lt;p&gt;经过各种搜索之后, 原来需要把&lt;code&gt;xcrun&lt;/code&gt;打包出来的&lt;code&gt;*.ipa&lt;/code&gt;解压, 然后新建一个文件夹, &lt;code&gt;*.xcarchive&lt;/code&gt;里面的&lt;code&gt;SwiftSupport&lt;/code&gt;文件夹&lt;code&gt;copy&lt;/code&gt;进去, 还有把&lt;code&gt;ipa&lt;/code&gt;解压出来的&lt;code&gt;move&lt;/code&gt;进入, 最后打个zip包, 再改成&lt;code&gt;ipa&lt;/code&gt;后缀就可以上传到&lt;code&gt;AppStore&lt;/code&gt;了(应该吧, 还没测试😂)&lt;/p&gt;
&lt;h2 id="坑六"&gt;坑六
&lt;/h2&gt;&lt;p&gt;经过一轮测试之后, 发现用这个&lt;code&gt;xcrun&lt;/code&gt;这个命令打的包需要自己吧SwiftSupport文件加到压缩包, 其实有一个命令没有那么麻烦的&amp;hellip;&lt;/p&gt;
&lt;p&gt;使用上面的第四个命令使用&lt;code&gt;*.xcarchive&lt;/code&gt;把ipa导出, 导出的&lt;code&gt;*.ipa&lt;/code&gt;里面会包含了&lt;code&gt;SwiftSupport&lt;/code&gt;, 还不需要自己把它加进去&lt;/p&gt;
&lt;h1 id="番外篇"&gt;番外篇
&lt;/h1&gt;&lt;p&gt;在踩到了第五个坑之后, 在&lt;code&gt;github&lt;/code&gt;发现了一个&lt;code&gt;iOS&lt;/code&gt;的打包、发布库&amp;hellip;
上地址: &lt;a class="link" href="https://github.com/nomad/shenzhen" target="_blank" rel="noopener"
 &gt;https://github.com/nomad/shenzhen&lt;/a&gt;	
懒得自己搞的可以使用这个库, 感觉还是挺不错的&lt;/p&gt;
&lt;h1 id="python封装打包命令"&gt;Python封装打包命令
&lt;/h1&gt;&lt;p&gt;github: &lt;a class="link" href="https://github.com/skytoup/package-ipa" target="_blank" rel="noopener"
 &gt;package-ipa&lt;/a&gt;&lt;/p&gt;</description></item><item><title>2016 CocosPods安装教程</title><link>https://blog.skytoup.com/p/2016-cocospods%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/</link><pubDate>Mon, 16 May 2016 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/2016-cocospods%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/</guid><description>
 &lt;blockquote&gt;
 &lt;p&gt;2016-06-01
修改安装的第四个命令多写了一个&amp;rsquo;o'&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h1 id="cocoapods简介"&gt;CocoaPods简介
&lt;/h1&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;code&gt;CocoaPods&lt;/code&gt;是一个管理&lt;code&gt;Swift&lt;/code&gt;和&lt;code&gt;Objective-C&lt;/code&gt;的&lt;code&gt;Cocoa&lt;/code&gt;项目的依赖工具。它现在有超过一万八千多个库，可以优雅地帮助你扩展你的项目。简单的说，就是替你管理&lt;code&gt;Swift&lt;/code&gt;和&lt;code&gt;Objective-C&lt;/code&gt;的Cocoa项目的第三方库引入。&lt;/p&gt;

 &lt;/blockquote&gt;

 &lt;blockquote&gt;
 &lt;p&gt;官网地址: &lt;a class="link" href="https://cocoapods.org/" target="_blank" rel="noopener"
 &gt;https://cocoapods.org/&lt;/a&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h1 id="安装"&gt;安装
&lt;/h1&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Mac上面本来就自带了ruby，所有就不用自己安装了(除非你卸载了)。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;打开&lt;code&gt;Terminal&lt;/code&gt;(终端)，输入以下命令(第二个命令可能会需要稍等一会儿)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; gem sources --remove https://rubygems.org/
 gem source -a https://gems.ruby-china.org
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第一个命令是移除官方源，因为在不翻墙的情况下，使用起来比较慢；第二个命令是添加&lt;code&gt;ruby-china&lt;/code&gt;的&lt;code&gt;RubyGems&lt;/code&gt;镜像(很多旧教程都是说使用taobao的gem源，但是taobao的gem源已经停止维护了，原文: &lt;a class="link" href="https://ruby-china.org/topics/29250" target="_blank" rel="noopener"
 &gt;https://ruby-china.org/topics/29250&lt;/a&gt;)。&lt;/p&gt;
&lt;p&gt;接下来运行一个命令查看是否成功添加了&lt;code&gt;ruby-china&lt;/code&gt;的&lt;code&gt;gem&lt;/code&gt;源:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; gem source
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;出现下图这样子，则代表成功添加~&lt;/p&gt;
&lt;p&gt;&lt;img alt="img" class="gallery-image" data-flex-basis="1205px" data-flex-grow="502" height="84" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/2016-cocospods%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/abcd4f6db25da96606fc3d80f0f2f50e_MD5.png" width="422"&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后就可以开始真正安装&lt;code&gt;CocoaPods&lt;/code&gt;了，输入一下命令:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; sudo gem install cocoapods
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等一会儿就能安装完成~~~&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装结束后，需要运行一下命令初始化&lt;code&gt;CocoaPods&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; pod setup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;没有什么错误的话，就算了安装结束了。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="基本使用"&gt;基本使用
&lt;/h1&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;打开&lt;code&gt;Terminal&lt;/code&gt;(终端)，&lt;code&gt;cd&lt;/code&gt;到你的Project目录，输入一下命令:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; pod init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行结束后，该目录下，会生成了一个&lt;code&gt;Podfile&lt;/code&gt;文件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用文本编辑器(vim、Sublime Text2、等等&amp;hellip;)打开它(&lt;code&gt;Podfile&lt;/code&gt;)，大概会看到以下的东西&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; platform :ios, 'xxx' # 目标平台及其版本
 use_frameworks! # swift项目需要这句话，是Objective-C项目的话，请在前面加个`#`注释掉
 target 'xxxx' do
 	# 在这里添加你的依赖库说明，如pod xxx
 	pod 'Alamofire', '~&amp;gt; 3.1’ # 例如这是引入Alamofire这个第三方库
 end
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;编辑完&lt;code&gt;Podfile&lt;/code&gt;后，使用&lt;code&gt;Terminal&lt;/code&gt;(终端)输入其中一个命令(需要cd到项目的根目录，即&lt;code&gt;Podfile&lt;/code&gt;所在目录):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; pod install --no-repo-update
 or
 pod install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一个命令是不更新本地库信息进行安装，速度会快一点，毕竟不需要更新。但是会有一点点问题，当有一个新的库发布的时候，就会无法安装成功。如果不嫌麻烦，可以定时执行以下命令更新&lt;code&gt;CocoaPods&lt;/code&gt;的库，然后就可以在一段时间使用以上的第一个命令进行安装:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; pod repo update
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装完成之后，打开项目就需要打开&lt;code&gt;xxx.xcworkspace&lt;/code&gt;，而不是&lt;code&gt;xxx.xcodeproj&lt;/code&gt;了&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果在安装之后，修改了&lt;code&gt;Podfile&lt;/code&gt;文件，可以执行以下的其中一个命令进行库的更新(两个命令的区别和上面说的一样):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; pod update --no-repo-update
 or
 pod update
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="安装cocoapods的可能失败原因"&gt;安装CocoaPods的可能失败原因
&lt;/h1&gt;&lt;p&gt;gem过旧，使用以下命令更新一下，再进行安装(先切换到了&lt;code&gt;ruby-china&lt;/code&gt;的&lt;code&gt;gem&lt;/code&gt;源再运行一下命令更新):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	sudo gem update
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>iOS使用runtime监测UIViewController的dealloc</title><link>https://blog.skytoup.com/p/ios%E4%BD%BF%E7%94%A8runtime%E7%9B%91%E6%B5%8Buiviewcontroller%E7%9A%84dealloc/</link><pubDate>Tue, 02 Feb 2016 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/ios%E4%BD%BF%E7%94%A8runtime%E7%9B%91%E6%B5%8Buiviewcontroller%E7%9A%84dealloc/</guid><description>&lt;p&gt;平时在iOS开发的时候，很多情况会导致内存泄露。有时候因为循环引用，导致了&lt;code&gt;UIViewController&lt;/code&gt;不回收，还有其它好多原因。一般检测内存泄露都是使用&lt;code&gt;Xcode&lt;/code&gt;的&lt;code&gt;Instruments&lt;/code&gt;工具。但是这个工具有点复杂，新手入门还是有点难度。所以想到了使用runtime替换&lt;code&gt;UIViewController&lt;/code&gt;的&lt;code&gt;-(void)dealloc:&lt;/code&gt;方法的实现，检测&lt;code&gt;ViewController&lt;/code&gt;是否被释放，从而知道&lt;code&gt;ViewController&lt;/code&gt;里面有没有内存泄露。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;runtime的相关细节就不说了，不理解也能用，复制放到项目里面就好了。
&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id="一思路"&gt;一、思路
&lt;/h1&gt;&lt;ol&gt;
&lt;li&gt;需要被替换的方法是&lt;code&gt;UIViewController&lt;/code&gt;的&lt;code&gt;-(void)dealloc:&lt;/code&gt;，所以新建一个&lt;code&gt;UIViewController&lt;/code&gt;的&lt;code&gt;Category&lt;/code&gt;，在其&lt;code&gt;+(void)load&lt;/code&gt;里面执行方法替换。&lt;/li&gt;
&lt;li&gt;替换的新方法里面做一个简单地log一下当前&lt;code&gt;UIViewController&lt;/code&gt;的类名就好了就好了，即当UIViewController被回收的时候，log其类名。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="二实现"&gt;二、实现
&lt;/h1&gt;&lt;p&gt;1.新建一个UIViewController的&lt;code&gt;Category&lt;/code&gt;，编写新的dealloc方法。代码如下(可自行修改):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objective-c" data-lang="objective-c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;skyLogInDealloc&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;-------------start-------------&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;Dealloc : %@&amp;#34;&lt;/span&gt;, NSStringFromClass([self &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;]));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;--------------end--------------&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self skyLogInDealloc];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;2.重写&lt;code&gt;+(void)onLoad:&lt;/code&gt;方法。代码如下:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objective-c" data-lang="objective-c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;load&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [super load];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;SEL&lt;/span&gt; originSEL &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NSSelectorFromString(&lt;span style="color:#e6db74"&gt;@&amp;#34;dealloc&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;SEL&lt;/span&gt; swapSEL &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(skyLogInDealloc);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Method originMethod &lt;span style="color:#f92672"&gt;=&lt;/span&gt; class_getInstanceMethod(self, originSEL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Method swapMethod &lt;span style="color:#f92672"&gt;=&lt;/span&gt; class_getInstanceMethod(self, swapSEL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;IMP&lt;/span&gt; originIMP &lt;span style="color:#f92672"&gt;=&lt;/span&gt; method_getImplementation(originMethod);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;IMP&lt;/span&gt; swapIMP &lt;span style="color:#f92672"&gt;=&lt;/span&gt; method_getImplementation(swapMethod);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;BOOL&lt;/span&gt; didAddMethod &lt;span style="color:#f92672"&gt;=&lt;/span&gt; class_addMethod(self, originSEL, swapIMP, method_getTypeEncoding(originMethod));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(didAddMethod) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; class_replaceMethod(self, swapSEL, originIMP, method_getTypeEncoding(originMethod));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; method_exchangeImplementations(originMethod, swapMethod);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;完整的m文件实现代码&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objective-c" data-lang="objective-c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#if DEBUG
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;+ (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;load&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [super load];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;SEL&lt;/span&gt; originSEL &lt;span style="color:#f92672"&gt;=&lt;/span&gt; NSSelectorFromString(&lt;span style="color:#e6db74"&gt;@&amp;#34;dealloc&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;SEL&lt;/span&gt; swapSEL &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;@selector&lt;/span&gt;(skyLogInDealloc);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Method originMethod &lt;span style="color:#f92672"&gt;=&lt;/span&gt; class_getInstanceMethod(self, originSEL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Method swapMethod &lt;span style="color:#f92672"&gt;=&lt;/span&gt; class_getInstanceMethod(self, swapSEL);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;IMP&lt;/span&gt; originIMP &lt;span style="color:#f92672"&gt;=&lt;/span&gt; method_getImplementation(originMethod);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;IMP&lt;/span&gt; swapIMP &lt;span style="color:#f92672"&gt;=&lt;/span&gt; method_getImplementation(swapMethod);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;BOOL&lt;/span&gt; didAddMethod &lt;span style="color:#f92672"&gt;=&lt;/span&gt; class_addMethod(self, originSEL, swapIMP, method_getTypeEncoding(originMethod));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(didAddMethod) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; class_replaceMethod(self, swapSEL, originIMP, method_getTypeEncoding(originMethod));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; } &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; method_exchangeImplementations(originMethod, swapMethod);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)&lt;span style="color:#a6e22e"&gt;skyLogInDealloc&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;-------------start-------------&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;Dealloc : %@&amp;#34;&lt;/span&gt;, NSStringFromClass([self &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt;]));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; NSLog(&lt;span style="color:#e6db74"&gt;@&amp;#34;--------------end--------------&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [self skyLogInDealloc];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id="三部分细节"&gt;三、部分细节
&lt;/h1&gt;&lt;ol&gt;
&lt;li&gt;在ARC下，使用&lt;code&gt;@selector(dealloc:)&lt;/code&gt;会报错，所以只好这样子获取它的SEL: &lt;code&gt;NSSelectorFromString(@&amp;quot;dealloc&amp;quot;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DEBUG&lt;/code&gt;是一个宏，当构建项目使用Debug的时候，其值会为YES，当使用Release的时候，其值会是NO。加上去就是为了发布的时候，也不需要担心忘记将其移除功能。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;附上github地址: &lt;a class="link" href="https://github.com/skytoup/SkyLogInDealloc" target="_blank" rel="noopener"
 &gt;https://github.com/skytoup/SkyLogInDealloc&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Webstorm使用babel6</title><link>https://blog.skytoup.com/p/webstorm%E4%BD%BF%E7%94%A8babel6/</link><pubDate>Thu, 28 Jan 2016 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/webstorm%E4%BD%BF%E7%94%A8babel6/</guid><description>&lt;h1 id="一初始化工程"&gt;一、初始化工程
&lt;/h1&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;npm&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;init&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;project name&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输入各种信息之后，新建工程完毕。&lt;/p&gt;
&lt;h1 id="二安装babel"&gt;二、安装babel
&lt;/h1&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;npm&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;install&lt;/span&gt; &lt;span style="color:#f92672"&gt;--&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;save&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dev&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;babel&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;cli&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id="三修改webstorm配置"&gt;三、修改Webstorm配置
&lt;/h1&gt;&lt;p&gt;打开Setting -&amp;gt; Languages &amp;amp; Frameworks -&amp;gt; JavaScript -&amp;gt; JavaScript language version，选择ECMAScript6。&lt;/p&gt;
&lt;h1 id="四安装babel预插件"&gt;四、安装babel预插件
&lt;/h1&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;npm&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;install&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;babel&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;preset&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;es2015&lt;/span&gt; &lt;span style="color:#f92672"&gt;--&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;save&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;dev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id="五创建babelrc配置文件"&gt;五、创建.babelrc配置文件
&lt;/h1&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;echo &amp;#39;{ &amp;#34;presets&amp;#34;: [&amp;#34;es2015&amp;#34;] }&amp;#39; &amp;gt; .babelrc
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;或自行在项目根目录创建&lt;code&gt;.babelrc&lt;/code&gt;文件，并输入&lt;code&gt;{ &amp;quot;presets&amp;quot;: [&amp;quot;es2015&amp;quot;] }&lt;/code&gt;，保存、退出。&lt;/p&gt;
&lt;h1 id="end"&gt;END
&lt;/h1&gt;&lt;pre&gt;&lt;code&gt;tip: 运行的时候选择转换好的文件，别选原文件！！！
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更详细请参考官方说明: &lt;a class="link" href="http://babeljs.io/docs/setup/#webstorm" target="_blank" rel="noopener"
 &gt;Babel_Webstorm&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Node.js的BT下载</title><link>https://blog.skytoup.com/p/node.js%E7%9A%84bt%E4%B8%8B%E8%BD%BD/</link><pubDate>Mon, 25 Jan 2016 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/node.js%E7%9A%84bt%E4%B8%8B%E8%BD%BD/</guid><description>&lt;p&gt;近来想用Node.js做一个BT下载的程序，于是研究了一下BT下载相关的知识。&lt;/p&gt;
&lt;h1 id="一bt文件解析"&gt;一、BT文件解析
&lt;/h1&gt;&lt;pre&gt;&lt;code&gt;用了那么久的bt下载，都知道下载前，都是先解析种子文件(.torrent)的吧。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;种子文件使用的是&lt;code&gt;BEncode(B编码)&lt;/code&gt;保存数据，这种编码有四种数据结构：&lt;/p&gt;
&lt;h3 id="1string字符串"&gt;1.string(字符串)
&lt;/h3&gt;&lt;p&gt;string的编码为 &lt;code&gt;&amp;lt;string length&amp;gt;:&amp;lt;string&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;例: 7:example, 表示字符串 'example'
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="2integer整数"&gt;2.integer(整数)
&lt;/h3&gt;&lt;p&gt;integer的编码为 &lt;code&gt;i&amp;lt;integer&amp;gt;e&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;例: i123456e, 表示整数 123456
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="3list列表"&gt;3.list(列表)
&lt;/h3&gt;&lt;p&gt;list的编码为 &lt;code&gt;l&amp;lt;BEncode&amp;gt;e&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;例: l6:stringi123ee, 表示数组 ['string', 123]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="4dictionary字典"&gt;4.dictionary(字典)
&lt;/h3&gt;&lt;p&gt;dictionary的编码为 &lt;code&gt;d&amp;lt;BEcode的string&amp;gt;&amp;lt;BEncode&amp;gt;e&lt;/code&gt;,即&lt;code&gt;d&amp;lt;key&amp;gt;&amp;lt;value&amp;gt;e&lt;/code&gt;,key为BEcode的string,value为BEncode&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;例:d3:key5:value4:testi123ee, 表示{key:'value', test:123}
&lt;/code&gt;&lt;/pre&gt;

 &lt;blockquote&gt;
 &lt;p&gt;注: list和dictionary可以相互嵌套&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;解析基本思路，dictionary的key肯定为字符串，value和list的元素为任意类型，使用递归思路解析比较简单。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;附上一份自己写的简单解析代码: &lt;a class="link" href="https://github.com/skytoup/node.js-BEncode" target="_blank" rel="noopener"
 &gt;node.js简单解析bencode&lt;/a&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h1 id="二bt文件结构"&gt;二、BT文件结构
&lt;/h1&gt;&lt;p&gt;参考别人的文章: &lt;a class="link" href="http://www.cnblogs.com/hnrainll/archive/2011/07/21/2112809.html" target="_blank" rel="noopener"
 &gt;torrent文件分析&lt;/a&gt;&lt;/p&gt;
&lt;h1 id="三bt协议"&gt;三、BT协议
&lt;/h1&gt;&lt;p&gt;还是参考别人的文章:&lt;/p&gt;
&lt;ol start="0"&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="http://blog.chinaunix.net/uid-26548237-id-3056731.html" target="_blank" rel="noopener"
 &gt;BT（带中心Tracker）通信协议的分析&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="http://blog.chinaunix.net/uid-14408083-id-2814554.html" target="_blank" rel="noopener"
 &gt;BitTorrent协议规范&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="http://blog.csdn.net/wengpingbo/article/details/9174363" target="_blank" rel="noopener"
 &gt;常见P2P协议之BitTorrent 分析&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 发现BT协议还是挺复杂的,下载的代码一时半刻写不出来。
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="番外篇"&gt;番外篇
&lt;/h1&gt;&lt;h2 id="一-关于info_hash"&gt;一、 关于info_hash
&lt;/h2&gt;&lt;p&gt;网上的资料比较少，搜了好久，发现很多都是说得不是很清楚。&lt;/p&gt;
&lt;p&gt;1.BT协议中的info_hash&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;info_hash是种子解析后的对象的info节点中的pieces，其长度为20的倍数，每20个字节对应一块文件。在BT协议中，下载文件需要一块一块下载，下载那一块，就是看你传过去的info_hash。&lt;/p&gt;
&lt;p&gt;但是BT文件里面的部分数据是ASCII码，不能直接传输过去，需要经过一定的编码。编码很简单，凡是ASCII码的数字、字母，都按数字、字母传输，其余的以它的16进制前面加一个&lt;code&gt;%&lt;/code&gt;符号传输。&lt;/p&gt;
&lt;p&gt;例如: ASCII编码 &lt;code&gt;6D8875&lt;/code&gt; 应该为 &lt;code&gt;m%88u&lt;/code&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;2.BT种子转磁力链接的info_hash&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;经过各种搜索、测试，最后看源码发现，BT种子是如何转磁力链接。
首先把种子的info节点以BEcode编码，将其sha1散列，最后把得到的结果拼接到这里的末尾: &lt;code&gt;magnet:?xt=urn:btih:&lt;/code&gt;。多个文件的情况，好像是用&lt;code&gt;&amp;amp;&lt;/code&gt;符号拼接每一个文件。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;原本想做一个测试测试的，谁知道node.js用buffer读取bt的部分string后，length就变了......
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="二nodejs的bt下载库"&gt;二、node.js的BT下载库
&lt;/h2&gt;&lt;p&gt;找了好久, 终于发现了一个node.js的BT下载库, 功能还是挺强大的，貌似还有其它的功能。&lt;/p&gt;
&lt;p&gt;上地址: &lt;a class="link" href="https://github.com/feross/webtorrent" target="_blank" rel="noopener"
 &gt;webtorrent&lt;/a&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;官方文档写得挺详细的，而且这个库简单易用。至于还有其它什么功能我也不太了解了。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="文章参考"&gt;文章参考
&lt;/h2&gt;&lt;ol start="0"&gt;
&lt;li&gt;&lt;a class="link" href="http://www.cnblogs.com/hnrainll/archive/2011/07/21/2112809.html" target="_blank" rel="noopener"
 &gt;torrent文件分析&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="http://blog.chinaunix.net/uid-26548237-id-3056731.html" target="_blank" rel="noopener"
 &gt;BT（带中心Tracker）通信协议的分析&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="http://blog.chinaunix.net/uid-14408083-id-2814554.html" target="_blank" rel="noopener"
 &gt;BitTorrent协议规范&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="http://blog.csdn.net/wengpingbo/article/details/9174363" target="_blank" rel="noopener"
 &gt;常见P2P协议之BitTorrent 分析&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>React-Native搭建Redux框架</title><link>https://blog.skytoup.com/p/react-native%E6%90%AD%E5%BB%BAredux%E6%A1%86%E6%9E%B6/</link><pubDate>Thu, 24 Dec 2015 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/react-native%E6%90%AD%E5%BB%BAredux%E6%A1%86%E6%9E%B6/</guid><description>
 &lt;blockquote&gt;
 &lt;p&gt;近段时间在学习React-Native，发现了还可以用flux思想进行开发，于是便想试一试。&lt;/p&gt;
&lt;p&gt;查了各种关于flux的资料之后，有好几个这类型的框架。但是Redux这个框架貌似比较多人使用，所以就选择这个框架了。&lt;/p&gt;
&lt;p&gt;选好框架之后，发现框架的介绍资料很少，而且没有搭建的教程，只好自己做一下实验了。经过无数次实验、踩坑，终于成功了&amp;hellip;&amp;hellip;..&lt;/p&gt;
&lt;p&gt;注: 我是一个iOS程序员，不太懂大前端，为了学习react-native，react只是随便学习了一点基础，若本文有错，望你能指出&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;下面分享一下成果:&lt;/p&gt;
&lt;h3 id="1-搭建基本react-native项目"&gt;1. 搭建基本React-Native项目
&lt;/h3&gt;&lt;p&gt;很简单，大家都会，一句命令&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;react-native init 你的项目名称
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-添加框架模块"&gt;2. 添加框架模块
&lt;/h3&gt;&lt;p&gt;新建完成基本项目后，打开package.json，在dependencies下，添加&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;#34;react-redux&amp;#34;: &amp;#34;^3.1.2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;有人或许想问，最新的`react-redux`最新版不是4.x么？为什么不用最新的。	
这是一个坑，到github的项目主页看下面的文档，里面说4.x不支持`react-native`，请使用3.x的。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;添加完成后，继续输入一下命令：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm i &lt;span style="color:#75715e"&gt;# 安装刚才添加的项目&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm install --save redux
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm install --save redux-thunk
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-修改项目结构"&gt;3. 修改项目结构
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;以下是我的目录结构
├── App
│   ├── Action
│   ├── Component
│   ├── Container
│   ├── Reducer
│   ├── Store
│   └── Main.js
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="4创建redux项目框架相关名词不解析了请自行学习redux框架了解"&gt;4.创建Redux项目框架(相关名词不解析了，请自行学习Redux框架了解)
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;这里就不详细说了，简单说一下搭建时，编辑文件的顺序估计就可以了，详细的编写内容，到我的github上clone一下示例项目就好了。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;新建Action &amp;ndash;&amp;raquo; 新建Redicer &amp;ndash;&amp;raquo; 新建Store &amp;ndash;&amp;raquo; 新建Main.js入口 &amp;ndash;&amp;raquo; 修改android和iOS的入口文件(即项目根目录的index.xxx.js)&lt;/p&gt;
&lt;p&gt;基本就是这样子了~&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;最后附上详细代码的github地址: https://github.com/skytoup/react-native_ReduxTest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本文参考:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;react-native的Redux示例: &lt;a class="link" href="https://github.com/chentsulin/react-native-counter-ios-android" target="_blank" rel="noopener"
 &gt;https://github.com/chentsulin/react-native-counter-ios-android&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>React Native 之 Atom配置nuclide插件</title><link>https://blog.skytoup.com/p/react-native-%E4%B9%8B-atom%E9%85%8D%E7%BD%AEnuclide%E6%8F%92%E4%BB%B6/</link><pubDate>Wed, 09 Dec 2015 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/react-native-%E4%B9%8B-atom%E9%85%8D%E7%BD%AEnuclide%E6%8F%92%E4%BB%B6/</guid><description>&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;首先下载&lt;a class="link" href="https://atom.io" target="_blank" rel="noopener"
 &gt;Atom&lt;/a&gt;，下载地址:&lt;a class="link" href="https://atom.io" target="_blank" rel="noopener"
 &gt;https://atom.io&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;打开&lt;code&gt;Atom&lt;/code&gt;，在右上角&lt;code&gt;Atom&lt;/code&gt;的菜单处选择&lt;code&gt;Install Shell Comments&lt;/code&gt;(安装apm)
&lt;img alt="shell" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px"&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;到github下载一下&lt;code&gt;nuclide&lt;/code&gt;，直接用git或者下载zip文件解压。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 项目地址: https://github.com/facebook/nuclide
 git命令: git clone https://github.com/facebook/nuclide
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装&lt;code&gt;nuclide&lt;/code&gt;前，需要电脑有以下环境&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; - python 2.6 or later
 - Atom 0.209.0 or later
 - Node 0.12.0 or latr
 - node、npm、apm、git在你的$PATH
 (node、npm可通过安装node.js来安装)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;执行一下命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	cd nuclide
	./script/dev/setup
	# 上面的命令会通过npm下载东西，可能比较久
	apm link
	# 注意，上面的命令是把当前目录 软链接 到 ~/.atom/packages 目录下，所以安装完了之后，别把nuclide这个文件夹删了！！！

搞定之后，打开Atom试一下是否安装成功，如果不成功，`Atom`会提示你rebuild插件，我也不知道什么问题，我安装的时候失败了，点了几次rebuild就突然成功了。
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start="5"&gt;
&lt;li&gt;
&lt;p&gt;配置一下&lt;code&gt;nuclide-flow&lt;/code&gt;吧，这个插件可以检测语法错误，&lt;code&gt;CMD+左键点击&lt;/code&gt;跳转。&lt;/p&gt;
&lt;p&gt;使用这个插件之前，请先安装&lt;code&gt;flow&lt;/code&gt;，安装完之后，到&lt;code&gt;Atom&lt;/code&gt;的&lt;code&gt;Setting-Packages&lt;/code&gt;，找到&lt;code&gt;nuclide&lt;/code&gt;的插件，进入设置里面，滚动到&lt;code&gt;nuclide-flow&lt;/code&gt;插件的设置，把flow的位置填上，根据个人喜好打上几个选项的钩。
&lt;img alt="flow_1" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px"&gt;
&lt;img alt="flow_1" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px"&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;另外有几个插件也不错&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; - atom-beautify 代码格式化
 - atomerminal 打开终端，pwd为当前文件所在路径
 - docblockr 写注释的插件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以通过&lt;code&gt;apm install xxx&lt;/code&gt;来安装，如&lt;code&gt;apm install atom-beautify&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;接下来就可以好好享受Atom了~~~&lt;/p&gt;</description></item><item><title>iOS9 ATS 设置</title><link>https://blog.skytoup.com/p/ios9-ats-%E8%AE%BE%E7%BD%AE/</link><pubDate>Sat, 28 Nov 2015 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/ios9-ats-%E8%AE%BE%E7%BD%AE/</guid><description>&lt;p&gt;iOS9有一个新特性&amp;ndash;ATS(App Transport Security)，加强了一下App网络传输安全。&lt;/p&gt;
&lt;h2 id="官方文档描述"&gt;&lt;a class="link" href="https://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS9.html#//apple_ref/doc/uid/TP40016198-SW14" target="_blank" rel="noopener"
 &gt;官方文档描述&lt;/a&gt;:
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;App Transport Security (ATS) enforces best practices in the secure connections between an app and its back end. ATS prevents accidental disclosure, provides secure default behavior, and is easy to adopt; it is also on by default in iOS 9 and OS X v10.11. You should adopt ATS as soon as possible, regardless of whether you’re creating a new app or updating an existing one.&lt;/p&gt;
&lt;p&gt;If you’re developing a new app, you should use HTTPS exclusively. If you have an existing app, you should use HTTPS as much as you can right now, and create a plan for migrating the rest of your app as soon as possible. In addition, your communication through higher-level APIs needs to be encrypted using TLS version 1.2 with forward secrecy. If you try to make a connection that doesn&amp;rsquo;t follow this requirement, an error is thrown. If your app needs to make a request to an insecure domain, you have to specify this domain in your app&amp;rsquo;s Info.plist file.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;大概意思就是iOS9和OS X 10.11不能直接使用HTTP，只能使用HTTPS，现在开始，最好计划好迁移工作。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际上，没有强制一定要使用HTTPS，如果需要使用HTTP，可以到Info.plist文件配置一下。&lt;/p&gt;
&lt;h3 id="ats基本使用大概用json格式表示"&gt;ATS基本使用(大概用Json格式表示)
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;在Info.plist的Information Property List下添加NSAppTransportSecurity，类型是Dictionary。&lt;/li&gt;
&lt;li&gt;在NSAppTransportSecurity下添加NSAllowsArbitraryLoads，类型是Boolean，值是YES。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;{
	NSAppTransportSecurity: {
		NSAllowsArbitraryLoads : YES
	}
}
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;	大概意思就是，配置ATS，设置为允许使用任意的HTTP/HTTPS。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="ats进阶使用大概用json格式表示"&gt;ATS进阶使用(大概用Json格式表示)
&lt;/h3&gt;&lt;p&gt;1、允许单个服务器的HTTP连接:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#960050;background-color:#1e0010"&gt;AppTransportSecurity:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#960050;background-color:#1e0010"&gt;NSExceptionDomains:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#960050;background-color:#1e0010"&gt;允许HTTP访问的地址:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#960050;background-color:#1e0010"&gt;NSExceptionAllowsInsecureHTTPLoads&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;YES&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;2、允许单个服务器的HTTPS使用较低的安全协议&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#960050;background-color:#1e0010"&gt;AppTransportSecurity:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#960050;background-color:#1e0010"&gt;NSExceptionDomains:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#960050;background-color:#1e0010"&gt;允许HTTP访问的地址:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#960050;background-color:#1e0010"&gt;NSExceptionRequiresForwardSecrecy&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;NO,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#960050;background-color:#1e0010"&gt;NSExceptionMinimumTLSVersion&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;TLSv1.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;3、使用ATS，且允许使用HTTP访问指定的服务器&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#960050;background-color:#1e0010"&gt;AppTransportSecurity:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#960050;background-color:#1e0010"&gt;NSExceptionDomains:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#960050;background-color:#1e0010"&gt;允许HTTP访问的地址:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#960050;background-color:#1e0010"&gt;NSExceptionAllowsInsecureHTTPLoads&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;YES&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#960050;background-color:#1e0010"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#960050;background-color:#1e0010"&gt;NSAllowsArbitraryLoads&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;YES&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;4、指定服务器使用ATS，其余的不使用&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#960050;background-color:#1e0010"&gt;NSAppTransportSecurity:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#960050;background-color:#1e0010"&gt;NSAllowsArbitraryLoads&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;=&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;YES,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#960050;background-color:#1e0010"&gt;NSExceptionDomains:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			&lt;span style="color:#960050;background-color:#1e0010"&gt;使用HTTPS访问的地址:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;				&lt;span style="color:#960050;background-color:#1e0010"&gt;NSExceptionAllowsInsecureHTTPLoads&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;NO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;			}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>IntelliJ IDEA开发golang环境配置</title><link>https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/</link><pubDate>Thu, 26 Nov 2015 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/</guid><description>&lt;p&gt;看到一篇文章说IntelliJ IDEA开发作为Go的开发环境不错，突然发神经地想试了一下。
谁知道跟着教程走，到后面越来越不对劲，去百度其它教程，谁知道千篇一律。。。&lt;/p&gt;
&lt;p&gt;好了下面开始了&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;首先把&lt;code&gt;GO&lt;/code&gt;安装好。。。（自行安装，附上一篇我之前写的&lt;a class="link" href="http://skytoup.wicp.net/2015/10/03/MacOs%E4%B8%8B%E5%AE%89%E8%A3%85go-lang/" target="_blank" rel="noopener"
 &gt;MAC安装GO&lt;/a&gt;）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装&lt;code&gt;IntelliJ IDEA&lt;/code&gt;，下载地址: &lt;a class="link" href="https://www.jetbrains.com/idea/download/" target="_blank" rel="noopener"
 &gt;https://www.jetbrains.com/idea/download/&lt;/a&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;下载&lt;code&gt;go-lang-idea-plugin&lt;/code&gt;这个插件，下载地址: &lt;a class="link" href="https://plugins.jetbrains.com/plugin/5047" target="_blank" rel="noopener"
 &gt;https://plugins.jetbrains.com/plugin/5047&lt;/a&gt;。(PS:网上百度的基本都是下源码、编译，搞了一个下午编译，谁知道有已经编译好的可以下载)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;下载之后，是一个zip文件，不需要解压，打开IntelliJ IDEA，打开&lt;code&gt;Preferences-&amp;gt;Plugins&lt;/code&gt;，点击&lt;code&gt;Install plugin from disk...&lt;/code&gt;，选择刚下载的zip文件，然后重启一下，插件就这样安装好了。
&lt;img class="gallery-image" data-flex-basis="396px" data-flex-grow="165" height="1200" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/900924a191d1a2916eafce6a2c4d129e_MD5.png" srcset="https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/900924a191d1a2916eafce6a2c4d129e_MD5_hu_29a06b547a816ebc.png 800w, https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/900924a191d1a2916eafce6a2c4d129e_MD5_hu_13d8ad557323cf4.png 1600w, https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/900924a191d1a2916eafce6a2c4d129e_MD5.png 1980w" width="1980"&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;打开&lt;code&gt;File-&amp;gt;Project Structure...&lt;/code&gt;，找不到的随便打开一个项目就能看到。点击&lt;code&gt;SDKS&lt;/code&gt;，新建一个&lt;code&gt;GO SDK&lt;/code&gt;，填上&lt;code&gt;GO&lt;/code&gt;的安装目录。
&lt;img class="gallery-image" data-flex-basis="297px" data-flex-grow="123" height="520" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/0e76db77d6c12dad80fee3a58bca6885_MD5.png" width="644"&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="736px" data-flex-grow="307" height="400" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/a4023a032804cdbabba20a2f917aff80_MD5.png" srcset="https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/a4023a032804cdbabba20a2f917aff80_MD5_hu_ab7d7916061eeaec.png 800w, https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/a4023a032804cdbabba20a2f917aff80_MD5.png 1228w" width="1228"&gt;&lt;/p&gt;
&lt;p&gt;使用:随便新建一个Go项目，点击&lt;code&gt;Edit Configurations...&lt;/code&gt;，新建一个&lt;code&gt;Go Application&lt;/code&gt;，右边&lt;code&gt;File&lt;/code&gt;你的&lt;code&gt;pack main&lt;/code&gt;包含&lt;code&gt;func main&lt;/code&gt;的文件，&lt;code&gt;Output directory&lt;/code&gt;为编译后的文件输出目录。新建完毕后，选择新建的Debug选项就可以编译、运行程序了。
&lt;img class="gallery-image" data-flex-basis="1216px" data-flex-grow="506" height="118" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/689955efbed3eda00072cac95068941e_MD5.png" width="598"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="356px" data-flex-grow="148" height="376" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/5f6e4ca08fe46418ccc27f9aa4171855_MD5.png" width="558"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="742px" data-flex-grow="309" height="554" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/c8d0e837c1fc9e844f6318d6b20d5d0e_MD5.png" srcset="https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/c8d0e837c1fc9e844f6318d6b20d5d0e_MD5_hu_c8a7aeb80fe94d86.png 800w, https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/c8d0e837c1fc9e844f6318d6b20d5d0e_MD5_hu_1d147a35b84be908.png 1600w, https://blog.skytoup.com/p/intellij-idea%E5%BC%80%E5%8F%91golang%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/c8d0e837c1fc9e844f6318d6b20d5d0e_MD5.png 1714w" width="1714"&gt;&lt;/p&gt;
&lt;p&gt;接下来来点IntelliJ IDEA的快捷键吧(我的是Mac OSX) :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;CMD+Shift+O 查找跳转文件&lt;/li&gt;
&lt;li&gt;CMD+Shift+L 代码对齐&lt;/li&gt;
&lt;li&gt;CMD+Shift+Alt+F go fmt 一个文件&lt;/li&gt;
&lt;li&gt;CMD+Shift+Alt+P go fmt整个项目&lt;/li&gt;
&lt;li&gt;CMD+Alt+O 自动import&lt;/li&gt;
&lt;li&gt;CMD+F12 显示当前文件的结构&lt;/li&gt;
&lt;li&gt;按住CMD点击结构体可以源码跳转&lt;/li&gt;
&lt;li&gt;CMD+P 显示函数参数&lt;/li&gt;
&lt;li&gt;CMD+E 显示最近编辑文件&lt;/li&gt;
&lt;li&gt;Alt+Enter 自动修复错误&lt;/li&gt;
&lt;li&gt;Shift+F6 重构&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>MacOs下安装go lang</title><link>https://blog.skytoup.com/p/macos%E4%B8%8B%E5%AE%89%E8%A3%85go-lang/</link><pubDate>Sat, 03 Oct 2015 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/macos%E4%B8%8B%E5%AE%89%E8%A3%85go-lang/</guid><description>&lt;h2 id="1下载安装包"&gt;1.下载安装包
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;由于官网被墙了，所以到国内的一个go论坛下载:&lt;a class="link" href="http://golangtc.com/download" target="_blank" rel="noopener"
 &gt;点击进入下载&lt;/a&gt;
&lt;img class="gallery-image" data-flex-basis="7728px" data-flex-grow="3220" height="70" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/macos%E4%B8%8B%E5%AE%89%E8%A3%85go-lang/c5524307595fd3df77801fe1f754ad09_MD5.png" srcset="https://blog.skytoup.com/p/macos%E4%B8%8B%E5%AE%89%E8%A3%85go-lang/c5524307595fd3df77801fe1f754ad09_MD5_hu_7dd084146d128c4c.png 800w, https://blog.skytoup.com/p/macos%E4%B8%8B%E5%AE%89%E8%A3%85go-lang/c5524307595fd3df77801fe1f754ad09_MD5_hu_ebf7db252e98ac02.png 1600w, https://blog.skytoup.com/p/macos%E4%B8%8B%E5%AE%89%E8%A3%85go-lang/c5524307595fd3df77801fe1f754ad09_MD5.png 2254w" width="2254"&gt;
下载后，双击进行安装。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="2配置环境变量"&gt;2.配置环境变量
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;$GOROOT:go lang 安装目录
$GOPATH:go lang 工作目录，有点像Eclipse那样子&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;下面开始配置
到终端输入以下命令:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;vim ~/.bash_profile &lt;span style="color:#75715e"&gt;# 打开环境变量配置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在最下面添加&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export GOPATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/Users/&lt;span style="color:#f92672"&gt;(&lt;/span&gt;用户名/路径&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#75715e"&gt;# 改成你喜欢的路径&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export GOROOT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/local/go &lt;span style="color:#75715e"&gt;# 默认安装都市这个路径&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;添加完毕后，退出vim
到终端输入以下命令:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;source ~/.bash_profile &lt;span style="color:#75715e"&gt;# 让环境变量配置生效&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;完成后，到$GOPATH的目录下，新建三个文件夹
&lt;img class="gallery-image" data-flex-basis="840px" data-flex-grow="350" height="108" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/macos%E4%B8%8B%E5%AE%89%E8%A3%85go-lang/9c30504296c8bfe2b1952c36402f5160_MD5.png" width="378"&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bin:存放编译后的可执行文件;
pkg:存放编译后的包文件;
src:存放项目源文件;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后，到终端输入以下命令验证时候安装成功:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go version
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="4301px" data-flex-grow="1792" height="26" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/macos%E4%B8%8B%E5%AE%89%E8%A3%85go-lang/854bb3f9c3fd732dba5099c105706f4b_MD5.png" width="466"&gt;
出现类似图中则为成功，若不成功，请检测一下你的环境变量配置。&lt;/p&gt;
&lt;h2 id="3ide"&gt;3.IDE
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;一.Sublime Text(个人比较喜欢)
安装好SublimeText后，再安装插件管理器，到插件管理器安装处，输入GoSublime，回车安装
安装完成后，还要安装一个语法提示插件:
到终端输入一下命令:&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go get github.com/nsf/gocode
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go install github.com/nsf/gocode
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;blockquote&gt;
 &lt;p&gt;二.LiteIDE
下载地址:&lt;a class="link" href="http://www.golangtc.com/download/liteide" target="_blank" rel="noopener"
 &gt;LiteIDE&lt;/a&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;img class="gallery-image" data-flex-basis="3977px" data-flex-grow="1657" height="136" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/macos%E4%B8%8B%E5%AE%89%E8%A3%85go-lang/f15901d34c1f17ab1c9c718c715c87c2_MD5.png" srcset="https://blog.skytoup.com/p/macos%E4%B8%8B%E5%AE%89%E8%A3%85go-lang/f15901d34c1f17ab1c9c718c715c87c2_MD5_hu_5e8cf5d1f299eed7.png 800w, https://blog.skytoup.com/p/macos%E4%B8%8B%E5%AE%89%E8%A3%85go-lang/f15901d34c1f17ab1c9c718c715c87c2_MD5_hu_f786c843f22b61b4.png 1600w, https://blog.skytoup.com/p/macos%E4%B8%8B%E5%AE%89%E8%A3%85go-lang/f15901d34c1f17ab1c9c718c715c87c2_MD5.png 2254w" width="2254"&gt;
下载其中一个即可
解压即可用&lt;/p&gt;

 &lt;/blockquote&gt;

 &lt;/blockquote&gt;

 &lt;blockquote&gt;
 &lt;p&gt;三.Wide
项目地址:&lt;a class="link" href="https://github.com/b3log/wide" target="_blank" rel="noopener"
 &gt;Wide项目&lt;/a&gt;
官网地址:[官网][wide]
下载后，使用go来运行，在浏览器打开指定的ip和端口即可使用(详情请参考[官网][wide])
[wide]:	https://wide.b3log.org/login	&amp;ldquo;wide&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="4学习go-lang"&gt;4.学习Go lang
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;官方教程:&lt;a class="link" href="http://tour.studygolang.com/welcome/1" target="_blank" rel="noopener"
 &gt;免翻墙&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Go语言中文网:&lt;a class="link" href="http://studygolang.com/" target="_blank" rel="noopener"
 &gt;Go语言中文网&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GoLang中国:&lt;a class="link" href="http://www.golangtc.com/" target="_blank" rel="noopener"
 &gt;GoLang中国&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>iOS metaio虚拟现实-位置 demo</title><link>https://blog.skytoup.com/p/ios-metaio%E8%99%9A%E6%8B%9F%E7%8E%B0%E5%AE%9E-%E4%BD%8D%E7%BD%AE-demo/</link><pubDate>Thu, 27 Aug 2015 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/ios-metaio%E8%99%9A%E6%8B%9F%E7%8E%B0%E5%AE%9E-%E4%BD%8D%E7%BD%AE-demo/</guid><description>&lt;h1 id="locationartest"&gt;LocationARTest
&lt;/h1&gt;&lt;h3 id="测试环境xcode-6ios-70真机以上"&gt;测试环境：Xcode 6，iOS 7.0(真机)以上。
&lt;/h3&gt;&lt;p&gt;基于Metaio的demo修改出来的，查看周边的美食&lt;/p&gt;
&lt;p&gt;github链接 : &lt;a class="link" href="https://github.com/skytoup/LocationARTest" target="_blank" rel="noopener"
 &gt;https://github.com/skytoup/LocationARTest&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="GIF" class="gallery-image" data-flex-basis="134px" data-flex-grow="56" height="635" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/ios-metaio%E8%99%9A%E6%8B%9F%E7%8E%B0%E5%AE%9E-%E4%BD%8D%E7%BD%AE-demo/1.gif" width="357"&gt;&lt;/p&gt;
&lt;h2 id="注意"&gt;注意
&lt;/h2&gt;&lt;p&gt;本demo不能直接运行&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;需要修改JHKey.h中的JH_ID(修改为你的聚合id，并到聚合数据网站申请数据)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 聚合数据账号注册：http://www.juhe.cn/
 数据申请：http://www.juhe.cn/docs/api/id/45
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;需要修改Info.plist中的MetaioLicenseString&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; MetaioLicense申请：http://metaio.com/
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;由于MetaioSDK.framework有300+M，github限制单文件100M，所以无法上传&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 请自行到Metaio官网下载http://metaio.com/
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="用到的其他工具"&gt;用到的其他工具
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://github.com/skytoup/JsonToModule" target="_blank" rel="noopener"
 &gt;JsonToModule&lt;/a&gt;:一个命令行工具，能把json文件转换成java或者objc的模型类&lt;/p&gt;
&lt;h3 id="用到的第三方库"&gt;用到的第三方库
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="http://metaio.com/" target="_blank" rel="noopener"
 &gt;metaioSDK.framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="http://www.juhe.cn/" target="_blank" rel="noopener"
 &gt;JuheApisSDK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>iOS价格日历</title><link>https://blog.skytoup.com/p/ios%E4%BB%B7%E6%A0%BC%E6%97%A5%E5%8E%86/</link><pubDate>Thu, 27 Aug 2015 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/ios%E4%BB%B7%E6%A0%BC%E6%97%A5%E5%8E%86/</guid><description>&lt;h1 id="skycalendarpriceview"&gt;SkyCalendarPriceView
&lt;/h1&gt;&lt;hr&gt;
&lt;h2 id="测试环境xcode-6ios-70以上"&gt;测试环境：Xcode 6，iOS 7.0以上。
&lt;/h2&gt;&lt;p&gt;github地址 : &lt;a class="link" href="https://github.com/skytoup/SkyCalendarPriceView" target="_blank" rel="noopener"
 &gt;https://github.com/skytoup/SkyCalendarPriceView&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="GIF" class="gallery-image" data-flex-basis="132px" data-flex-grow="55" height="498" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/ios%E4%BB%B7%E6%A0%BC%E6%97%A5%E5%8E%86/1.gif" width="275"&gt;&lt;/p&gt;
&lt;h2 id="简介"&gt;简介
&lt;/h2&gt;&lt;p&gt;一个可以自定义样式的价格日历&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高度封装，简单使用，传入对应的数据模型即可显示&lt;/li&gt;
&lt;li&gt;灵活度高，大部分view的样式可调整&lt;/li&gt;
&lt;li&gt;显示的文字可自定义处理，也可以自定义和系统处理一起使用&lt;/li&gt;
&lt;li&gt;可在Xib或StoryBoard中拖拽使用，也支持自动布局，也可以手写固定的Frame&lt;/li&gt;
&lt;li&gt;支持旋屏&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="使用方法"&gt;使用方法
&lt;/h2&gt;&lt;p&gt;把头文件 &lt;code&gt;SkyCalendarPriceView.h&lt;/code&gt; 导入项目。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;#import &amp;#34;SkyCalendarPriceView.h&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="基本使用"&gt;基本使用
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// 创建价格日历
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SkyCalendarPriceView &lt;span style="color:#f92672"&gt;*&lt;/span&gt;v &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [SkyCalendarPriceView calendarPriceView];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 创建数据模型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SkyCalendarPriceModel &lt;span style="color:#f92672"&gt;*&lt;/span&gt;model &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [SkyCalendarPriceModel calendarPriceModelWithYear:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2015&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt; withMonth:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt; withDay:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt; withPrice:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt; withCount:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SkyCalendarPriceModel &lt;span style="color:#f92672"&gt;*&lt;/span&gt;model2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [SkyCalendarPriceModel calendarPriceModelWithYear:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2015&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt; withMonth:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt; withDay:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;22&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt; withPrice:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt; withCount:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; SkyCalendarPriceModel &lt;span style="color:#f92672"&gt;*&lt;/span&gt;model3 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [SkyCalendarPriceModel calendarPriceModelWithYear:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2015&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt; withMonth:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt; withDay:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;24&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt; withPrice:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt; withCount:&lt;span style="color:#ae81ff"&gt;@(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;)&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 导入数据模型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _v.datas &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;@[&lt;/span&gt;model, model2, model3&lt;span style="color:#ae81ff"&gt;]&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 设置今天的时间，可不设置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; _v.today &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [NSDate date];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="定制样式"&gt;定制样式
&lt;/h3&gt;&lt;p&gt;详情请看&lt;a class="link" href="SkyCalendarPriceView/SkyCalendarPriceViewConfig.h" &gt;SkyCalendarPriceViewConfig.h&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="代码修改部分view样式"&gt;代码修改部分view样式
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// 可通过调用以下几个方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SkyCalendarHeader
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#f92672"&gt;+&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)SkyCalendarPriceViewInitHeaderViewOfYearMonthViewStyleWithBlock:(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;(&lt;span style="color:#f92672"&gt;^&lt;/span&gt;)(UIView &lt;span style="color:#f92672"&gt;*&lt;/span&gt;view))block
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#f92672"&gt;+&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)SkyCalendarPriceViewInitHeaderViewOfWeekLabelsStyleWithBlock:(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;(&lt;span style="color:#f92672"&gt;^&lt;/span&gt;)(NSArray &lt;span style="color:#f92672"&gt;*&lt;/span&gt;labels))block;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	SkyCalendarCell
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#f92672"&gt;+&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)SkyCalendarPriceViewInitCellStyleWithBlock:(&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;(&lt;span style="color:#f92672"&gt;^&lt;/span&gt;)(UICollectionViewCell &lt;span style="color:#f92672"&gt;*&lt;/span&gt;cell))block;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="自定义显示的数据样式"&gt;自定义显示的数据样式
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// 通过实现SkyCalendarPriceViewDelegate的方法进行显示自定义的数据样式
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#f92672"&gt;-&lt;/span&gt; (NSDictionary&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)skyCalendarPriceView:(SkyCalendarPriceView&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)cview cellDataStringDictionaryWithIndexPath:(NSIndexPath&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)indexPath withYear:(NSString&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)year withMonth:(NSString&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)month withDay:(NSString&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)day withPrice:(NSString&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)price withCount:(NSString&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)count withIsToday:(&lt;span style="color:#66d9ef"&gt;BOOL&lt;/span&gt;)isToady;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#f92672"&gt;-&lt;/span&gt; (NSString&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)skyCalendarPriceView:(SkyCalendarPriceView&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)cview cellDayStringWithYear:(NSString&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)year withMonth:(NSString&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)month withDay:(NSString&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)day withIsToday:(&lt;span style="color:#66d9ef"&gt;BOOL&lt;/span&gt;)isToday;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#f92672"&gt;-&lt;/span&gt; (NSString&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)skyCalendarPriceView:(SkyCalendarPriceView &lt;span style="color:#f92672"&gt;*&lt;/span&gt;)cview headerLabelStringWithYear:(NSString&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)year withMonth:(NSString&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)month;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="若不需要header停留在顶部"&gt;若不需要header停留在顶部
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// 更换默认布局（注:Xib或StoryBoard中，需手动在代码或面板里设置Layout，设置的Layout需要为UICollectionViewFlowLayout的子类）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	skyCalendarPriceView.collectionViewLayout &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [UICollectionViewFlowLayout new];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="监听选中取消选中日期"&gt;监听选中/取消选中日期
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// 通过实现SkyCalendarPriceViewDelegate的方法进行监听
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#f92672"&gt;-&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;BOOL&lt;/span&gt;)skyCalendarPriceView:(SkyCalendarPriceView&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)cview shouldSelectIndexWithPriceModel:(SkyCalendarPriceModel&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)model;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#f92672"&gt;-&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt;)skyCalendarPriceView:(SkyCalendarPriceView&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)cview didUnselectIndexWithPriceModel:(SkyCalendarPriceModel&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)model;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>iOS UIView自定义四个边角的圆角</title><link>https://blog.skytoup.com/p/ios-uiview%E8%87%AA%E5%AE%9A%E4%B9%89%E5%9B%9B%E4%B8%AA%E8%BE%B9%E8%A7%92%E7%9A%84%E5%9C%86%E8%A7%92/</link><pubDate>Wed, 12 Aug 2015 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/ios-uiview%E8%87%AA%E5%AE%9A%E4%B9%89%E5%9B%9B%E4%B8%AA%E8%BE%B9%E8%A7%92%E7%9A%84%E5%9C%86%E8%A7%92/</guid><description>&lt;p&gt;UIView背景色的四个边角自定义成圆角&lt;/p&gt;
&lt;p&gt;比较简单，没什么好介绍的&lt;/p&gt;
&lt;p&gt;GitHub链接：&lt;a class="link" href="https://github.com/skytoup/SkyRadiusView" target="_blank" rel="noopener"
 &gt;https://github.com/skytoup/SkyRadiusView&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;测试环境：Xcode 6，iOS 7.0以上&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;input disabled="" type="checkbox"&gt; &lt;a class="link" href="https://img-blog.csdn.net/20150812072718059https://img-blog.csdn.net/20150812072718059" target="_blank" rel="noopener"
 &gt;https://img-blog.csdn.net/20150812072718059https://img-blog.csdn.net/20150812072718059&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;pod &amp;lsquo;SkyRaduisView&amp;rsquo;, &amp;lsquo;~&amp;gt; 1.0.0&amp;rsquo;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="gif" class="gallery-image" data-flex-basis="458px" data-flex-grow="190" height="422" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/ios-uiview%E8%87%AA%E5%AE%9A%E4%B9%89%E5%9B%9B%E4%B8%AA%E8%BE%B9%E8%A7%92%E7%9A%84%E5%9C%86%E8%A7%92/20150812072718059.gif" srcset="https://blog.skytoup.com/p/ios-uiview%E8%87%AA%E5%AE%9A%E4%B9%89%E5%9B%9B%E4%B8%AA%E8%BE%B9%E8%A7%92%E7%9A%84%E5%9C%86%E8%A7%92/20150812072718059_hu_8009585d3280a197.gif 800w, https://blog.skytoup.com/p/ios-uiview%E8%87%AA%E5%AE%9A%E4%B9%89%E5%9B%9B%E4%B8%AA%E8%BE%B9%E8%A7%92%E7%9A%84%E5%9C%86%E8%A7%92/20150812072718059.gif 806w" width="806"&gt;&lt;/p&gt;</description></item><item><title>把json转成java、objc的module的小工具</title><link>https://blog.skytoup.com/p/%E6%8A%8Ajson%E8%BD%AC%E6%88%90javaobjc%E7%9A%84module%E7%9A%84%E5%B0%8F%E5%B7%A5%E5%85%B7/</link><pubDate>Thu, 06 Aug 2015 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/%E6%8A%8Ajson%E8%BD%AC%E6%88%90javaobjc%E7%9A%84module%E7%9A%84%E5%B0%8F%E5%B7%A5%E5%85%B7/</guid><description>&lt;h3 id="简介"&gt;简介
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;一个把json文件，转换为java、objcetive-c的module文件。
暂不支持一个array的下一级，还是array
简单方便地处理后台返回的json数据，不必要一个一个字段复制到module类上。
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="github"&gt;github
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;[json2module](https://github.com/skytoup/JsonToModule)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="用到的第三方开源库"&gt;用到的第三方开源库
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;cJSON c语言的json解析库
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="基本的实现逻辑"&gt;基本的实现逻辑
&lt;/h3&gt;&lt;p&gt;&lt;img alt="实现逻辑" class="gallery-image" data-flex-basis="102px" data-flex-grow="42" height="700" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/%E6%8A%8Ajson%E8%BD%AC%E6%88%90javaobjc%E7%9A%84module%E7%9A%84%E5%B0%8F%E5%B7%A5%E5%85%B7/20150806202839772.png" width="300"&gt;&lt;/p&gt;
&lt;h3 id="编译"&gt;编译
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;命令行进入到项目根目录后
make

测试:
	make test
	测试生成的文件在项目目录下的out_file里面
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="使用说明english不是很好"&gt;使用说明(English不是很好):
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;json2moudle &amp;lt;json file path&amp;gt; [-n] [-o] [-p] [-h] [--java] [--objc]

option:
-n &amp;lt;module name&amp;gt; 	 	default is json file name
-o &amp;lt;out path&amp;gt; 		 	default is run path
-p &amp;lt;java pack name&amp;gt; 	default is &amp;quot;&amp;quot;
-h 			 			help
--java 			 		out java module file
--objc 			 		out objective-c module file

if not have --java or --objective-c, default is java
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="使用事例"&gt;使用事例：
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;json2moudle t.json
json2moudle t.json -n test2 -o ~/Desktop/test -p test.com.hehe
json2moudle t.json -n test2 -o ~/Desktop/test
json2moudle t.json -n test2 -o ~/Desktop/test -p test.com.hehe --objc --java
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>记录一下iOS的几个UIView的方法</title><link>https://blog.skytoup.com/p/%E8%AE%B0%E5%BD%95%E4%B8%80%E4%B8%8Bios%E7%9A%84%E5%87%A0%E4%B8%AAuiview%E7%9A%84%E6%96%B9%E6%B3%95/</link><pubDate>Tue, 04 Aug 2015 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/%E8%AE%B0%E5%BD%95%E4%B8%80%E4%B8%8Bios%E7%9A%84%E5%87%A0%E4%B8%AAuiview%E7%9A%84%E6%96%B9%E6%B3%95/</guid><description>&lt;p&gt;在用自动布局的时候，老是忘记更新Constraint使用哪个方法，特意去查了一下资料，做了一下笔记。
如果出现错误的地方，希望大家指出，谢谢。&lt;/p&gt;
&lt;h3 id="uiview"&gt;UIView:
&lt;/h3&gt;&lt;p&gt;`// 重写此方法，当约束更新时，可更新你的特殊约束，别忘记调用super方法&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(void)updateConstraints;`&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;`// 调用这个方法，会触发update Constraints的操作，即更新约束。在needsUpdateConstraints返回YES时，才能成功触发update Constraints的操作。我们不应该重写这个方法。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(void)updateConstraintsIfNeeded;`&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;`// 会调用drawRect方法&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(void)setNeedsDisplay;`&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;`// 会默认调用layoutSubViews&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(void)setNeedsLayout;`&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;`// 当一个自定义的View某一个属性的改变可能影响到界面布局，我们应该调用这个方法来告诉布局系统在未来某个时刻需要更新。系统会调用updateConstraints去更新布局。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(void)setNeedsUpdateConstraints;`&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;`// 布局系统使用这个返回值来确定是否调用updateConstraints&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(void)needsUpdateConstraints;`&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;// 如果有刷新的标记(应该是指调用过-(void) setNeedsLayout这个方法吧)，立即调用layoutSubviews进行布局 -(void) layoutIfNeeded;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;`// 自动调用layoutIfNeeded，当使用基于约束的布局基本实现适用于基于约束的布局，否则什么也不做。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(void)layoutSubviews;`&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>iOS一个带动画的等待指示器</title><link>https://blog.skytoup.com/p/ios%E4%B8%80%E4%B8%AA%E5%B8%A6%E5%8A%A8%E7%94%BB%E7%9A%84%E7%AD%89%E5%BE%85%E6%8C%87%E7%A4%BA%E5%99%A8/</link><pubDate>Mon, 06 Jul 2015 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/ios%E4%B8%80%E4%B8%AA%E5%B8%A6%E5%8A%A8%E7%94%BB%E7%9A%84%E7%AD%89%E5%BE%85%E6%8C%87%E7%A4%BA%E5%99%A8/</guid><description>&lt;h1 id="skywaitingviewgithub链接"&gt;SkyWaitingView（&lt;a class="link" href="https://github.com/skytoup/SkyWaitingView" target="_blank" rel="noopener"
 &gt;github链接&lt;/a&gt;）
&lt;/h1&gt;&lt;hr&gt;
&lt;h2 id="测试环境xcode-6ios-70以上"&gt;测试环境：Xcode 6，iOS 7.0以上。
&lt;/h2&gt;&lt;p&gt;&lt;img alt="GIF" class="gallery-image" data-flex-basis="159px" data-flex-grow="66" height="356" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/ios%E4%B8%80%E4%B8%AA%E5%B8%A6%E5%8A%A8%E7%94%BB%E7%9A%84%E7%AD%89%E5%BE%85%E6%8C%87%E7%A4%BA%E5%99%A8/1.gif" width="236"&gt;&lt;/p&gt;
&lt;h2 id="简介"&gt;简介
&lt;/h2&gt;&lt;p&gt;一个简单的等待指示器&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可自定义圆弧粗细、颜色、旋转速率&lt;/li&gt;
&lt;li&gt;可自定义标签显示&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="使用方法"&gt;使用方法
&lt;/h2&gt;&lt;p&gt;把头文件 &lt;code&gt;SkyWaitingView.h&lt;/code&gt; 导入项目，然后设置各属性，具体使用方法请参考示例项目。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-objc" data-lang="objc"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SkyCircleWatingView &lt;span style="color:#f92672"&gt;*&lt;/span&gt;v &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [SkyCircleWatingView new];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;v.frame &lt;span style="color:#f92672"&gt;=&lt;/span&gt; CGRectMake(&lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;, baseY, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[v sizeToFit];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[self.view addSubview:v];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;v.rate &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1.f&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[v start];
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="联系方式"&gt;联系方式
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;QQ：875766917，请备注&lt;/li&gt;
&lt;li&gt;QQMail：875766917@qq.com&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>数据结构-链表</title><link>https://blog.skytoup.com/p/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84-%E9%93%BE%E8%A1%A8/</link><pubDate>Sat, 20 Jun 2015 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84-%E9%93%BE%E8%A1%A8/</guid><description>&lt;h1 id="1链表基础"&gt;1.链表基础
&lt;/h1&gt;&lt;p&gt;链表是一段非连续物理地址的存储结构，通过节点的成员变量，存储其它单元格的地址，构成一条链，称为链表。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;链表的结构如下图（画得不是很好）：&lt;/code&gt;
&lt;img alt="链表示意图|96" class="gallery-image" data-flex-basis="75px" data-flex-grow="31" height="1272" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84-%E9%93%BE%E8%A1%A8/link_diagram.png" width="402"&gt;&lt;/p&gt;
&lt;p&gt;这是一个双向链表，可以通过每一个节点，找到它的上一个节点，或者下一个节点。
如果为单向链表，则节点没有pre这个成员变量。&lt;/p&gt;
&lt;p&gt;节点的结构体定义：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; link_node {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; link_node &lt;span style="color:#f92672"&gt;*&lt;/span&gt;next; &lt;span style="color:#75715e"&gt;// 前一个节点
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; link_node &lt;span style="color:#f92672"&gt;*&lt;/span&gt;pre; &lt;span style="color:#75715e"&gt;// 后一个节点
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;val; &lt;span style="color:#75715e"&gt;// 节点值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一般来说，都会有一个存储链表头节点的结构体，如上图的第一个圆角矩形。&lt;/p&gt;
&lt;p&gt;可以新建一个结构体来存储链表首节点，或者新建一个不存储数值的节点来存储首节点。&lt;/p&gt;
&lt;h1 id="2优缺点"&gt;2.优缺点
&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;动态创建节点来存储数据&lt;/li&gt;
&lt;li&gt;插入节点快&lt;/li&gt;
&lt;li&gt;读取指定位置节点慢&lt;/li&gt;
&lt;li&gt;结构较简单&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="3扩展"&gt;3.扩展
&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;栈&lt;/li&gt;
&lt;li&gt;循环链表&lt;/li&gt;
&lt;li&gt;队列（双向队列、单向队列）&lt;/li&gt;
&lt;li&gt;树、图、链地址法的哈希表 结构的基础&lt;/li&gt;
&lt;li&gt;。。。。。。（还有很多吧）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="栈" class="gallery-image" data-flex-basis="197px" data-flex-grow="82" height="562" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84-%E9%93%BE%E8%A1%A8/stack.png" width="462"&gt;&lt;/p&gt;</description></item><item><title>iOS三级联想菜单（SkyAssociationMenuView）</title><link>https://blog.skytoup.com/p/ios%E4%B8%89%E7%BA%A7%E8%81%94%E6%83%B3%E8%8F%9C%E5%8D%95skyassociationmenuview/</link><pubDate>Fri, 19 Jun 2015 00:00:00 +0000</pubDate><guid>https://blog.skytoup.com/p/ios%E4%B8%89%E7%BA%A7%E8%81%94%E6%83%B3%E8%8F%9C%E5%8D%95skyassociationmenuview/</guid><description>&lt;h1 id="三级联想菜单skyassociationmenuview"&gt;三级联想菜单（SkyAssociationMenuView）
&lt;/h1&gt;&lt;h3 id="测试环境xcode-6ios-70以上"&gt;测试环境：Xcode 6，iOS 7.0以上。
&lt;/h3&gt;&lt;p&gt;以前做一个项目准备用来当做地区选择用的，后来没用上。。。。。&lt;/p&gt;
&lt;p&gt;只是粗略的实现了一下，写得不是很好，望大家见谅。。。。。&lt;/p&gt;
&lt;p&gt;github：&lt;a class="link" href="https://github.com/skytoup/SkyAssociationMenuView" target="_blank" rel="noopener"
 &gt;https://github.com/skytoup/SkyAssociationMenuView&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;效果图：&lt;/p&gt;
&lt;p&gt;&lt;img alt="GIF" class="gallery-image" data-flex-basis="133px" data-flex-grow="55" height="497" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.skytoup.com/p/ios%E4%B8%89%E7%BA%A7%E8%81%94%E6%83%B3%E8%8F%9C%E5%8D%95skyassociationmenuview/1.gif" width="276"&gt;&lt;/p&gt;</description></item></channel></rss>