ulysses 外部文件夹里的文件 无法dnf觉醒插图文件夹的问题。

雨季来得猛烈突然,不知道你的城市有没有在看海,总之还是希望不会遇上这种事,大家出...
今日传来消息称,苹果终于要开放 Siri 的 API 给第三方开发者,让 Siri 更深层地与第...
“喝酒”、“撩妹”的中年大叔也照样能拿个第一,走上人生巅峰啊!
有时候不需要长篇大论,一张图就已经可以点明主题。
不要方,库克只是开个玩笑而已。
没错,我们这里说的是LTE芯片。高通在这一领域的优势不是这么随便就能超过的。
财政部长对外商投资促进委员会的决定表示支持,认为苹果也没有例外。
柔性屏加模块化,看起来LG要继续将革命进行到底~
刀塔的故事背景我想不少朋友已经很熟悉,再重复灌输难免显得有些啰嗦,详细的剧情小...
这款名为《点击猫大战(Tap Cats: Idle Warfare)》的游戏一看就知道是以点击操作为主...
几年之前,在真人秀还没有扎堆的以“孩子”、“鲜肉”、“男男CP”为卖点的时候,寻找...
以史前时代为创作灵感的游戏很多,类型的涵盖面也比较广,最近 Ivanovich Games 推出...
此前华纳公司曾经宣布将会在移动平台当中推出一款蝙蝠侠游戏,这款名为《蝙蝠侠:阿甘...
在这里我们会率领众多英雄级人物完成各种战斗使命,从原来的一方据点逐渐将整片土地拿...
近日,游戏开发商
在苹果商店当中推出了其体育类休闲游戏《冰球明星(Ho...
由于当地还没有官方零售店,库克在授权店也开了一次眼界。
这款 Otterbox 模块化保护壳的背面底部拥有一个凹槽设计,允许用户将自己需要增强的模...
苹果与飞利浦其实也是老搭档了~
耳机的造型设计借鉴了黑胶唱片标志性的圆碟造型,在享有优良音质的同时迎合时尚品味。
说得我都想天天呆厨房里做甜品了~
尽管有缺陷,但它应该称得上是一款很优秀的,适配iPhone的VR设备。
BookBook 保护壳能够将用户的 iPad Pro 变成一本尺寸较大的皮革装订书。
这两款镜头都非常薄,这种厚度令其放置于钱包中都毫无压力。
你的灯亮着吗:发现问题的真正所在(插图本)
注册时间 最后登录
在线时间233 小时 UID
主题帖子人气
白苹果, 积分 674, 距离下一级还需 826 积分
本帖最后由 我本向佛 于
00:11 编辑
& & 本书以别具一格的视角和幽默风趣的语言讨论了解决问题时有可能遇到的多种困难,并就如何训练思维能力指点迷津。本书分六个主题,每个主题都由若干生动有趣和发人深省的小故事组成,巧妙地引导读者先确认真正的问题,然后明确问题该由谁解决,再确定问题的根源,最后决定到底想不想解决这个问题。
& &本书适合所有业界人士以及想要探索问题解决之道的虚心读者细细品味。
00:11 上传
点击文件名下载附件
<p id="rate_25940" onmouseover="showTip(this)" tip="我用@威锋微信支持你!&人气 + 1
" class="mtn mbn">
<p id="rate_98565" onmouseover="showTip(this)" tip="感谢分享^_^&人气 + 1
" class="mtn mbn">
<p id="rate_51588" onmouseover="showTip(this)" tip="感谢分享^_^&人气 + 1
" class="mtn mbn">
<p id="rate_23460" onmouseover="showTip(this)" tip="感谢分享^_^&人气 + 3
" class="mtn mbn">
<p id="rate_19781" onmouseover="showTip(this)" tip="感谢分享^_^&人气 + 1
" class="mtn mbn">
<p id="rate_44140" onmouseover="showTip(this)" tip="威锋有你更精彩:)&人气 + 1
" class="mtn mbn">
<p id="rate_92742" onmouseover="showTip(this)" tip="感谢分享^_^&人气 + 5
" class="mtn mbn">
<p id="rate_79901" onmouseover="showTip(this)" tip="&a
href=&forum.php?mod=redirect&goto=findpost&ptid=9123216&pid=&fromuid=1&&&span &感谢楼主分享&/span&&/a&&人气 + 1
" class="mtn mbn">
<p id="rate_63563" onmouseover="showTip(this)" tip="感谢分享^_^&人气 + 1
" class="mtn mbn">
<p id="rate_27077" onmouseover="showTip(this)" tip="感谢分享^_^&人气 + 1
" class="mtn mbn">
<p id="rate_60633" onmouseover="showTip(this)" tip="感谢分享..&人气 + 1
" class="mtn mbn">
<p id="rate_10918" onmouseover="showTip(this)" tip="&a
href=&forum.php?mod=redirect&goto=findpost&ptid=9123216&pid=&fromuid=1&&&span &精彩转帖^_^&/span&&/a&&人气 + 1
" class="mtn mbn">
<p id="rate_56191" onmouseover="showTip(this)" tip="&a
href=&forum.php?mod=redirect&goto=findpost&ptid=9123216&pid=&fromuid=1&&&span &感谢分享^_^&/span&&/a&&人气 + 2
" class="mtn mbn">
<p id="rate_43729" onmouseover="showTip(this)" tip="感谢分享^_^&人气 + 2
" class="mtn mbn">
评分次数14
我用@威锋微信支持你!
感谢分享^_^
感谢分享^_^
感谢分享^_^
感谢分享^_^
威锋有你更精彩:)
感谢分享^_^
感谢分享^_^
感谢分享^_^
感谢分享..
感谢分享^_^
八零末犯二屌丝一枚,平时不务正业,唯独喜欢舞文弄墨!个人公号:时光劫;微信号:shiguangjie521。
注册时间 最后登录
在线时间265 小时 UID
主题帖子人气
注册时间 最后登录
在线时间13 小时 UID
主题帖子人气
下了顶,顶了下
<p id="rate_25940" onmouseover="showTip(this)" tip="我用@威锋微信支持你!&人气 + 1
" class="mtn mbn">
我用@威锋微信支持你!
注册时间 最后登录
在线时间144 小时 UID
主题帖子人气
感谢分享& && && &
注册时间 最后登录
在线时间144 小时 UID
主题帖子人气
感谢分享& && && &
注册时间 最后登录
在线时间64 小时 UID
主题帖子人气
谢谢楼主分享
注册时间 最后登录
在线时间231 小时 UID
主题帖子人气
对我本向佛于 23:52:55在楼主发表的内容评分:人气:+2;
本帖最后由 我本向佛 于
00:11 编辑
& & 本书以别具一格的视角和幽默风趣的语言讨论了解决问题时有可能遇到的多种困难,并就如何训练思维能力指点迷津。本书分六个主题,每个主题都由若干生动有趣和发人深省的小故事组成,巧妙地引导……感谢分享^_^
注册时间 最后登录
在线时间17 小时 UID
主题帖子人气
感谢分享!
注册时间 最后登录
在线时间14 小时 UID
主题帖子人气
看看 能帮我解决目前的问题不
注册时间 最后登录
在线时间40 小时 UID
主题帖子人气
Thanks for sharing.
威锋旗下产品
Hi~我是威威!
沪公网安备 29号 | 沪ICP备号-1
新三板上市公司威锋科技(836555)
增值电信业务经营许可证:
Powered by Discuz!Pages(四)文档编辑中的对象
文档编辑类的软件有不少共同的特性,不过在使用场景上还是各有侧重,就Mac上的几款文档编辑软件而言,Pages适合短篇内容创作,并且在图文混排和版式控制上非常灵活。小说或论文这一类对内容的组织和管理上要求更高的长篇文档推荐使用Scrivener。博客网文类的创作推荐Ulysses这类支持Markdown的编辑器,既有一定的文档组织特性,在编辑和写作上也非常方便。
文档交流的过程中,很多时候因为兼容性问题常常是受限于对方的文档格式,以至于我们不得不使用和商业伙伴一样的软件来进行编辑和修改,体现最集中的就是Office的文档。Mac平台上的Office和Windows平台下的Office存在不小的差异,运行的速度和流畅性有时候还不如虚拟机中的Windows版Office,所以推荐在Windows虚拟机上安装Office的方式来兼容。
Word在功能点上和Pages存在不少差异,对于超出Pages范畴的格式设置肯定会存在兼容问题,但是反过来Pages的导出的Word格式在Word中打开没有太大的问题。对于不需要给对方提供原始稿件的交流来说,PDF格式是个很好的选择,既能保证对方看到的与你所看到的一致,而且注释方便且不存在兼容性问题。
在常规的文档编辑工作中,Pages的优势很明显,上手快,交互直观,编辑和排版效率高,能让人把重心放在内容上而不会被繁琐的设置搞晕。直观的让你了解当前的设定状态,这一点在文档编辑中是非常重要的。Word里通常你选中一个段落、一个图片只是提供给你可设定的多种途径,不能反馈给你当前对象的状况,这很容易让人「迷茫」。Pages中这种反馈则非常直接和明确,三击选中一个段落,面板会显示具体的段落设置项;选中一个图片,面板会跳转到图片设置;插入各种对象时,常规设置在对象上就能实现,打开一个包含修订和重点的文稿,顶部会自动显示修订栏。
总的来说,Pages更符合编辑和写作的自然流程,帮助我们聚焦在内容的创作上,Pages的文档编辑方面没有太多需要赘述的地方,下面的内容中会罗列一些要点,帮助我们对Pages的编辑能力形成一个整体的概念。
粘贴并匹配样式,从网页或者其他文档中复制内容到Pages,采用粘贴并匹配样式(&#8679;&#8997;&#8984;V)的方式来粘贴并让内容匹配当前的格式,这也是大多数文档编辑软件支持的一种特殊粘贴方式。如果是基于模板新建的Pages文档中,可以一次性被选中占位符文本(文本占位符区域会呈现橘红色的高亮)的多个段落,进行粘贴。
单词自动完成,输入英文单词时,可以在输入一部分后按option+esc键来显示备选单词列表,实现快速的输入或单词检索。
高亮文本(&#8679;&#8984;H)和批注(&#8679;&#8984;K),高亮文本和批注作为一种写作的辅助手段来标注和补充额外的信息,它们不会出现在打印或输出的文档格式中,高亮文本可以理解成不写注释内容的批注。相比较「字符样式」只能够的字体背景色而言,高亮不涉及到输出层面,另外利用快捷键设置便捷,通过「修订栏」上的左右箭头,可以在多个重点之间跳转定位。
在内容的定位和文字处理上,常用的快捷键有:
Command+左箭头键或右箭头键,当前行的行首和行尾;
Option+上箭头键或下箭头键,当前段落的开始位置和结束位置;
Control+L,将插入点居中放置在应用程序窗口的中心;
连按段落三次,选择当前段落;
Shift+Command+右箭头键或右箭头,选中光标位置到行尾的内容或由光标到行首的内容;
Shift+Command+上箭头键或下箭头,选中光标位置到文章开始的内容或由光标到文章结束的内容;
Command+B,加粗文本;
Command+K,给文字加超链接;
Shift+Command+H,高亮文本;
Shift+Command+K,添加批注。
图片对象是文档编辑中的另一个重要元素,Pages中比Word方便的地方在于「预览」和对图片的拖拽。基于模板新建的文档中,图片可以直接拖拽到媒体占位符的图片上,不是媒体占位符标记的图片,直接拖拽图片到图像面板的图片文件上也能快速实现替换。反过来,按住图像面板中的图片名称,还可以直接将图片拖拽到桌面。
图片的拖拽替换
处理包含很多插图的文档过程中,为了操作方便,通常我们将桌面作为截图或图片编辑软件与Pages的交换空间,这样,更新和插入图片的操作简单的拖拽就能完成。
插入的图片采用哪一种环绕模式是文本编辑中比较突出的问题,默认拖拽到Pages中的图片选择的「文本绕排」方式是「自动」,拖移中会显示辅助对齐线来帮助你定位,会选择相对于页面和四周文本最适合的文本绕排方式来放置对象。
对于软件界面插图这类的图片,多半选择的是「上方和下方」的绕排方式,选中图片的情况下可以看到蓝色的图钉式的定位锚点。
如果是在一行文字中插入一个小的图标类的图片,图片的绕排方式应该是「内联(带文字)」,插入的对象位于文本的基线上,并将随着文本移动。如古文写作中遇到一些字体库中无法显示的字符时,通常我们用图片来代替,插入这类图片采用的就都是「内联(带文字)」的方式。
用于版式布局的图片才会采用「停留在页面」的方式来固定图片位置。例如封面中的插图、水印图片等。
Pages和Word在表格的插入逻辑上不太一样,Pages是先确定风格等插入后再调节行数和列数,Word则是先确定行数和列数再选择不同风格。在列宽度的拖拽调节上,Pages和Word的逻辑也不同,Word里直接拖拽列所在的纵线就可以,其他的列不会变动。Pages中插入的表格默认已经是内容的最大宽度,要调节单独列的宽度需要先调小整个表格的宽度,留出空间后才能单独放大某个列的宽度。不过通过表格面板「行与列的大小」进行具体的列宽度数值调节时不受此影响。
表格和运算
实际体验对比上,Pages中插入表格到调节行、列,到最后填充数据,整个交互都更流畅,表格的行数、列数以及标题行可以直接在界面上快速设定,函数公式的使用上也非常直观,只需要在单元格中输入「=」号就会弹出公式窗口,此时鼠标选中要计算的单元格,最后点击绿色对勾确认即可。同比Word中要完成这些操作,需要展开好几个层级。
表格的定位
表格的位置由表格格式设置中的「对象放置」的设定来决定,如果选择「停留在页面」那么表格会像图片一样任意的摆放位置,但是表格跨页不会分页。
通常我们会设置表格为「随文本移动」,跟随在文本和段落后,遇到跨页的情况时,默认的样式会跳转到新的页面开始表格而不是在标题后继续,如果不想表格自动换页开始,可以将标题的样式中的「防止寡行与孤行」的勾选去掉。
表格的定位
跨页的表格可以在每一页显示标题行,只需要展开标题行的选项,勾选「在每页重复标题行」。
多个文档合并时,如果遇到表格错位的问题,可以检查一下表格前后段落的设置中行距是否是倍数行距,如果是固定的磅数,表格的排列方式会是「停留在页面」,从而有可能形成段落和表格的叠加。
通过点击插入图表下方的「编辑图表数据」,进入「图表数据」的具体设置窗口。点按「图表数据」窗口右上角的行或列按钮,可以更改数据序列是行还是列。
图表和图表类型
图标设置面板底部的图表类型中可以改变图表的显示形态,柱状图、饼图或者三维立体图等。
选中整个图标后,可以在图标颜色中选择不同的系列颜色,选中具体的色块对象后也可以在图标面板的样式中给具体的项目设定具体的其他颜色或填充。
自动保存和版本
Pages会自动保存文稿并每隔一小时保存一个版本,这也Mac系统的特色,苹果自家的iWork、文本编辑都支持「自动保存」和「版本」功能。
「自动保存」让我们可以只专注于写作,切换到其他程序、或者随时合盖,后台运行的自动保存功能会保存你的工作;如果连续工作,则每 5
分钟就会保存一次。
TimeMachine 每隔一小时保存一份新版本,从而为你的文稿建立完整的历史记录。手动 Command+S
的存储也会保存在Time Machine中。通过时光隧道能很方便的浏览或恢复到某个版本,也可以从某个版本中复制部分内容。
版本的时光隧道
进入版本的方式有两种,一种是通过Pages的菜单项「文件-复原到-浏览所有版本」,一种方式是通过系统顶栏中的Time
Machine图标「进入Time Machine」。
文稿的锁定
最终版本的文稿,可以勾选「已锁定」来防止意外的更改。
就文档编辑而言,除了格式的控制灵活性和友好的界面以外,自动保存和版本管理可以说是「写作者」的福音。自从苹果公布了
相关的API以后,越来越多的第三方软件开始支持这一功能,它们都有一个共同特点,就是窗口标题名称后面有一个可以展开的下三角箭头,例如,Pixelmator、OmniGraffle、Scapple、PlistEdit
本站系本网编辑转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与本网联系,我们将在第一时间删除内容![声明]本站文章版权归原作者所有
内容为作者个人观点 本站只提供参考并不构成任何投资及应用建议。本站拥有对此声明的最终解释权
一、本站内收录的所有教程与资源均来自于互联网,其版权均归原作者及其网站所有,本站虽力求保存原有的版权信息,但由于诸多原因,可能导致无法确定其真实来源,请原作者原谅!如果您对本站教程与资源的归属存有异议,请立即通知优设,情况属实,我们会第一时间予以删除,并同时向您表示歉意!看着优设真诚的小眼神,绝对不是故意侵犯原作者版权的哦!如果您有优秀的作品,优设也会帮您在微博扩散推荐。
二、本站转载的教程与资源仅为资源共享、学习参考之目的,很难对其可用性、准确性或可靠性做出任何承诺与保证。本站无法对任何由于使用或无法使用本站提供的教程与资源所造成的损失负任何责任。
三、本站通过互联网转载的教程与资源,或是站内作者自己提供的教程与资源,版权均归原作者所有,未经原版权作者许可,任何人不得擅作他用!您可以复制、转载和传播本站的任何信息,但务必在转载时注明来源,尊重其知识产权,并自负版权等法律责任。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。认识与入门 Markdown - 少数派
认识与入门 Markdown
认识与入门 Markdown
是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用。看到这里请不要被「标记」、「语言」所迷惑,Markdown 的语法十分简单。常用的标记符号也不超过十个,这种相对于更为复杂的HTML 标记语言来说,Markdown 可谓是十分轻量的,学习成本也不需要太多,且一旦熟悉这种语法规则,会有一劳永逸的效果。
一、认识 Markdown
在刚才的导语里提到,Markdown 是一种用来写作的轻量级「标记语言」,它用简洁的语法代替排版,而不像一般我们用的字处理软件 Word 或 Pages 有大量的排版、字体设置。它使我们专心于码字,用「标记」语法,来代替常见的排版格式。例如此文从内容到格式,甚至插图,键盘就可以通通搞定了。目前来看,支持 Markdown 语法的编辑器有很多,包括很多网站(例如)也支持了 Markdown 的文字录入。Markdown 从写作到完成,导出格式随心所欲,你可以导出 HTML 格式的文件用来网站发布,也可以十分方便的导出 PDF 格式,这种格式写出的简历更能得到 HR 的好感。甚至可以利用
这种云服务工具直接上传至网页用来分享你的文章,全球最大的轻博客平台 Tumblr,也支持使用 Mou 这类 Markdown 工具进行编辑并直接上传。
Markdown 官方文档
这里可以看到官方的 Markdown 语法规则文档,当然,后文我也会用自己的方式,阐述这些语法在实际使用中的用法。
使用 Markdown 的优点
专注你的文字内容而不是排版样式。
轻松的导出 HTML、PDF 和本身的 .md 文件。
纯文本内容,兼容所有的文本编辑器与字处理软件。
可读,直观。适合所有人的写作语言。
我该用什么工具?
在 Mac OS X 上,我强烈建议你用
这款免费且十分好用的 Markdown 编辑器,它支持实时预览,既左边是你编辑 Markdown 语言,右边会实时的生成预览效果,笔者文章就是 Mou 这款应用写出来的。
其次还有很多同类选择。如果你是个编辑作者,我强烈建议你购买 ,这款应用入围了苹果去年 Mac App Store 的 The Best of 2013,相比 Mou 它支持更多的写作格式、多文档的支持。Mou、iA Writer 这些应用都是基于单文档的管理方式,而 Ulysses Ⅲ 支持 Folder、Filter 的管理,一个 Folder 里面可以创建多个 Sheet,Sheet 之间还可以进行 Combine 处理。
Windows、iOS、Web 平台
笔者并未使用过 Windows 下的 Markdown 工具,但经朋友介绍,有两款还算不错,一款叫
,另一款叫 。
iOS 端已有相当多的 app 支持 Markdown 语法编辑,例如 Drafts、Day One、iA Writer 等。
Web 端上,我强烈推荐
这款产品,上面有无数热爱文字的人在不停的创造、分享。在 Web 端使用 Markdown 没有比简书更舒服的地方了,它同样支持左右两栏的实时预览,字体优雅、简洁。
同样是 Web 端, 这款在线 MD 编辑器也近乎完美。
二、Markdown 语法的简要规则
标题是每篇文章都需要也是最常用的格式,在 Markdown 中,如果一段文字被定义为标题,只要在这段文字前加 # 号即可。
# 一级标题
## 二级标题
### 三级标题
以此类推,总共六级标题,建议在井号后加一个空格,这是最标准的 Markdown 语法。
熟悉 HTML 的同学肯定知道有序列表与无序列表的区别,在 Markdown 下,列表的显示只需要在文字前加上 - 或 * 即可变为无序列表,有序列表则直接在文字前加 1. 2. 3. 符号要和文字之间加上一个字符的空格。
如果你需要引用一小段别处的句子,那么就要用引用的格式。
& 例如这样
只需要在文本前加入 & 这种尖括号(大于号)即可
图片与链接
插入链接与插入图片的语法很像,区别在一个 !号
插入图片的地址需要图床,这里推荐
的服务,生成URL地址即可。
粗体与斜体
Markdown 的粗体和斜体也非常简单,用两个 * 包含一段文本就是粗体的语法,用一个 * 包含一段文本就是斜体的语法。
例如:这里是粗体 这里是斜体
表格是我觉得 Markdown 比较累人的地方,例子如下:
| ------------- |:-------------:| -----:|
| col 3 is
| right-aligned | $1600 |
| col 2 is
| centered
| zebra stripes | are neat
这种语法生成的表格如下:
TablesAreCool
right-aligned
zebra stripes
如果你是个程序猿,需要在文章里优雅的引用代码框,在 Markdown 下实现也非常简单,只需要用两个 ` 把中间的代码包裹起来,如 `code`。图例:
使用 tab 键即可缩进。
分割线的语法只需要另起一行,连续输入三个星号 *** 即可。
到这里,Markdown 的基本语法在日常的使用中基本就没什么大问题了,只要多加练习,配合好用的工具,写起东西来肯定会行云流水。更多的语法规则,其实 Mou 的 Help 文档例子很好,当你第一次使用 Mou 时,就会显示该文档,其次,你也可在撰写过程中,使用 CMD+R 快捷键来快速打开文档,以随时查阅和学习语法。
三、与 Markdown 相关的一些推荐
可配套使用的工具
相关文章阅读
分享到微信
自由撰稿人,Mac user
Email 登录
商务&合作:
投稿&报道:
微信订阅二维码精通iCloud文档存储
即便在推出 3 年后,iCloud 文档存储依然是一个充满神秘、误解和抱怨的话题。iCloud 同步经常被批评不可靠且速度慢。虽然在 iCloud 的早期有一些严重的 bug,开发者们还是不得不学习有关文件同
本文转自 ,原文:《》
即便在推出 3 年后,iCloud 文档存储依然是一个充满神秘、误解和抱怨的话题。iCloud 同步经常被批评不可靠且速度慢。虽然在 iCloud 的早期有一些严重的 bug,开发者们还是不得不学习有关文件同步的课程。文件同步事关重大,为应用开发带来了新方向 & 一个经常被低估的方向,比如进行同步服务相关的合作时,对于处理文件异步更改的需要。
本文会介绍几个创建支持 iCloud 的应用时可能会遇到的一些绊脚石。因为本文只会给出一些粗略的概述,所以如果你对 iCloud 文档存储还不熟悉,我们强烈建议你先阅读 。
文档存储简介
iCloud 文档存储的核心思想非常简单: 每个应用都有至少通往一个&魔法文件夹&的入口,该文件夹可以存储文件并且随后在所有注册了同一个 iCloud 帐号的设备间同步。
与其他基于文件系统的同步服务相比,iCloud 文档存储得益于与 OS X 和 iOS 的深度整合。很多系统框架已经被扩展以支持 iCloud。像 NSDocument 和 UIDocument 这样的类被按照可以处理外部变化来进行设计。版本存储和 NSFileVersion 处理同步冲突。Spotlight 被用来提供同步元数据,比如文件传输进度或者云端文档可用性。
写一个简单的基于文档并开启了 iCloud 的 OS X 应用并不需要费多大力气。实际上你并不需要关心任何 iCloud 内部的工作,NSDocument 无偿的做了几乎每件事情: 协调文档的 iCloud 访问,自动观察外部变化,触发下载,处理冲突。它甚至提供了一个简单的 UI 界面来管理云文档。你需要做的所有事情就是创建一个 NSDocument 子类并实现读取和写入文档内容所需要的方法。&
NSDocument provides a simple user interface for managing the synchronized documents of an app.
然而,一旦脱离预设的路径,你就需要了解的更多。例如,默认打开面板提供的单层文件夹以外的任何操作都需要手动完成。可能你的应用需要管理除了文档内容以外的文档,比如像 Mail,iPhoto 或者
(我们自己的app) 中做的那样。这种时候,你不能依赖于 NSDocument,而需要自己实现它的功能。但为此你需要对 iCloud 提供的锁和通知机制有一个深入的了解。
开发支持 iCloud 的 iOS 应用同样需要更多的工作和知识: 虽然 UIDocument 仍然管理 iCloud 文件访问和处理同步冲突,但缺乏管理文档和文件夹的图形界面。因为性能和存储空间的原因,iOS 也不会自动从云端下载新文档。你需要使用 Spotlight 来检索最近变化的目录并手动触发下载。
什么是开放性容器 (Ubiquity Container)
任何符合 App Store 条件的应用都可以使用 iCloud 文档存储。设置正确的后,就获得了一个或多个所谓的&开放性容器&的访问权限。这是苹果用来称呼&一个被 iCloud 管理和同步的目录&的别称。每一个开放性容器限定在一个 app id 内,由此让每个用户在每个应用中有一份共享的存储仓库。有多个应用的开发者可以指定同一个团队的多个 app id,由此可以访问多个容器。
NSFileManager 通过 提供每一个容器的 URL。在 OS X 系统,可以通过打开 ~/Library/Mobile Documents 目录来查看所有可用的开放性容器。&
The contents of &~/Library/Mobile Documents.& It contains a separate folder for each ubiquity container of each application.
通常每个开放性容器有两个并发进程访问。首先,有一个应用呈现和操作容器内的文档。第二,有一个主要通过开放性守护 (Ubiquity Daemon ubd) 体现的 iCloud 架构。iCloud 架构等待应用对文档的更改并将其上传至苹果云服务器。同时也等待从 iCloud 上收到的更改并相应修改容器的内容。
由于两个进程完全独立于彼此工作,因此需某种形式的仲裁来避免资源竞争或丢失容器内的文件更新的问题。应用需要使用名为
的概念来确保对于每一个独立文件的访问权。该访问权由
类提供。概括来说,它为每个文件提供了一个简单的 读-写 锁。这个锁由一个通知机制扩展,该机制用于用于改善访问同一个文件的不同进程间的合作。
这个通知机制相比于简单的文件锁来说是有巨大的好处,并且提供了无缝的用户体验。iCloud 可能会在任何时间把文档用一个来自其他设备的新版本覆盖。如果一个应用当前正在显示同一个文档,它必须从磁盘加载新版本并向用户展示更新过的内容。更新过程中,应用可能需要锁住用户界面一段时间并随后在此打开。甚至可能发生更坏的情况: 应用可能保留着未保存的内容,这些内容需要首先保存到磁盘上以便检查同步冲突。最后,在网络条件良好的时候 iCloud 会上传文件最近的版本。因此必须能够要求应用立刻保存所有未保存的变更。
为了实现这个过程,文件协调伴随着另一套名为 文件展示 (file presentation) 的机制。无论什么时候应用打开并向用户展示一个文件,这被称为 展示文档,并且应该注册一个实现了协议的对象。只要另一个进程通过一个文件协调访问文件,文件展示者 (file presenter) 就会收到关于该文件的通知。这些通知被作为方法调用传递,这些方法在展示者指定的一个操作队列()中异步执行。
例如,在任何其他线程被允许开始一个读取操作前,文件展示者被要求保存任何未保存的变化。这些操作通过分发一个 block 到它的展示队列来执行 方法来完成。展示者需要保存文件并通过执行作为参数传入的 block 来确认通知。除了改变通知,文件展示者还用来通知应用同步冲突。一旦一个文件的冲突版本被下载,一个新的文件版本被加入到版本存储里。所有的展示者通过 被通知有一个新版本被创建。该回调接收一个引用了潜在冲突的 NSFileVersion 实例。
文件展示者还可以被用来监视文件夹内容。例如,一旦 iCloud 改变文件夹内容,如创建,删除或者移动文件,应用应该被通知到以便更新它的文档展示。为此,应用可以对展示的目录注册一个实现了 NSFilePresenter 协议的实例。一个目录的文件展示者会收到任何文件夹或其中文件或子文件夹的改变的通知。比如一个文件夹内的文件被修改,展示者会收到一个引用了该文件的 URL 的 presentedSubitemDidChangeAtURL: 通知。
因为带宽和电池寿命在移动设备上更加有限,iOS 不会自动从 iCloud 下载新文件。而是由应用手动决定何时来触发下载新文件到开放性容器中。为了持续告知应用哪些文件可用及其同步状态,iCloud 还会同步开放性容器内的文件元信息。应用可以通过 NSMetadataQuery 或访问 NSURL 的开放资源属性查询这些元信息。无论何时应用想要访问一个文件,它一定会通过 NSFileManager 的来触发下载行为。
深入 iCloud
在继续解释如何实现文件协调和观察之前,现在我们将深入一些过去几年里碰到的一些常见问题。再一次的,确保你已经阅读并理解了 。
虽然这些文件机制的描述让它们的使用看起来简单明了,但其实其中有很多隐藏的陷阱。这些陷阱中有些来自于底层框架的 bug。因为 iCloud 同步延伸到操作系统中相当多的层面,人们只能寄希望于苹果能够小心的修复这些 bug。实际上,苹果看起来宁愿废弃坏掉的 API 而不是修复它们。
即便如此,我们的经验告诉我们使用 iCloud 是非常非常容易犯错误的。异步,协作,基于锁特性的文件协调和文件展示互相牵连,并不容易掌握。下面,我们将介绍整合 iCloud 文档同步时的一些主要规则,并以这种形式分享我们的经验。
只在需要时使用 Presenters
文件展示者代价高昂。仅当你的应用需要立即应对或干预文件访问的时候,才应该使用它。
如果你的应用正在展示类似文档编辑器这样的东西给用户,文件展示足以胜任。这时,在其他进程写入该文件的时候也许需要锁住编辑器,或者还需要保存未保存的改变。然而,如果只是临时访问并且通知也可能会被延迟处理,就不应该使用文件展示。例如,当创建文件索引或缩略图,查看文件更改日期并使用简单的文件协调可能会更高效。另外,如果你正展示一个字典树的内容,在树的根节点注册 一个 展示者或用 NSMetadataQuery 来延迟获取改变通知会可能会非常高效。
是什么让文件展示代价如此高昂?它需要很多的进程间通信: 每个文件上注册的展示者在其他进程获取文件的访问权时都被要求释放该文件。比如另一个进程尝试读取一个文件,该文件的展示者会被要求保存所有未保存的内容 ()。它们还会被要求释放文件给读取者(),例如文件被读取时暂时锁住编辑器。
这些通知每一个都需要分发,加工并由各自的接收者确认。并且因为只有实现的进程知道哪些通知会被处理,所以即使展示者没有实现任何方法,进程间也会为每一个可能的通知进行通信。
另外,每个步骤都需要在读取进程,展示进程和文件协调守护进程 (filecoordinationd) 间的多重上下文的切换。结果就导致了一个简单的文件访问很快就变成耗费资源的操作。
除此之外,如果太多的展示者被注册,文件协调守护进程可能会删除重要的系统资源。对于每一个展示者,都需要打开并监听每一个它所描述的路径上的文件夹。尤其在 OS X Lion 和 iOS 5 上,这些资源是非常稀少的,过度的使用很容易导致文件协调守护进程的锁死或崩溃。
基于这些原因,我们强烈建议不要在目录树的每一个节点上增加文件展示者,只根据需要使用最少的文件展示者。
只在需要时使用协调
虽然文件协调要比文件展示节约资源,但它仍然给你的应用和整个系统增加额外的负担。
每当你的应用正在协调一个文件,其他同时想要访问同一个文件的进程可能需要等待。因此你不该在协调文件时执行过于耗时的任务。如果你这么做了,比如存储了大文件,你可以考虑将它存储到一个临时文件夹,随后在协调访问时使用硬连接。注意每一个协调的访问都可能会触发另一个进程上的文件展示者 & 该展示者可能需要时间在你的访问之前更新文件。始终考虑使用诸如 NSFileCoordinatorReadingWithoutChanges 这样的标识,除非需要读取文件的最新版本。
虽然你的应用的开放性容器可能不会被其他应用访问,过分的文件协调仍然可能成为 iCloud 的一个问题,执行太多的协调请求会造成类似 ubd 的进程的问题。在应用启动阶段,ubd 似乎会扫描开放性容器内的所有文件。如果你的应用在程序启动阶段也在执行相同的扫描。两个进程会经常冲突,从而可能导致协调的高开销。这时考虑更优化的解决方案是明智的。例如扫描目录内容时,单独的文件内容访问权限是根本不需要的。把协调工作延迟到文件内容真正被展示的时候再进行会是不错的选择。
最后,绝对不要协调一个还没有被下载的文件。文件协调会触发对该文件的下载。不幸的是,协调将会一直等待直到下载完成,这有可能会导致应用被锁住很长一段时间。访问一个文件之前,应用应该先检查文件下载状态。你可以通过查询 URL 的 NSURLUbiquitousItemDownloadingStatusKey 的值或使用 NSMetadataQuery 做到这一点。
协调方法的几个备注
阅读 NSFileCoordinator 的文档,你可能注意到每个方法都有一个冗长而复杂的描述。虽然 API 文档通常是非常可靠的,但由于同其他协调器和文件展示者交互的多样性,以及文件夹和文件锁的语法多样性,都造成了很高的复杂度。有一些很容易忽略的细节和问题贯穿这些长长的描述:
1. 认真选择协调选项。它们真的对文件协调器和文件展示者有着影响。比如,如果没有采用 NSFileCoordinatorWritingForDeleting 标识,文件展示者将无法通过 accommodatePresentedItemDeletionWithCompletionHandler: 对文件删除操作做出影响。如果移动目录时不使用 NSFileCoordinatorWritingForMoving,则移动操作将不会等待其子项目上正在执行的协调操作进行完成。
2. 始终认为协调调用可能会失败并返回错误。因为文件协调同 iCloud 交互,如果被协调的文件不能被下载,协调调用会失败并产生一条错误信息,并且你实际的文件操作可能不会被执行。如果没有正确的实现错误处理方法,你的应用可能不会注意到这样的问题。
3. 在进入协调 block 之后检查文件状态。协调请求之后,也许很长时间已经过去了。这时,应用操作文件的前提条件可能已经失效。你想写入的信息直到重新获得锁之前有可能都是脏数据。也可能在你等待获得写入权限的时候文件已经被删除。这时你可能会无意中再次创建已经被删除的文件。
实现 NSFilePresenter 的通知处理方法需要特别注意。类似 relinquishPresentedItemToReader: 这样的通知处理方法必须被确认及告知其他进程该文件已经对访问准备就绪。这一般通过执行作为参数传入通知处理方法的确认 block 来完成。确认 block 被调用之前,其他进程不得不等待,了解这一点是尤为重要的。如果确认因为通知处理的缓慢而被延迟,协调进程也许会被搁置。如果一直没有被执行,则可能会永远被挂起。
不幸的是,需要被确认的通知也会被其他完全独立的通知拖慢。为了确保通知以正确的顺序执行,presentedItemOperationQueue 一般被设置为一个顺序执行队列。但是一个顺序队列就意味着处理速度慢的通知会延缓随后的通知。尤其是它们会延缓需要确认的通知,在那之前,所有的进程都将等待。
例如,假设一个 presentedItemDidChange 通知首先进入队列。该回调漫长的处理过程将会延缓其他随后进入队列的通知,比如 relinquishPresentedItemToReader:。因此,该通知的确认也会被延迟,从而也导致等待它的进程被延缓。
综上所述,在展示队列里的时候 永远不要 执行文件协调。实际上,即使简单的不需要任何确认的通知 (比如 presentedItemDidChange) 也会导致死锁。设想两个文件展示者同时在展示同一个文件。两个展示者都通过执行协调的读取操作来处理 presentedItemDidChange 通知。如果文件发生改变,通知被发送到两个展示者并且二者都在同一个文件上执行协调的读取操作。因此,两个展示者都通过入队一个 relinquishPresentedItemToReader: 请求对方释放文件并等待对方确认。不幸的是,两个展示者无法确认通知,因为它们都因为永久的等待对方确认的协调请求而阻塞了它们的展示队列。我们在上提供了一个小例子展示这种死锁。
从通知中得出正确结论并不容易。文件展示中存在的 bug 造成了有些通知处理器从未被执行。这里初步介绍一些已知的不太规律的通知:
1. 除了 presentedSubitemDidChangeAtURL: 和 presentedSubitemAtURL:didMoveToURL:,所有的子项目通知要么不被调用,要么以一种难以预测的方式被调用。绝对不要依赖它们 & 实际上,presentedSubitemDidAppearAtURL: 和 accommodatePresentedSubitemDeletionAtURL:completionHandler: 从不会被调用。
2. 只有通过使用了 NSFileCoordinatorWritingForDeleting 的文件协调来删除文件,accommodatePresentedItemDeletionWithCompletionHandler: 才会工作。否则,你会连一个 change 的通知都收不到。
3. 只有文件展示者执行 itemAtURL:didMoveToURL: 时,presentedItemDidMoveToURL: 和 presentedSubitemAtURL:didMoveToURL: 才会被调用。否则项目不会收到任何有用的通知。子项目仍旧会分别针对旧的和新的 URL 收到 presentedSubitemDidChange 通知。
4. 即使文件被正确移动,presentedSubitemAtURL:didMoveToURL: 通知也被发送,你仍然会针对旧的和新的 URL 收到两个额外的 presentedSubitemDidChangeAtURL: 通知。要做好准备好处理这个。
一般来说,你必须注意通知可能会失效。也不应该依赖于任何特定的通知顺序。例如,当描述一个目录树时,你不能期望父文件夹的通知会先于或晚于其中子项目的通知。
注意 URL 变化
在文件协调和文件展示者传递参照着相同文件的不同的 URL 时,有几种你需要应对的情况。你绝不应该使用 isEqual: 比较 URL,因为两个不同的 URL 可能关联同一个文件。应该始终在比较之前标准化它们。这一点在 iOS 上尤为重要,在 iOS 中开放性容器存储在 /var/mobile/Library/Mobile Documents/ 中,这个文件夹是 /private/var/mobile/Library/Mobile Documents/ 的符号链接。你会收到带有指向同一个文件,基于 两种路径变体 的 URL 的展示者通知。如果你对 iCloud 和本地文档使用文件协调代码,这个问题在 OS X 上也会发生。
除此之外,还有几个关于大小写不敏感的文件系统的问题。如果文件系统要求,应该始终确保你使用大小写不敏感的文件名比较。文件协调 block 和展示者通知可能传递使用不同大小写的相同的 URL 变体。实际上,这是使用文件协调器重命名时的重要问题。为了搞懂这个问题,你需要回顾文件实际上是如何被重命名的:
[coordinator&coordinateWritingItemAtURL:sourceURL&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&options:NSFileCoordinatorWritingForMoving&&&&&&&&&&&&&&&&&&&&&&&&writingItemAtURL:destURL&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&options:0&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&error:NULL&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&byAccessor:^(NSURL&*oldURL,&NSURL&*newURL)&{&&&&&[NSFileManager.defaultManager&moveItemAtURL:oldURL&toURL:newURL&error:NULL];&&&&&[coordinator&itemAtURL:oldURL&didMoveToURL:newURL];&}];&
假设 sourceURL 指向一个名为 ~/Desktop/my text 的文件,destURL 使用了大写字母的新文件名 ~/Desktop/My Text。协调 block 被有意设计成传入两个 URL 的最新版本,以兼容等待文件访问时发生的移动操作。现在,不幸的,当改变文件名的大小写,文件协调所执行的 URL 校验将会发现新旧两个 URL 都存在一个有效文件,而新的 URL 是小写 ~/Desktop/my text 的变体。访问 block 将会接收到同样的 小写 URL 作为 oldURL 和 newURL,导致移动操作失败。
在 iOS 中,触发从 iCloud 的下载是应用的责任。可以通过 NSFileManager 的方法触发下载。如果你的应用设计成自动下载文件 (也就是不由用户触发),你应该始终在一个顺序后台队列中执行这些下载请求。换句话说,每一个单独的下载请求涉及到相当多的进程间通信并可能会很耗时。另一方面,同时触发太多的下载有时会过载 ubd 守护进程。一个普遍的错误就是使用 NSMetadataQuery 等待 iCloud 中的新文件然后自动触发下载它们。因为查询结果总是在主队列中传递并且可能包含一打的更新信息,直接触发下载会阻塞应用很长一段时间。
为了查询某个文件的下载或者上传状态,你可以使用 NSURL 的资源值。在 iOS 7 / OS X 10.9 之前,一个文件的下载状态通过 NSURLUbiquitousItemIsDownloadedKey 来确认。根据头文件文档,这个资源值从未正确生效过,所以在 iOS 7 和 Mavericks 中被废弃了。现在苹果建议使用 NSURLUbiquitousItemDownloadingStatusKey。在老系统上,你应该使用 NSMetadataQuery 查询 NSMetadataUbiquitousItemIsDownloadedKey 来获得正确的下载状态。
为你的应用增加 iCloud 支持并不只是你增加的另一个功能,而是一个对应用设计和实现有着深远影响的决定。它既影响着你的数据模型也影响着 UI。所以不要低估支持 iCloud 所需要做出的努力。
最重要的,增加 iCloud 会引入一个新的异步层。应用必须能够在任何时候处理文档和元数据的变化。这些变化上的通知可能会在不同线程上收到,这就需要在你的整个应用中添加同步机制来对这些通知进行适当的处理。你需要注意那些对于用户文档完整性有重大影响的关键代码中的问题,比如丢失更新,竞争和死锁等。
始终注意 iCloud 的同步保证是非常脆弱的。你只能假设文件和包是自动同步的。但你不能期望多个同时被修改的文件也会被立刻同步。比如,如果你的应用分开存储元信息和实际的文件的话,你一定要能够应对元信息会先于或晚于实际文件被下载的情况。
使用 iCloud 文档同步同时也意味着你正在做一个发布的应用。你的文档会在运行着不同版本的不同设备上。你可能想要使你文件格式的不同版本向前兼容。起码,你必须确保你的应用在面对其他不同设备上安装的新版本应用创建的文件时不会崩溃或发生错误。用户未必会立刻更新所有的设备,所以预先准备好这个问题。
最后,你的 UI 需要反映同步行为。即使这会抹杀掉一些神奇之处。尤其在 iOS 上,连接失败和缓慢的文件转换是现实状况。你的用户应该被通知关于文档的同步状态。你应该考虑展示文件是在被上传还是在下载,以告知用户他们的文档现在是否可用。使用大文件时,你可能需要显示文件传输进度,你的 UI 应该优雅一些; 如果 iCloud 不能及时给你某个文档,你的应用应该响应,并且让用户重试或至少放弃操作。
因为涉及到多系统服务和外部服务,调试 iCloud 问题非常困难。Xcode 5 提供的 iCloud 调试功能非常有限并且大多数时候只会告诉你 iCloud 是否已经同步。幸运的是,还有一些差不多是官方的方法来调试 iCloud 文档存储。
在 OS X 上调试
有时你可能经历过 iCould 停止同步某个文件或干脆完全停止工作。实际上,这在文件协调器内使用断点或在一个文件操作进行期间杀掉一个进程时很容易发生。甚至如果你的应用在某个关键点崩溃后也会发生。通常来说,重启或者注销后重新登录 iCloud 都不能修复这个问题。
为了修复这些锁定,一个命令行工具会非常有好处: ubcontrol。这个工具是 10.7 以后版本 OS X 的一部分。使用命令 ubcontrol -x,你能够重置文档同步的本地状态。它通过重置一些私有数据库和缓存,重启所有涉及到的系统守护进程,来复原熄火的同步。同时它也会存储一些报告分析信息到 ~/Library/Application Support/Ubiquity-backups。
虽然已经有日志文件被写入 ~/Library/Logs/Ubiquity 中,你也还可以通过 ubcontrol -k 7 来增加日志级别。在进行 iCloud 相关的错误报告时,苹果工程师经常会要求你这么做以便收集信息。
为了调试文件协调,你还可以从文件协调守护进程中直接取回锁状态信息。这使你能够得知在应用中或多进程间可能遇到的文件协调死锁。为了访问这个信息,你需要在终端中执行以下命令:
sudo&heap&filecoordinationd&-addresses&NSFileAccessArbiter&sudo&lldb&-n&filecoordinationd&po&[&address&&valueForKey:&@&rootNode&]&
第一个命令会返回一个文件协调守护进程的内部单例对象的地址。随后,你关联 lldb 到运行的守护进程上。通过使用第一步取回的地址,你将会得到一个所有活动的锁和文件展示者的状态的概览。调试命令会展示当前正在被展示或协调的整个文件树。例如,如果 TextEdit 正在展示一个名为 example.txt 的文件,你会得到以下跟踪信息:
example.txt&&&&&&NSFileAccessNode&0x&&&parent:&0x&,&name:&&example.txt&&&&&&presenters:&&&&&&&&&&NSFilePresenterProxy&&&&client:&TextEdit&&&&&&&&&&&&location:&0x7f9f&&&&&access&claims:&&none&&&&&&progress&subscribers:&&none&&&&&&progress&publishers:&&none&&&&&&children:&&none&****&
如果你在文件协调进行时创建这种跟踪 (比如通过在文件协调 block 中设置断点),你还会得到一个等待文件协调器的所有进程的列表。
如果通过 lldb 观察文件协调,你应该始终记得尽快执行 detach 命令。否则,全局根进程文件协调守护进程将一直等待,这会影响到系统中几乎所有的应用。
在 iOS 上调试
在 iOS 上,调试要更加复杂,因为你无法检查运行的系统进程,你也无法使用像 ubcontrol 的命令行工具。
iCloud 锁定在 iOS 上似乎更经常发生。重启应用或设备都无效。唯一有效的修复这种问题的方法是 冷启动。在冷启动过程中,iOS 似乎进行了 iClouds 的内部数据库重置。可以通过同时按下电源键和 home 键 10 秒钟冷启动设备。
为了在 iOS 上激活更详细的日志,在苹果 有一个专用的 iCloud 日志概述。如果搜索 &Bug Reporter Logging Profiles (iOS)&,你将会找到一个叫做 &iCloud Logging Profile& 移动设备概述。在你的 iOS 设备上安装该文件来激活更详细的日志。你可以用 iTunes 同步设备来访问这些日志.随后,你可以在 Library/Logs/CrashReporter/Mobile Device/&Device Name&/DiagnosticLogs/Ubiquity 文件夹找到它。如果想要关掉这种加强的日志输出,从设备删除描述文件即可。苹果建议你在激活或关闭概述前重启设备。
在 iCloud Servers 上调试
除了在你自己的设备上调试,考虑使用苹果服务上的调试服务可能也会有用。上有一个特殊的 web 应用,它允许你浏览存储在开放性容器内的所有信息和当前传输状态。
过去的几个月,苹果还提供了安全地在服务端对所有已连接设备进行 iCloud 重置的方法。更多信息可查看。
CocoaChina是全球最大的苹果开发中文社区,官方微信每日定时推送各种精彩的研发教程资源和工具,介绍app推广营销经验,最新企业招聘和外包信息,以及Cocos2d引擎、Cocos Studio开发工具包的最新动态及培训信息。关注微信可以第一时间了解最新产品和服务动态,微信在手,天下我有!
请搜索微信号“CocoaChina”关注我们!
关注微信 每日推荐
扫一扫 浏览移动版

我要回帖

更多关于 ulysses 的文章

 

随机推荐