Keynote 内置共享和多人协作功能。点击菜单栏的「共享」->「发送副本」可以将当前表格文件的副本以邮件、AirDrop 等方式发送出去。点击菜单栏的「共享」->「与其他人协作...」或点击工具栏的「协作按钮」可以将邀请其他用户共同参与当前表格的编辑,发送者可以设置文件的访问权限,以防被不具有修改权限的访问者意外修改了文件内容。这一功能在其他的 Apple 自带软件中都有,在文件协作者也是使用 Apple 设备的情况下可以非常方便地进行多人协作。
母版编辑状态下,在左方导航栏右键单击幻灯片可以为母版重命名,便于后续使用时进行区分。母版编辑界面中默认开启了标尺的显示,可以拖拽基准线辅助对齐,在自带的母版设计中可以看到 Apple 也是通过这种方式来对齐对象的。在母版中添加的对象默认是不能够由使用者改变的,如果需要设置为占位符,需要选中对象后,在右侧检查器的「格式」->「样式」页中,勾选「定义为文本(媒体)占位符」,使用者才能够在使用母版时对定义为占位符的对象进行修改,没有被定义为占位符的对象都是不能够直接修改的,需要在母版编辑状态下才能修改。占位符的「显示」框的内容是用来展示给使用者的内容,可以自行设置。
Keynote 还提供了一个类似「Time Machine」的版本复原功能,它会定期对文件的快照进行备份,供用户回到文件过去的状态。依次点击菜单栏「文件」->「复原到」->「浏览所有版本...」,可以看到当前的表格文件以类似于 Time machine 的方式呈现出来,点击上下箭头或右方的时间轴可以选择回退的时间。这一功能相当于给了用户一颗“后悔药”,即使在改错内容的情况下,也能够还原到出错之前的版本。
总结
作为 Apple 官方御用的幻灯片制作软件,Keynote 承担了 Apple 所有发布会的幻灯片制作,甚至其他品牌的产品发布会的幻灯片也可能是使用 Keynote 制作的。Keynote 凭借其强大的功能和简单易上手的特性,使得制作酷炫的幻灯片不再是设计高手的专利,而是每个人都可以做到的事情。对于普通用户来说,Keynote 或许是 Microsoft PowerPoint 的绝佳替代品,丰富的动画效果和能够快速上手的使用体验,这可能是 Apple 在办公软件领域打的唯一一场“胜仗”。当然,熟练使用 PowerPoint 可以实现更加复杂的幻灯片设计,两款软件并没有明显的优劣之分——都是工具,唯手熟尔。
使用 Apple 设备的各位在以后需要制作幻灯片的时候,不妨考虑一下这个 Apple 的御用软件,说不定你也能做一份 Apple 风格的演示文稿呢。
系统内部进行消息传递的通知,实现了观察者模式。iOS 的实现方式是需要在通知中心(NotificationCenter)中注册通知,告诉通知中心需要向哪些对象发送通知,然后在需要的时候 post 相应的通知即可。对于接收通知的对象,可以选择仅接收自己感兴趣的通知。区分不同通知的方法是采用字符串或枚举作为通知的 id。
NotificationCenter
NotificationCenter 是一种通知的分发机制,可以向已注册的观察者进行信息的广播(A notification dispatch mechanism that enables the broadcast of information to registered observers)。
可以看到,在主线程调用 post 发出通知后,会立即在 post 的线程上同步执行 selector。如果在主线程上发出通知后执行的操作比较耗费时间,需要将耗时任务分到异步线程中执行,例如:
@objc private func downloadImage(notification: Notification) {
// 使用 GCD 将任务放入全局异步线程中
DispatchQueue.global().async {
// userInfo is used to transfer user defined data
let userInfo = notification.userInfo as! [String:Any]
let value1 = userInfo["username"] as! String
let value2 = userInfo["id"] as! Int
print("\(self.name)获取到通知,用户名:\(value1), 密码:\(value2)")
sleep(3)
print("\(self.name)执行完毕")
}
}
// create an instance of notification center
let nc = NotificationCenter.default
// fetch the main queue
let queue = OperationQueue.main
// add an observer which listens to the UIApplicationDidEnterBackground notification.
let observer = nc.addObserver(forName: .UIApplicationDidEnterBackground, object: nil, queue: queue) {
noti in
print("Entering background...")
}
Create a trigger. Depending on the situation that triggers a notification, select a different constructor.
Create the content of the notification, using UNMutableNotificationContent.
Create the request, using the trigger and content above.
Add the request to the notification center, using UNUserNotificationCenter.current().add()
Remember to ask the user for permission to show notification.
To provide attachment, use the UNNotificationAttachment class to add attachment to the notification.
To add an action in the notification, use UNNotificationAction and UNNotificationCategory
Create the action for the notification
Defines the category of the action
Just to remind: the majority of notification needs an identifier. Do not mess them up! It is recommended to use enum or at least constants to manage these identifiers.
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
if let error = error {
// Handle the error here.
}
// Enable or disable features based on the authorization.
if granted {
// user permit
} else {
// user deny
}
}
let center = UNUserNotificationCenter.current()
center.getNotificationSettings { settings in
guard (settings.authorizationStatus == .authorized) ||
(settings.authorizationStatus == .provisional) else { return }
if settings.alertSetting == .enabled {
// Schedule an alert-only notification.
} else {
// Schedule a notification with a badge and sound.
}
}
// Create the request
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString,
content: content, trigger: trigger)
// Schedule the request with the system.
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.add(request) { (error) in
if error != nil {
// Handle any errors.
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler:
@escaping () -> Void) {
// Get the meeting ID from the original notification.
let userInfo = response.notification.request.content.userInfo
let meetingID = userInfo["MEETING_ID"] as! String
let userID = userInfo["USER_ID"] as! String
// Perform the task associated with the action.
switch response.actionIdentifier {
case "ACCEPT_ACTION":
sharedMeetingManager.acceptMeeting(user: userID,
meetingID: meetingID)
break
case "DECLINE_ACTION":
sharedMeetingManager.declineMeeting(user: userID,
meetingID: meetingID)
break
// Handle other actions…
default:
break
}
// Always call the completion handler when done.
completionHandler()
}
示例代码
最后贴一段示例代码吧(部分来源 Apple Developer 官网):
AppDelegate.swift
import UIKit
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// 设置 UserNotifications 代理
UNUserNotificationCenter.current().delegate = self
// 请求本地推送的权限
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
if let error = error {
print("Oops, we've met an error: \(error)")
}
if granted {
print("The user grants us the permission to push notifications😃")
} else {
print("The user denies our permission😣")
}
}
return true
}
}
// 代理方法
extension AppDelegate: UNUserNotificationCenterDelegate {
public func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
print(response.actionIdentifier)
completionHandler()
}
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
// New in iOS 10, we can show notifications when app is in foreground, by calling completion handler with our desired presentation type.
print("something")
// 设置提醒的方式:.alert, .sound, etc
completionHandler(.alert)
}
}
ViewControler.swift
import UIKit
import UserNotifications
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// 设置推送内容
let content = UNMutableNotificationContent()
content.title = "This is title"
content.subtitle = "This is subtitle"
content.body = "This is body"
content.sound = UNNotificationSound.default
// 定义用户交互方式
let acceptAction = UNNotificationAction(identifier: "ACCEPT_ACTION",
title: "Accept",
options: UNNotificationActionOptions(rawValue: 0))
let declineAction = UNNotificationAction(identifier: "DECLINE_ACTION",
title: "Decline",
options: UNNotificationActionOptions(rawValue: 0))
// 定义推送能够响应的交互类别
let meetingInviteCategory =
UNNotificationCategory(identifier: "MEETING_INVITATION",
actions: [acceptAction, declineAction],
intentIdentifiers: [],
hiddenPreviewsBodyPlaceholder: "",
options: .customDismissAction)
// 向通知中心注册交互类别
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.setNotificationCategories([meetingInviteCategory])
content.categoryIdentifier = "MEETING_INVITATION"
// 设置一个 10 秒的触发器
// 若希望重复提醒(repeats 为 true),则两次推送的时间间隔(timeInterval)必须大于 60,否则会崩溃。
let tenSecondsTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
let request = UNNotificationRequest(identifier: "tenSeconds", content: content, trigger: tenSecondsTrigger)
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
print(error)
} else {
print("Notification request added.")
}
}
}
}
「整理生活」是一项技术活,每个人都应该有一套属于自己的方法,帮助自己管理生活中的大事小事。对于我来说,充分利用原生 app 来帮助自己安排每天要做的事情,然后倾注全部的精力完成好手上的工作,可能是最适合我的工作流:备忘录作为我的电子笔记本,能够帮助我记录下重要的想法、灵光一现的 idea 和学习笔记;提醒事项和日历会在适合的时间提醒我应该做什么事情,让我不再需要分心记住接下来有哪些事情要做;番茄钟能够保持我对手头任务的专注度,不被其他不重要的事情打断。
在进入大学之前,爸妈为我添置了我的第一台笔记本电脑——2015年款的13.3寸Retina MacBook Pro,那个时候这台笔记本刚刚上市,售价 8k+,让当时的我着实吃了一惊,没有想到爸妈会给我买一台这么贵的电脑(谢谢爸妈😊)。那时候的我对电脑系统接触得不多,也不知道 MacBook 的系统和其他电脑的系统是不一样的,因此也没有对 Windows 系统有强烈的依赖,很顺利地就过渡到了 Mac 的系统中(当时还是 OS X Yosemite)。爸妈的同事还贴心地帮我用 Boot Camp 安装了双系统 Windows,这为我后面的学校课程学习提供了不小的帮助。
众所周知,2015 年的 MacBook Pro 的视网膜屏存在涂层脱落的问题,在我得知这个消息的时候电脑已经使用了三年了,于是抱着试一试的心态,预约前往广州天环广场的 Apple Store 咨询了一下这个问题。Genius Bar 的小哥很爽快地就直接给我换了,大概只花了半天的时间就换好了屏幕,看上去就跟换了一台新的电脑一样。虽然现在好像又出现了涂层脱落的问题,但是影响不算特别大,将就着用了。换完屏幕后,我又为我的爱机贴上了贴纸,贴完之后简直就是一台新机器了有!没!有!
当然啦,毕竟是四年前的机器了,这台电脑也存在一定的问小毛病包括电池状况不佳、键盘磨损等,打算在疫情结束之后去 Apple Store 看看能不能解决,让这台笔记本继续发光发热吧!
作为我的第二台 Apple 设备,iPhone 的加入使得 MacBook Pro 和 iPhone 两者之间的生态链更加完整,两台设备之间可以进行更加紧密的协作,包括 iCloud、Handoff、AirDrop 等技术都极大地提高了我的工作学习效率。感兴趣的朋友可以关注一下我的知乎专栏。
和 MacBook 一样,手机用久了也会有不少的毛病。2019 年的时候我在 Apple Store 为手机更换了电池后,明显感觉到手机的流畅度有一定程度的提升,续航时间也得到了保证。希望这台手机也能够陪伴我走完研究生的生涯吧!
Apple Watch Series 3
Apple Watch 对我来说是个意外的收获——朋友送的。在对 Apple 的产品有了一定的使用经验后,我对 Apple Watch 也有了一定的期待。这只 Apple Watch Series 3 是GPS 版的,需要配合手机才能有更好的使用体验,但是这对我来说并不是一个问题,毕竟手机是 24 小时都在身边的。我对于 Apple Watch 的使用主要包括:
看时间,这是一只手表的基本素养。
记录自己每天的运动消耗和锻炼时间。
当作闹钟和计时器。
转发 iPhone 上的通知,可以不用拿出手机扫一眼是不是重要的事情。
实在腾不出手的情况下可以接电话。
提醒自己每隔一段时间进行一次深呼吸和站立。
找不到手机的时候,可以通过 Apple Watch 使手机发出声音,对于我这种大头虾来说是一个非常实用的功能。
作为一件奖励自己 2019 年表现的礼物,iPad 2019 是真正意义上自己花钱买的第一台 Apple 设备。自从进了 Apple 的坑以后,就愈发想凑齐 Apple 的不同设备,体验到更加完美的苹果生态圈。由于是花自己的钱买的设备,极其有限的预算让我把目光瞄向了最便宜的 iPad —— iPad 2019。
在确定购买哪一款 iPad 之前,我也经历过一段非常纠结的时光,在 iPad Air 3 和 iPad 2019 之间举棋不定。不少人觉得 iPad 2019 是一台「智商机」,但是我认为,对于预算确实非常有限的消费者来说,iPad 2019 在实际的使用体验上已经足够好了:足够大的 10.2 寸屏幕、对于学习来说足够能打的 A10 芯片、能够使用 Apple Pencil,种种因素都令我对手上的这台机器心满意足。使用 Apple Pencil 在 iPad 上写字的时候,其实并不会感觉到非全贴合屏带来的影响,虽然反光比较严重,但是调整角度后还是能够克服的。当然我还是觉得如果预算不是决定购买 iPad 的第一要素、或者不介意小屏幕的话,iPad Air 3 和 iPad mini 5 绝对是性价比更高的选择。
长文、多图预警。
知乎小透明一枚,居然有人翻牌让我深入写写 iWork 软件的使用教程🤣那么我就分三篇文章来写写 Pages、Numbers 和 Keynote 三款 Apple 平台办公软件的基础和进阶使用教程吧!
我为什么把目光投向了 Numbers
作为一名手持 Apple 全家桶的(伪)果粉,我认为 Apple 自家软件都有着不错的设计,抱着一种「能用自带的就避免下载第三方软件」的心态,我尝试着将 Apple 平台的自带软件充分利用起来。在 iPhone、iPad 和 Mac 上,Apple 已经为消费者提供了许多优秀的应用软件,使消费者在机器到手的时候就已经能够应付日常生活的各种任务了。
Numbers 内置共享和多人协作功能。点击菜单栏的「共享」->「发送副本」可以将当前表格文件的副本以邮件、AirDrop 等方式发送出去。点击菜单栏的「共享」->「与其他人协作...」或点击工具栏的「协作按钮」可以将邀请其他用户共同参与当前表格的编辑,发送者可以设置文件的访问权限,以防被不具有修改权限的访问者意外修改了文件内容。这一功能在其他的 Apple 自带软件中都有,在文件协作者也是使用 Apple 设备的情况下可以非常方便地进行多人协作。
例如,我想要在不同部门的分类基础上,查找等级为 A 的员工,则可以在按「部门」分类的基础上,选择「员工等级」「是」「A」的过滤条件。过滤功能同样可以选择多个过滤条件对表格内容进行过滤,点击右侧的垃圾桶图标可以删除该过滤条件,拖拽左侧的横线可以对过滤条件的先后顺序进行排序,表格中的显示会即时进行更新。除此之外,点击「添加规则」还可以对已有的过滤条件追加新的规则,以实现更加复杂的逻辑关系。
创建图表后,点击「添加图表数据」即可选择图表的数据来源,在左下角可以选择「根据列绘制序列」或「根据行绘制序列」,前者以各行的值作为横坐标、各列的值作为纵坐标,后者以各列的值作为横坐标、各行的值作为纵坐标,在使用的时候注意区分。选中图表后,右侧检查器栏会显示对当前选中图表的样式设置:「图表」页包含对图表本身的设置,例如图表选项(标题、图例、边框等)、图表字体、图表颜色等;「坐标轴」页包含对柱状图 X 轴和 Y 轴的标签、刻度线、标度等内容的设置;「扇区」页包含对饼图每一块分区的标签、位置等内容的设置;「序列」页包含对图表一维数据的设置,还可以添加趋势线和误差线等。检查器栏的页签会根据图表类型的不同而发生相应的变化,具体的设置可以自行尝试。
需要注意的是,在 Finder 的「iCloud 云盘」中没有办法直接看到这个目录,必须通过上述方法才能够进入该目录。书籍文件名旁边的小云朵表示该文件只保存在云端而没有保存在本地,通过右键单击书籍文件,选择「现在下载」可以将云端文件下载到本地,或者选择「移除下载项」将本地文件删除而仅保留在云端。在 macOS 端的 iBooks 应用中打开书籍,会自动将云端的书籍文件下载到本地。至于移动端,暂时没有办法手动释放占用的空间。
iBooks 以「书库」和「精选集」的形式来对书籍进行管理,「书库」中的书籍就是你拥有的所有书籍。「精选集」则是自己对分类,一本书籍可以被归类到不同的「精选集」中。这种分类方式类似于 Apple Music 中「资料库」和「播放列表」的关系。在「书库」中,iBooks 还会自动将书籍按照「图书」、「有声书」、「PDF」、「作者」、「类别」等几种不同的方式进行一个简单的分类。
iOS / iPadOS 端的 iBooks 应用界面经过了全新的设计,与其他 Apple 自带的 App 设计风格相近,可以方便地实现书籍的排序、切换视图、编辑等操作。
作为一名有着大量文献阅读需求的工科研究生,我通常是采用「打印 + 电脑」的方式对文献资料进行学习,这里的文献除了期刊论文、学位论文等文章以外,还包括了专业书籍等「大部头」的内容。对于电子版的专业书籍,我通常是在 MarginNote 这款软件上进行学习的,这是一款非常棒的阅读软件,集合了 PDF 阅读器、思维导图、复习卡等多种不同的学习功能,能够帮助我对书籍的知识按照自己的方法重新进行梳理、消化,全方面地对书本知识进行掌握,真正变成自己学到的知识(没有收广告费的呀)。而对于期刊论文,我通常是打印成纸质版,用普通的中性笔和荧光笔进行标注,传统的纸媒让我能够更快地定位到自己感兴趣的部分,从而判断是否需要对这篇文章精读;传统的标注工具从小学就开始使用了,完全不存在使用门槛的问题。
在去年年末购入了 iPad 2019 和 Apple Pencil 后,我尝试着将文献阅读的任务转移到 iPad 上进行,一方面,「iPad + Apple Pencil」的组合能够最大化模拟传统纸笔,在阅读文献的时候能够有更好的体验;另一方面,就我个人来说,在电脑上进行文献阅读还是比较容易受到干扰的,总会一不小心就打开视频、游戏什么的,导致工作流程中断。为了能够充分发挥 iPad 和 Mac 各自的优势,我希望最后达到的效果是在 iPad 上进行文献的阅读、标注,在 Mac 上进行文献的收集和管理,两台设备各司其职,又能够进行同步。
将下载到的 PDF 文件直接拖拽到应用中就能够在,Zotero 会将 PDF 文件复制到默认文档路径中,在 macOS 上的默认路径是 ~/Zotero,可以点击左上方的按钮或者在侧边栏中点击鼠标右键,新建分类或新建文库对文献做进一步的整理。
对于期刊论文等文献,如果是在期刊的官网或者 Google 学术中下载的,大部分是会带有元数据的,这些元数据包括期刊名称、作者、发表时间等。文献的元数据是导出引用格式的基础,Zotero 通过元数据的信息来生成对该文献的应用。对于一些无法读取到元数据的文件,可以在 Zotero 中「右键单击文件」->「创建父条目」,并在下方的信息栏中输入相应的信息。
值得注意的是,分类并不对应硬盘中的实际目录。一份文献可以同时存在于多个不同分类中,但是它们都是对应于同一个 PDF 文件的。对于已经存在于某个分类中的文献,如果将它拖拽到另一个分类中,就会在新的分类下把这个文献添加进去。也就是说,Zotero 的分类系统并不是单纯的树形关系,更像是在给文献打标签,一篇文献可以有多个标签,即一份文献可以存在于多个分类中。
Zotero 内置了不少的引用样式,可以点击「管理样式...」添加新的样式,并且支持自定义样式,通过编辑 XML 文件模板就能够创建自己想要的样式了。选择好想要用的样式后,可以选择将样式导出为 RTF、HTML 或复制到剪贴板。经实测,Zotero 自带的样式管理功能还是比较弱,但是相信在开源社区有功能更加丰富的插件可以选择。
当然,Google 学术也提供了类似的功能。
与 Word 的整合
如果使用 Word 或者 LibreOffice 来完成文章的撰写,Zotero 提供了对应的插件,可以直接将生成的引用插入到文档中。在「首选项」->「引用」->「文字处理软件」中就可以安装 Word 或者 LibreOffice 的插件了。由于我没有使用过这个功能,有需要的读者可以自行查找相关的资料。
General Settings:ZotFile 可以在一个指定的目录内容发生变化的时候,将新的文件自动导入到 Zotero 中。可以专门设置一个文件夹作为中转站,将要导入的文献放进去,ZotFile 就会自动将文献导入到 Zotero 中。
Tablet Settings:ZotFile 可以将文献发送到一个指定的目录中,同时还可以将文献取回来。我们需要勾选「Use ZotFile to send and get files from tablet」,并在「Base Folder」处选择一个文件夹,这个文件夹就是 ZotFile 发送文献的目标位置。为了让这个位置能够被 iPad 读取到,我将它设置成了 iCloud 中的一个目录。最后需要选择的选项是「Create subfolders from zotero collections」,在发送到目标位置后根据文献在 Zotero 分类中的位置创建子文件夹,方便根据自己在 Zotero 中的分类情况来管理文献;「Rename files when they are sent to the tablet」,对原 PDF 进行重命名;「Automatically extract annotations when getting PDFs back from tablet」,自动提取在 iPad 上对文献的标注内容。
Renaming Rules:设置 ZotFile 在发送至目标位置时对原 PDF 文件进行重命名的规则。在网上下载到的 PDF 文件名往往凌乱不堪(尤其是从 arXiv 上下载到的文献),如果有需要的话,可以通过 ZotFile 对文件名进行自动重命名。ZotFile 可以针对专利和专利以外的文件区分不同的命名方式,具体的占位符格式需要参考 ZotFile 的文档。这里我设置的是「文献题目 - 作者」的格式,这样比较方便在同一分类下快速找到自己想要看的文献。
Advanced Settings:高级设置,普通使用下一般无需理会。
实现 iPad 与 Mac 之间的联动
下面简单介绍一下我是如何利用「Zotero + ZotFile + iCloud」的组合来实现文献阅读任务在 iPad 与 Mac 之间的联动的。
移动端负责的是文献阅读与标注,在 Zotero 完成文献的管理后,将想看的文献发送到 iPad 上进行阅读,完成 ZotFile 的设置后,对于我们想要发送到 iPad 上的文献,右键单击,依次选择「Manage Attachments 」->「Send to subfolders on tablet」,就能够将文献按照其在 Zotero 自定义分类中的情况,创建相应的子文件夹,发送到先前设定到的目标位置。
这里其实还有一个选项,直接就是「Send to tablet」,这个选项只会将 PDF 文件发送过去,而不会创建子文件夹,对于一些临时看的文献可以选择该选项。我选择将文献发送到 iCloud 的一个文件夹中,便于在 iPad 上进行访问。发送完成后,可以在 Zotero 的侧边栏发现新增了两个分类,分别为「Tablet Files」和「Tablet Files (modified) 」,前者里面放的就是我们发送到平板上的所有文件(其实这也是类似于打标签)。
发送到 iPad 后,就可以利用各种 PDF 阅读器对文献进行标注。自带的「文件」能够进行简单的批注,实际上手时也发现足够自己使用了,但是有一个我个人不太喜欢的问题,就是「文件」会挡住文献的右边缘,不利于充分利用空间。为了尽可能模拟在纸张上阅读文献的感觉,我找到了一个叫做「PDF Viewer」的免费软件,解决了边缘空白无法利用的问题。
在 iPad 上完成文献的阅读后,进入 Zotero,在「Tablet Files」分类中找到想要取回的文献,右键单击,依次选择「Manage Attachments 」->「Get from Tablet」,就可以将标注后的 PDF 文件重新取回到 Zotero 的文件存储位置,并覆盖原来的文件,使得标注的内容得以同步。标注后的 PDF 文件体积通常会变大不少。
由于有 Apple 的加持,无论是在移动端还是在桌面端,iWork 能够有一致的优秀表现,并且与 iCloud 高度集成,方便用户实现对文档的共享和跨设备编辑。下面笔者将介绍自己是如何在日常的学习和生活中使用 iWork 套件满足自己对文档制作的需求的。
Pages
Pages 对标 Microsoft Office Word,是 iWork 办公套件中的富文本编辑软件。
和大多数的文字处理软件一样,Pages 是一款「所见即所得」的软件,用户在文档中对文字内容、格式作出的任何改变都会直接影响到文档的最终效果,例如对文字的加粗、下划线等。Pages 在操作上与 Word 相差不多,用户可以方便地在右边的格式面板中对文档的格式、布局等作出修改,并在主编辑面板进行文字的编辑。
本文介绍了如何在 Apple 设备上使用 iWork 办公套件满足日常的文档编辑需求。相比于 Microsoft Office 来说,iWork 在功能及兼容性上都存在一定的限制,无法像 Microsoft Office 那样成为「事实上的行业标准」。但是,大而全所付出的代价是运行速度较慢、需要一定的经济成本,对于一些普通的文档编辑任务来说,使用 iWork 已经能够满足要求了,如果需要在不同平台上进行兼容,导出为 PDF 才是最好的选择。
对于需要登录的 app,如果不想采用 Core Data 来进行用户数据的存储,可以考虑将用户的信息以文件的形式保存在本地。当然,如果这么做还需要考虑到文件的加密等安全措施。
Example code:
// This code shows how to combine FileManager
// and NSSearchPathForDirectoriesInDomains to deal with file system.
// create a file manager instance that manages the files in sandbox.
let manager = FileManager.default
// specify the location of directory, using a string-related enum.
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
// grasp the first element of the array, which is the path string.
let testDir = path[0]
print(testDir)
// add more details to system path.
let filePath = testDir + "/folder1"
do {
// call the responding methods to create directories, files, or
// access them.
try manager.createDirectory(atPath: filePath, withIntermediateDirectories: false, attributes: nil)
print("succeed")
} catch {
// deal with errors in the above operation.
print("error")
}