詳解蘋果提供的UTI(統一類型標識符)

前言

最近項目中有個需求,在iOS設備上使用iOS系統提供的內容分享功能,從第三方App應用直接分享實體內容到我們的應用中。其大概的原理是這樣的,首先為我們的iOS應用注冊可以打開document types(文檔類型),然后在第三方應用中,如果它們使用了iOS提供的分享功能,那么就會看到我們的應用程序,點擊進行分享。

而關于需求的設計和實現的具體思路,我會在下一篇博客中詳細講解。這篇文章是來講一下在iOS系統中為了更好的進行類型標識,而提供的一套共用的規范,也就是標題中提到的“Uniform Type Identifier(UTI)”,我把它翻譯成“統一類型標識符”,下面統一簡稱為“UTI”。

官方教程

網上關于UTI的使用教程少之又少,所以我只是參考了蘋果官方文檔提供的講解,這篇博客權當是我對于官方文檔的一個理解吧!!自認為很重要的部分,我會貼出來官方文檔原文,以便于大家學習理解,不至于被我的歪詞所誤導,同時也推薦大家從開發者中心上搜一些文檔來看,這里推薦幾篇:
1.Cocoa Core Competencies -- Uniform Type Identifier?
這篇文檔提供了一個視圖來說明UTI是什么,怎么工作和被誰使用,是個非常好的新手指南。
2.Uniform Type Identifier介紹和使用?
這篇文檔詳細得描述了UTI的基礎概念和屬性,還有它們的使用方法,內容非常豐富,本文主要參考的就是這篇
3.System-Declared Uniform Type Identifiers?
這篇文檔提供了在OS X系統中定義的一個UTI的列表,我們可以查看每一種官方提供的UTI的定義和涵義。
4.UTType Reference?
這篇文檔提供了對UTI字符串直接操作的函數方法
5.一步一步為iOS應用添加自定義的document type和新的UTI?
顧名思義,這篇文檔,講解的是如何在iOS應用中導入新的UTI和添加自定義的document type。

為什么會有UTI

為什么會有UTI,打個比方,它就像是如今世界各國作為官方語言統講得英文。為什么這么比喻呢,因為中國人講母語漢語,法國人講母語法語,但是如果一個中國人到了法國,而又不懂法語,碰到的法國人不懂漢語,那么他們如何交流溝通呢,這就是英文的用武之地了。而相對而言,蘋果操作系統相當于整個世界,各個不同的程序或者服務相當于各個國家,倆個不同的程序想要互通交流,就比如互相發送文件,可是一個使用文件擴展名,一個使用MIME類型,倆者的數據類型不同,無法解析,都互相不認識,那么怎么交流溝通呢?在這樣的情景下,UTI就有了用武之地啦,它就充當的是現實世界的英文這個角色。

UTI概念

Uniform type identifiers(UTIs)提供了在整個系統里面標識數據的一個統一的方式,比如documents(文檔)、pasteboard data(剪貼板數據)和bundles(包)。

而具體到UTI的定義,官方文檔是這么說的:“A uniform type identifier is a string that uniquely identifies a class of entities considered to have a ‘type’.”。其大概意思是說,一個統一類型標識符是一個唯一標識一種擁有"類型"屬性實體的字符串。而且,針對這個“type”,官方文檔還給我們提出了例子解釋,對于一個文件或者是字節流來說,“type”指的的數據類型;而對于packages和bundles來說,“type”指的就是它們內部的目錄層級結構。

UTI用途

大多數情況下,一個UTI提供的是系統中所有程序和服務都能夠識別并且依賴的一個唯一的標識,這么講可能有些太抽象,我們使用一下官方文檔中給出的例子,比如一個JPEG類型的圖片文件,在不同的環境下,可以有下面幾種不同的標識方法:

  1. ‘JPEG’, OSType表示,
  1. '.jpg', 文件擴展名
  2. '.jpeg', 文件擴展名
  3. 'image/jpeg', MIME(多用途互聯網郵件擴展類型)中的一種類型

而UTI則是用‘public.jpeg’這個字符串標識,完全代替了這些不一致的標簽,這個字符串和其他任何一個舊標簽都是完全兼容的,而且他們之間可以相互轉換。由于UTI可以標識任何類型的實體,所以他們相對于舊標簽來說靈活性更強了;使用UTI我們可以表示下面這些實體:

  • Pasteboard data
  • Folders (directories)
  • Bundles
  • Frameworks
  • Streaming data
  • Aliases and symbolic links

用法

1. 簡介

Apple給我們提供了在iOS和Mac應用中通用的UTI字符串集合,比如,'public.data'、'public.item'、'public.image'等,這些我們都可以在官方文檔中進行查閱他們的涵義。除此之外,我們也可以在應用程序中自定義自己的UTI字符串,比如我們可以定義一個標識特殊文檔格式的UTI字符串叫'cc.icoc.shaobozheng',如果其他的應用程序想要支持我們這種格式的文檔,他們就可以用'cc.icoc.shaobozheng'來標識我們的文檔。

2. 字符集

看到我們上邊的舉例了,那么我們來說一下定義UTI字符串時所用到的字符集。通常一個UTI字符串是一個包含ASCII字符的Unicode字符串,同時也可以加入羅馬字母和阿拉伯數字,如(A-Z),(a-z),(0-9)還有點號(".")和連接符("-")。而任何包含非法字符的字符串,如包含下劃線'_',都無法作為UTI來標識內容,而且Apple不會有任何錯誤反饋。

3. 語法

就像我上面的例子一樣,UTI的定義和我們開發iOS程序時填寫organization時一樣,采取的是反域名規則。如下面這幾種:

  • com.apple.quicktime-movie
  • com.mycompany.myapp.myspecialfiletype
  • public.html
  • com.apple.pict
  • public.jpeg

而UTI中的域名,如‘com’、‘public’這些,僅僅是用來表示這個UTI字符串在域名層級中的位置,它不會影響任何相似類型的分組。比如,‘public’域名就是大部分應用程序用來標識標準類型的,而目前僅僅只有Apple可以創建‘public’域名的UTI。

另外,我們可能會碰到的是一種‘dyn’域名,是動態域名,意思就是我們使用中,不會指定這種類型的UTI為某一個字符串,然后系統運行過程中,會自動識別幫我們處理。針對這種動態標識,我們是看不到的,但是我們可以通過UTI字符串的操作方式轉換成我們的常用類型,比如OSType,MIME類型等。

官方文檔中,對動態標識有個比喻:“You can think of a dynamic identifier as a UTI-compatible wrapper around an otherwise unknown filename extension, MIME type, OSType, and so on”,大概意思就是我們可以把這種動態標識當做是針對普通類型進行了重寫包裝的,而且是兼容UTI的一種標識。

最后一種就是可以自定義的域名,代表性的就是‘com’域名,Apple也給我們提供了一些他們定義的'com'域名的UTI。

順應性

UTI相對于其他那些舊標簽的一個關鍵優勢就是在于,它可以在一個順應結構中聲明。而用我們面向對象的方式說,UTI就是可繼承的,而且是多繼承方式。先上圖:


UTI繼承結構
UTI繼承結構

如上圖所示,‘public.html’這個UTI就是繼承于‘public.text’這個UTI,因為‘public.html’標識的是HTML文本格式,也屬于是文本格式的一種,而文本、圖片等等這些內容又都屬于是數據的一種,所以他們繼承于'public.data'這個UTI。

上面這個UTI繼承結構圖,指的是UTI中的內容形式的繼承結構,此外,原則上來說,指定UTI層次的時候,即可以指定它的功能結構,也可以指定它的物理結構,上圖是就是一個內容形式的功能結構圖.物理結構指的就是這個UTI的物理實質,比如它標識一個目錄,一個文件等,而功能結構指的就是這個UTI的用圖,比如同樣是文件,它標識的可以是圖片、視頻等等。 而官方文檔也給出了一般指定UTI層次結構的規則:

1.一個UTI在物理層次上需要繼承‘public.item’
2.一個UTI在功能層次需要繼承非'public.item'之外的UTI。

然而,指定UTI的功能層次并不是強制的,但是這樣做是考慮到可以更好地將UTI集成到系統一些特性中,就比如Spotlight應用,就可以把我們指定的功能性UTI和命名屬性聯系起來。下面是一個UTI功能順應結構和物理順應結構圖:


UTI功能結構和物理結構
UTI功能結構和物理結構

這個順應性使得我們的UTI在決定類型上擁有更高的靈活性,不僅避免了大量的條件判斷的使用,而且還可以關聯你想不到的一些類型。

使用UTI

1. 應用場景

在Mac OS中我們開發應用時我們可以經常使用到UTI,但是在開發iOS應用程序時,我們應用到UTI的場景不是很多,這也是現在網上教程偏少得原因。而在iOS開發中,一般我們使用UTI來標識剪貼板的類型。而在具體使用到Apple給我們提供的UTI字符串的時候,我們必須使用在UTCoreTypes.h文件中定義的常量來代替直接使用字符串。關于UIPasteboard的詳細使用,大家可以去這篇博客中詳細學習一下:精通UIPasteboard粘貼板

2. 操作方法

現在我們來看一下蘋果提供的一些直接操作UTI的函數方法,簡單列舉幾個。我們可以在MobileCoreServices這個framework中的UIType.h文件中找到,我們也可以仔細的看一下這個framework中的其他文件,都是對UTI的一些定義和聲明。

1.UITypeEqual
判斷倆個UTI是否完全一樣,后者是一個動態標簽說明是否是另外一個UTI標簽說明的子集。
2.UITypeConformsTo
判斷倆個標簽的順應性,用面向對象的角度理解,就是判斷是否是子類。
3.UTTypeCreatePreferredIdentifierForTag
通過其他類型標識符,如MIME標識符,轉換成UTI,當可以創建多個UTI字符串時,一般返回'public'域名的UTI。
4.UTTypeCreateAllIdentifiersForTag
通過其他類型標識符,如MIME標識符,轉換成UTI,當可以創建多個UTI字符串時,返回所有的UTIs,讓你自己選
5.UTTypeCopyPreferredTagWithClass
交換UTI字符串標識

自定義UTI

1. 用法

蘋果允許Mac開發者為他們的Mac App中獨有的數據格式自定義新的UTI。它們一般被聲明在下面幾個文件中

  • Info.plist
  • Application bundles
  • Spotlight Importer bundles
  • Automator action bundles

使用官方給我們的一個UTI聲明的例子,Public.jpeg聲明:

<key>UTExportedTypeDeclarations</key>
       <array>
           <dict>
               <key>UTTypeIdentifier</key>
               <string>public.jpeg</string>
               <key>UTTypeReferenceURL</key>
               <string>http://www.w3.org/Graphics/JPEG/</string>
               <key>UTTypeDescription</key>
               <string>JPEG image</string>
               <key>UTTypeIconFile</key>
               <string>public.jpeg.icns</string>
               <key>UTTypeConformsTo</key>
               <array>
                   <string>public.image</string>
                   <string>public.data</string>
               </array>
               <key>UTTypeTagSpecification</key>
               <dict>
                   <key>com.apple.ostype</key>
                   <string>JPEG</string>
                   <key>public.filename-extension</key>
                   <array>
                       <string>jpeg</string>
                       <string>jpg</string>
                   </array>
                   <key>public.mime-type</key>
                   <string>image/jpeg</string>
               </dict>
           </dict>
       </array>

一個UTI聲明的屬性列表:

<section>
<div style="margin-top:1.667em;margin-bottom:1.667em;">
<table border="0" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<th scope="col" style="font-weight:400;background-color:#93A5BB;padding:0.3em 0.667em;font-size:13px;color:#FFFFFF;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#9BB3CD;border-right-width:1px;border-right-style:solid;border-right-color:#9BB3CD;">
<p style="font-weight:700;line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;margin-bottom:0.33em;">
Key
</p>
</th>
<th scope="col" style="font-weight:400;background-color:#93A5BB;padding:0.3em 0.667em;font-size:13px;color:#FFFFFF;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#9BB3CD;border-right-width:1px;border-right-style:solid;border-right-color:#9BB3CD;">
<p style="font-weight:700;line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;margin-bottom:0.33em;">
Value type
</p>
</th>
<th scope="col" style="font-weight:400;background-color:#93A5BB;padding:0.3em 0.667em;font-size:13px;color:#FFFFFF;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#9BB3CD;border-right-width:1px;border-right-style:solid;border-right-color:#9BB3CD;">
<p style="font-weight:700;line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;margin-bottom:0.33em;">
Description
</p>
</th>
</tr>
<tr>
<td scope="row">
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
<code style="font-family:Courier, Consolas, monospace;color:#666666;">UTExportedTypeDeclarations</code>
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
array of dictionaries
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
An array of exported UTI declarations (that is, identifiers owned by the bundle’s publisher).
</p>
</td>
</tr>
<tr>
<td scope="row">
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
<code style="font-family:Courier, Consolas, monospace;color:#666666;">UTImportedTypeDeclarations</code>
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
array of dictionaries
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
An array of imported UTI declarations (that is, identifiers owned by another company or organization).
</p>
</td>
</tr>
<tr>
<td scope="row">
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
<code style="font-family:Courier, Consolas, monospace;color:#666666;">UTTypeIdentifier</code>
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
string
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
The UTI for the declared type. This key is required for UTI declarations.
</p>
</td>
</tr>
<tr>
<td scope="row">
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
<code style="font-family:Courier, Consolas, monospace;color:#666666;">UTTypeTagSpecification</code>
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
dictionary
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
A dictionary defining one or more equivalent type identifiers.
</p>
</td>
</tr>
<tr>
<td scope="row">
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
<code style="font-family:Courier, Consolas, monospace;color:#666666;">UTTypeConformsTo</code>
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
array of strings
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
The UTIs to which this identifier conforms.
</p>
</td>
</tr>
<tr>
<td scope="row">
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
<code style="font-family:Courier, Consolas, monospace;color:#666666;">UTTypeIconFile</code>
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
string
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
The name of the bundle icon resource to associate with this UTI.
</p>
</td>
</tr>
<tr>
<td scope="row">
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
<code style="font-family:Courier, Consolas, monospace;color:#666666;">UTTypeDescription</code>
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
string
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
A user-visible description of this type. You can localize this string by including it in an <code style="font-family:Courier, Consolas, monospace;color:#666666;">InfoPlist.strings</code> file.
</p>
</td>
</tr>
<tr>
<td scope="row">
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
<code style="font-family:Courier, Consolas, monospace;color:#666666;">UTTypeReferenceURL</code>
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
string
</p>
</td>
<td>
<p style="line-height:normal;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;">
The URL of a reference document describing this type.
</p>
</td>
</tr>
</tbody>
</table><br />
</div>
</section>
<section>
<a name="http://apple_ref/doc/uid/TP40001319-CH204-SW4" title="Recommendations for Declaring new Uniform Type Identifiers" style="color:#3366CC;font-family:'Lucida Grande', 'Lucida Sans Unicode', Helvetica, Arial, Verdana, sans-serif;font-size:13px;background-color:#FFFFFF;"></a>
</section>
<p>
<br />
</p>

屬性列表

而且自定義的UTI必須指定UTExportedTypeDeclarations或者UTImportedTypeDeclarations,這樣如果是你定義的UTI,第三方應用程序和服務都可以使用,而如果是其他人定義的UTI,那么加入到你的項目中后,你就可以看到這種類型的數據。

而官方文檔中有一句話:“If both imported and exported declarations for a UTI exist, the exported declaration takes precedence over imported one”,我的理解是,被導出去得UTI聲明所有人是定義UTI的發布者,也就是你的項目,而被導入的UTI聲明所有人就是其他人,所以就是說如果對于一個UTI來說,倆種類型的聲明都存在,則自己定義的UTI聲明優先使用。

2. 自定義UTI的建議

  1. 你的UTI字符串必須是唯一的。以‘com.’開頭的反域名命名方式是確保唯一性的簡單有效的方法。
  2. 如果你的代碼依賴于第三方App,UTI類型或許不會在系統中展示,你應該在bundle中聲明為導入類型
  3. 如果你的UTI類型是一個或多個已存在的UTI類型的子類,則必須給它添加順應性,讓它繼承于某個父類。最好是繼承于‘public’類型。

原文地址:鄭少博的技術博客---詳解蘋果提供的UTI(統一類型標識符)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,785評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,661評論 25 708
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,898評論 6 342
  • { "Unterminated string literal.": "未終止的字符串文本。", "Identifi...
    一粒沙隨風飄搖閱讀 10,646評論 0 3
  • 今天應該是接觸天貓運營的第三天。解決了一些燃眉之急,把活動的布展也完成了了一部分。很幸運的是,第一位客戶...
    淺淺繪繪閱讀 174評論 0 0