在iCloud中存储用户文档
立即解锁
发布时间: 2025-08-17 01:56:41 阅读量: 2 订阅数: 14 

### 在 iCloud 中存储用户文档
#### 1. 问题与解决方案
你可能希望允许应用程序的用户在应用内创建文档,并确保这些文档在用户拥有的所有设备上都能同步显示。为实现这一目标,可使用 `UIDocument` 类。
#### 2. 数据存储注意事项
在使用 iCloud 存储数据时,每个应用都应谨慎考虑存储在用户 iCloud 存储空间中的数据量。仅用户在使用应用时生成的数据才需要保存到 iCloud 存储空间。例如,对于网页浏览器应用,浏览器在设备磁盘上缓存的数据不应存储在云端,因为这些数据并非用户生成,而是应用为提升用户体验而缓存的。若将此类数据存储在 iCloud 中,可能会占用用户付费购买的存储空间,这是不可取的。开发者必须告知用户应用在云端存储的数据内容,若用户不允许使用其云存储空间,则应仅在应用沙盒中本地存储数据。
#### 3. iCloud 存储关键要点
为将 iCloud 存储集成到应用中,并实现用户文档在 iCloud 中的加载和保存,需了解以下关键要点:
1. **无处不在的文件**:存在于用户云存储空间中的文件被称为无处不在的文件,这些文件存储在应用沙盒之外。
2. **子类化 `UIDocument` 类**:必须对 `UIDocument` 类进行子类化以管理用户文档。每个文档都会被分配一个无处不在的 URL 用于加载其内容。在子类中,需实现两个重要方法,以便 iOS 向我们传递数据(当 iOS 从 iCloud 读取数据时),以及我们将数据传递给 iOS 以存储在 iCloud 中。
3. **文件存储位置**:无处不在的文件不一定必须位于应用沙盒中。若要将文件存储在 iCloud 中,只需获取 iCloud 文件夹的直接 URL 并将文件放置在该位置。
4. **文件存在性检查**:在用户的 iCloud 存储空间中创建文件之前,必须先查询 iCloud 存储,以确定该文件是否已存在。
5. **应用标识符**:每个应用都有一个标识符,iCloud 使用该标识符将该应用的 iCloud 文件与用户 iOS 设备上其他应用的文件区分开来。若在多个应用中使用相同的应用标识符,这些应用将能够共享彼此的 iCloud 存储空间。
6. **文件搜索**:可使用 `NSMetadataQuery` 类在当前用户的应用 iCloud 存储中搜索文件。
#### 4. 应用开发步骤
我们将开发一个简单的应用,为用户创建一个文本文件并允许其编辑该文档,同时在后台将文档保存到 iCloud,以便用户在使用相同 iCloud 凭证的其他 iOS 设备上也能查看最新版本的文件。具体步骤如下:
1. **设置配置文件和权限**:为应用设置适当的配置文件和权限。
2. **命名文档**:为文档命名,此处将文档文件命名为 `UserDocument.txt`。
3. **查询文件**:应用启动时,启动元数据查询以查找用户 iCloud 存储中的文件。若文件已存在,则获取其 URL;若文件不存在,则在该 URL 处创建一个空文件。
4. **打开文档**:获取用户 iCloud 存储中文档文件的 URL 后,将该文档打开到 `UIDocument` 子类的实例中。
#### 5. `UIDocument` 类使用要点
使用 `UIDocument` 类时,需掌握以下四个要点:
1. **子类化**:必须始终对该类进行子类化,因为该类本身不知道如何加载其内容或如何将其内容作为数据传递给 iOS 以存储在云端。
2. **初始化**:必须使用文件的 URL 初始化该类。在本示例中,将用户云存储中文件的 URL 传递给该类的指定初始化方法。
3. **重写 `contentsForType:error:` 方法**:在子类中,必须重写 `UIDocument` 的 `contentsForType:error:` 实例方法。该方法的返回值可以是所管理文档的 `NSData` 快照。例如,若传递给文档类初始化方法的是文本文件的 URL,则需将该文本(假定为 `NSString` 形式)转换为 `NSData` 并返回该数据。
4. **重写 `loadFromContents:ofType:error:` 方法**:必须重写 `UIDocument` 子类的 `loadFromContents:ofType:error:` 实例方法。在该方法中,iOS 会将数据(可能是从云存储中读取的)传递给我们,我们必须将该数据读取为文本(若文档管理的是文本)。
#### 6. 子类化 `UIDocument` 类步骤
假设应用已完成 iCloud 设置,接下来开始对 `UIDocument` 类进行子类化。我们将在用户的 iCloud 存储中为应用创建一个 `Documents` 文件夹(若该文件夹尚不存在),然后在该文件夹中读取和存储名为 `UserDocument.txt` 的文件。具体步骤如下:
1. 在 Xcode 中,选择 `File → New → New File...`。
2. 在 `New File` 对话框中,确保左侧选择了 `iOS` 类别下的 `Cocoa Touch` 子类别,然后在对话框右侧选择 `Objective - C class` 项并点击 `Next` 按钮。
3. 在下一个屏幕中,将新类命名为 `CloudDocument`,并确保正在子类化 `UIDocument`,完成后点击 `Next` 按钮。
4. 在下一个对话框中,选择保存新类的位置并点击 `Create` 按钮。
#### 7. 定义协议和初始化方法
为了让文档在 iOS 从 iCloud 下载新版本数据时通知委托对象,我们需要定义一个协议和新的指定初始化方法。以下是在文档的头文件中定义的内容:
```objc
#import <UIKit/UIKit.h>
@class CloudDocument;
@protocol CloudDocumentProtocol<NSObject>
- (void) cloudDocumentChanged:(CloudDocument *)paramSender;
@end
@interface CloudDocument : UIDocument
@property (nonatomic, strong) NSString *documentText;
@property (nonatomic, weak) id<CloudDocumentProtocol> delegate;
/* Designated Initializer */
- (id) initWithFileURL:(NSURL *)paramURL
delegate:(id<CloudDocumentProtocol>)paramDelegate;
@end
```
上述代码中:
- `CloudDocumentProtocol` 协议:文档的委托对象必须遵循该协议,以便及时了解通过 iCloud 同步到用户当前设备的文档的更改情况。
- `documentText` 字符串:用于存储文档的内容。用户将需要初始化文档的文件 URL 传递给类的指定初始化方法,`UIDocument` 类会为我们读取该 URL 的内容并将文件数据传递给类,我们只需将该数据转换为文档管理的格式(这里是 `NSString`)。
- `initWithFileURL:delegate:` 指定初始化方法:该方法与超类的指定初始化方法类似,但额外需要一个委托对象作为参数。当 iOS 为我们管理的文档从 iCloud 下载新内容时,我们会更新委托对象。
以下是该初始化方法的实现:
```objc
- (id) initWithFileURL:(NSURL *)paramURL
delegate:(id<CloudDocumentProtocol>)paramDelegate{
self = [super initWithFileURL:paramURL];
if (self != nil){
if (paramDelegate == nil){
NSLog(@"Warning: no delegate is given.");
}
_delegate = paramDelegate;
}
return self;
}
- (id) initWithFileURL:(NSURL *)paramURL{
return [self initWithFileURL:paramURL
delegate:nil];
}
```
#### 8. 重写关键方法
接下来,我们需要重写 `contentsForType:error:` 和 `loadFromContents:ofType:error:` 方法。
`contentsForType:error:` 方法的实现如下:
```objc
- (id) contentsForType:(NSString *)typeName
error:(NSError *__autoreleasing *)outError{
if ([self.documentText length] == 0){
self.documentText = @"New Document";
}
return [self.documentText dataUsingEncoding:NSUTF8StringEncoding];
}
```
该方法在 iOS 需要读取文档内容以存储到 iCloud 或呈现给用户时被调用。若当前管理的文本为空,我们会设置一个默认文本,确保用户创建新文档时屏幕上至少显示一些内容。
`loadFromContents:ofType:error:` 方法的实现如下:
```objc
- (BOOL) loadFromContents:(id)contents
ofType:(NSString *)typeName
error:(NSError *__autoreleasing *)outError{
NSData *data = (NSData *)contents;
if ([data length] == 0){
self.documentText = @"New Document";
} else {
self.documentText = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
}
if ([_delegate respondsToSelector:@selector(cloudDocumentChanged:)]){
[_delegate cloudDocumentChanged:self];
}
return YES;
}
```
该方法在 iOS 读取用于初始化文档实例的 URL 内容时被调用。我们将传递的数据转换为字符串,并在委托对象设置且能响应 `cloudDocumentChanged:` 方法时通知委托对象文档内容已更改,以便委托对象更新 UI 等。
#### 9. 视图控制器中的操作
在视图控制器中,我们需要完成以下操作:
1. **获取 iCloud 文档目录 URL**:我们需要找到为用户创建的 `UserDocument.txt` 文件在 iCloud 中的路径。使用 `NSFileManager` 的 `URLForUbiquityContainerIdentifier:` 方法,并在应用的根 iCloud 目录中创建 `Documents` 目录(若不存在)。以下是实现该功能的方法:
```objc
- (NSURL *) urlForDocumentsDirectoryIniCloud{
NSURL *result = nil;
#error Replace this with your own Team ID
NSString *teamID = @"TEAM ID";
NSString *containerID = @"com.pixolity.Storing-User-Documents-in-iCloud";
NSString *teamIDAndContainerID = [NSString stringWithFormat:@"%@.%@",
teamID,
containerID];
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSURL *iCloudURL = [fileManager
URLForUbiquityContainerIdentifier:teamIDAndContainerID];
NSURL *documentsFolderURLIniCloud =
[iCloudURL URLByAppendingPathComponent:@"Documents"
isDirectory:YES];
/* If it doesn't exist, create it */
if ([fileManager fileExistsAtPath:[documentsFolderURLIniCloud path]] == NO){
NSLog(@"The documents folder does NOT exist in iCloud. Creating...");
NSError *folderCreationError = nil;
BOOL created = [fileManager createDirectoryAtURL:documentsFolderURLIniCloud
withIntermediateDirectories:YES
```
0
0
复制全文
相关推荐










