<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Library on Chen</title><link>https://hechen.github.io/zh-cn/tags/library/</link><description>Recent content in Library on Chen</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Thu, 04 Jul 2019 01:19:10 +0800</lastBuildDate><atom:link href="https://hechen.github.io/zh-cn/tags/library/index.xml" rel="self" type="application/rss+xml"/><item><title>LetsMove 中的几个点</title><link>https://hechen.github.io/zh-cn/post/letsmove/</link><pubDate>Thu, 04 Jul 2019 01:19:10 +0800</pubDate><guid>https://hechen.github.io/zh-cn/post/letsmove/</guid><description>&lt;p&gt;当我们从网络上下载某个 mac app 之后，一般都会默认在 Downloads 目录里，但是某一些 App 是需要放置到 Application 目录才行，最常见的就是自更新功能是受到当前所处目录的限制的，这时候很多下载到本地的 .app 文件打开之后都会弹出提示框，让用户选择是否移动到 Applications 目录，LetsMove 就是大部分 mac app 参考或者集成的开源库，封装了这套逻辑。&lt;/p&gt;
&lt;p&gt;&lt;img alt="LetsMove" loading="lazy" src="https://i.imgur.com/99z1BQf.png"&gt;&lt;/p&gt;
&lt;p&gt;这个库已经好多年了，最近的一次 Commit 是 2017年，其中有几个点可以学习借鉴。&lt;/p&gt;
&lt;h3 id="大致思路"&gt;大致思路&lt;/h3&gt;
&lt;p&gt;虽然叫 Move，实际上是先行 Copy 一份当前的 App Bundle 到 Application 目录，然后杀掉自己并删除源目录的 App 文件。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Move to Applications Folder 确认之后&lt;/li&gt;
&lt;li&gt;复制当前 App 文件到 /Applications 目录中&lt;/li&gt;
&lt;li&gt;删除当前已经打开 App （Mac 上是可行的，不同于 Windows，不存在占用文件句柄的情况）&lt;/li&gt;
&lt;li&gt;执行子进程执行重启过程，具体后文会讲。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="权限获取提权"&gt;权限获取（提权）&lt;/h3&gt;
&lt;p&gt;检查文件路径是否可以写入的方法是 NSFileManager 的 isWritableFileAtPath ，如果返回 false，LetsMove 会主动进行权限获取。&lt;/p&gt;
&lt;p&gt;获取权限所使用的接口是 AuthorizationExecuteWithPrivileges，该接口实际在 OSX 10.7 Lion 之后就已经标记废弃了，但是一直到目前的 macOS 10.14 还一直可以使用。&lt;/p&gt;
&lt;p&gt;而作者为了避免苹果直接移除该代码导致提权接口不可用，使用了动态查找方法的形式，利用 dlsym 查找方法指针来获取，从而避免如果完全移除该方法导致功能不稳定的情况发生。&lt;/p&gt;</description></item><item><title>XPC Services</title><link>https://hechen.github.io/zh-cn/post/xpcservice/</link><pubDate>Thu, 04 Jul 2019 01:01:10 +0800</pubDate><guid>https://hechen.github.io/zh-cn/post/xpcservice/</guid><description>&lt;h2 id="关于-xpc"&gt;关于 XPC&lt;/h2&gt;
&lt;p&gt;因为最近在做的工作涉及到这一块，就大致的记录一下，针对 XPC 技术也做个总结。&lt;/p&gt;
&lt;p&gt;XPC 是 macOS 上一种进程间通信的技术统称，其使得我们可以将 Mac 应用的功能模块拆分成不同的多进程模式，关于进程之间的通信也被系统封装完整了，你只需要按照既定的模式做即可。其带来的最大的好处是&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;提高 App 自身的稳定性&lt;/li&gt;
&lt;li&gt;进行权限隔离&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;拿我目前在做的工作来讲，确实有针对以上这两点的需求。上层业务通过执行脚本命令获取执行结果，执行脚本命令使用的就是 NSTask，大概结构如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="shared-42f9e747-a47b-46fd-b445-0c7615b41020" loading="lazy" src="https://i.imgur.com/8glAV2u.png"&gt;&lt;/p&gt;
&lt;p&gt;对于执行 NSTask 的这层命令行执行模块来讲，拆分到独立的进程中使得安全性得以提高，即使 XPC 进程挂掉，一般情况下再次向 XPC 通信，系统会自行恢复启用新的 XPC 进程，而主应用无感知。&lt;/p&gt;
&lt;h2 id="xpc-架构"&gt;XPC 架构&lt;/h2&gt;
&lt;p&gt;在 Apple 官方文档中有如下图，很清楚的展示了整个 NSXPC 的架构。&lt;/p&gt;
&lt;p&gt;主应用和 XPC Service 之间是通过 NSXPCConnection 对象保持通信的，其通信接口由 Protocol 定义，然后暴露给外界一个符合了该协议的对象。&lt;/p&gt;
&lt;p&gt;所有的 XPC Service 本身是由系统级别程序 launchd 来管理和维护的。&lt;/p&gt;
&lt;p&gt;&lt;img alt="NSXPC_intro_2x-337fb6a3-4df5-47b3-a322-e52c48905753" loading="lazy" src="https://i.imgur.com/OdvfZk4.png"&gt;&lt;/p&gt;
&lt;h2 id="开发过程"&gt;开发过程&lt;/h2&gt;
&lt;p&gt;整体上主应用和 XPC 通信是标准的 Client-Server 模式。客户端询问 Server 端数据，Server 端应答即可。这之间的数据序列化完全交由系统管理。&lt;/p&gt;
&lt;h3 id="具体步骤"&gt;具体步骤&lt;/h3&gt;
&lt;h4 id="新建-xpc-service-的-target"&gt;新建 XPC Service 的 Target&lt;/h4&gt;
&lt;p&gt;&lt;img alt="Add New XPC Service Target" loading="lazy" src="https://i.imgur.com/BNFRaG7.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Input Target Info" loading="lazy" src="https://i.imgur.com/AyEq9Iv.png"&gt;&lt;/p&gt;</description></item><item><title>Codable &amp;&amp; Tuple</title><link>https://hechen.github.io/zh-cn/post/tuple-codable/</link><pubDate>Mon, 10 Jun 2019 23:50:54 +0800</pubDate><guid>https://hechen.github.io/zh-cn/post/tuple-codable/</guid><description>&lt;p&gt;While learning Swift, I keep finding interesting things. Codable is one of them.&lt;/p&gt;
&lt;p&gt;Today, I defined a model with a tuple type, then Xcode gave me an error. The code might look like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Codable Person" loading="lazy" src="https://i.imgur.com/c67KrA8.png"&gt;&lt;/p&gt;
&lt;p&gt;You may want Xcode to automatically complete all the codable stuff. However, life is hard. Code like this cannot even be compiled. Xcode will tell you that it cannot synthesize Codable for Person because of FullName.&lt;/p&gt;</description></item><item><title>How to generate a NSViewController without a Nib?</title><link>https://hechen.github.io/zh-cn/post/create-nsviewcontroller-without-nib/</link><pubDate>Mon, 03 Jun 2019 20:55:54 +0800</pubDate><guid>https://hechen.github.io/zh-cn/post/create-nsviewcontroller-without-nib/</guid><description>&lt;p&gt;Recently, I created all the ViewControllers through the storyboard or the Nib (for views). Today, when I created a demo project without any Nib file, the ViewController did not show as I expected.&lt;/p&gt;
&lt;p&gt;WTF, Can you believe that? I cannot even create a ViewController now.&lt;/p&gt;
&lt;p&gt;There exist some differences between iOS and macOS.&lt;/p&gt;
&lt;h2 id="ios"&gt;iOS&lt;/h2&gt;
&lt;p&gt;In the previous development on the iOS platform, creating a ViewController — specifically a UIViewController instance — is dead simple, as below.&lt;/p&gt;</description></item><item><title>一道 Swift Quiz</title><link>https://hechen.github.io/zh-cn/post/a-swift-quiz/</link><pubDate>Tue, 14 May 2019 16:01:54 +0800</pubDate><guid>https://hechen.github.io/zh-cn/post/a-swift-quiz/</guid><description>&lt;p&gt;这两天在 &lt;a href="https://twitter.com/krzyzanowskim/status/1127875626579288064?s=12"&gt;Twitter&lt;/a&gt; 上看到一道题目，主要是考察 overload 和 type(of:) 的知识点，本文仅做记录，关于 MetaType 会单独写一篇文章来总结。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// Swift Quiz
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;class View {}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;class A: View {}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;class B: View {}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;func add(_ v: View) { print(type(of: v)) }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;func add(_ v: A) { print(type(of: v)) }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;func add(_ v: B) { print(type(of: v)) }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;func build() -&amp;gt; View { return B() }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;add(build())
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// What is the output?
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &amp;#34;View&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &amp;#34;A&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &amp;#34;B&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;答案的分布说明，大家对这个输出结果还是有一定的疑惑🤔&lt;/p&gt;</description></item><item><title>关于 Library 和 Framework</title><link>https://hechen.github.io/zh-cn/post/library_framework/</link><pubDate>Fri, 26 Apr 2019 00:35:30 +0800</pubDate><guid>https://hechen.github.io/zh-cn/post/library_framework/</guid><description>&lt;p&gt;Library 和 Framework 的概念大家应该脑海里都有一些，本文旨在讲述下基本概念，没有对每个字节都了如指掌。关于基本的编译过程在 &lt;a href="https://hechen.github.io/post/xcode-build-system/"&gt;Build Process&lt;/a&gt; 一文中也大概讲述了一些。&lt;/p&gt;
&lt;p&gt;在链接 Library 以及 Framework 之前，我们需要先了解一下 Mach—O。&lt;/p&gt;
&lt;p&gt;提到 Mach-O ，需要明确下 object file（目标文件）的概念，其实质上是指那些由源代码编译之后生成的，还未进行链接的中间文件（比如 Linux 下的 .o 以及 Windows 下的 .obj），它和可执行文件的内容和结构很相似，所以一般上会跟可执行文件格式采用一样的格式存储。&lt;/p&gt;
&lt;p&gt;那在 Unix 系统上的 COFF 是当时发明的在 Unix 表示一个目标文件的存取格式，后来 Linux 基于 COFF 发明了 ELF，而 Windows 基于 COFF 发明了 PE 格式。广义上来说，目标文件与可执行文件几乎一样。在 Linux 下统称为 ELF 文件，Windows 上统称为 PE-COFF 文件，而在 iOS/macOS 上我们的目标文件就是 Mach-O 格式，其在目标文件的大体组成上和其他两种很相似。而 Mach-O 的全称就是 Mach Object 的缩写。&lt;/p&gt;
&lt;p&gt;&lt;img alt="目标文件" loading="lazy" src="https://i.imgur.com/CUrWruq.png"&gt;&lt;/p&gt;
&lt;p&gt;我们以 Linux 上 ELF 结构的一张图来大概说明一下情况，不同的源文件通过分类，将代码和数据，以及变量放入不同的职责段，代码段 _TEXT，数据段 _DATA 等。&lt;/p&gt;
&lt;p&gt;&lt;img alt="ELF" loading="lazy" src="https://i.imgur.com/ozMscrW.jpg"&gt;&lt;/p&gt;
&lt;p&gt;而 Mach-O 文件格式如下图（源自于 Apple 文档）, 和 ELF 格式类似，其也是将不同职责的代码和数据放置于不同的 Section 段，然后再集中成一个一个的 Segment，而 Load Commands 是用来控制每一个 Segment 是如何被加载的，数据是从哪里取的，等等。&lt;/p&gt;</description></item></channel></rss>