Google+ もご覧ください
ユーザーアイコン

作って学ぶSDKの使い方

Dropbox Sync API SDKを使ってファイルの読み込み、書き込みをしてみる

Hirobe

Dropbox Sync API SDKを使ってファイルの読み込み、書き込みをしてみる

前回からの続きです。今回はDropboxからファイルを読み込み、編集して保存やファイル名の変更を行ってみます。

まず、一覧から選択したら、編集画面に遷移するようにしましょう。SMEditorViewControllerに選択したファイルを渡すためのプロパティを追加し、SMFilesViewControllerから渡すようにします。

SMEditorViewController.hにプロパティを追加します。また、入力フィールドの制御をするためにUITextFieldDelegateを宣言しておきます。

#import <UIKit/UIKit.h>

@class DBPath;

@interface SMEditorViewController : UIViewController <UITextFieldDelegate>
@property (nonatomic) DBPath *dropboxPath;
@end

SMFilesViewController.mに行を選択時のデリゲートとなるメソッドtableView:didSelectRowAtIndexPath:を追加してください。ここで、編集画面となるSMEditorViewControllerを生成し、選択したファイルを渡し、編集画面を表示します。

#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    SMEditorViewController *editorViewController = [[SMEditorViewController alloc]initWithNibName:nil bundle:nil];
    editorViewController.dropboxPath = [[DBPath root] childPath:[self.filesArray objectAtIndex:indexPath.row]];
    [self.navigationController pushViewController:editorViewController animated:YES];
}

さて、編集画面の中身を作りましょう。中身は、ファイル名を入力するフィールドと、テキストの本文を入力するフィールドです。ソースコードを分かりやすくするために必要最低限の制御を記述しているので、飾りっけの無い質素な画面です。

冒頭部は以下のようになります。

#import "SMEditorViewController.h"
#import <Dropbox/Dropbox.h>
#import "MBProgressHUD.h"

@interface SMEditorViewController ()
@property (nonatomic) UITextField *nameField;
@property (nonatomic) UITextView *documentTextView;
@property (nonatomic,copy) NSString *fileText;
@end

viewDidLoadを以下のように書き換えます。viewDidLoadの最後で、ファイルを読み込むために[self loadFile]を呼んでいます。これについては次に説明します。

- (void)viewDidLayoutSubviews
{
    CGSize size = self.view.frame.size;
    self.nameField.frame = CGRectMake(0,0,size.width,44);
    self.documentTextView.frame = CGRectMake(0,44,size.width,size.height-44);
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.nameField = [[UITextField alloc] init];
    self.nameField.borderStyle = UITextBorderStyleLine;
    self.nameField.text = [self.dropboxPath name];
    self.nameField.placeholder = [self.dropboxPath name];
    self.nameField.clearButtonMode = UITextFieldViewModeWhileEditing;
    self.nameField.delegate = self;
    [self.view addSubview:self.nameField];

    self.documentTextView = [[UITextView alloc] init];
    [self.view addSubview:self.documentTextView];

    [self loadFile];
}

ファイルの読み込み

テキストファイルを読み込むには、openFile:で開いた後にreadString:を実行します。テキスト以外のデータを読み込むために、readData:というメソッドもあります。ファイルを閉じるclose:というメソッドもありますが、明示的に呼び出す必要はありません。

ファイルの一覧の取得と同じく、ファイルの読み込み(readString:)も完了まで待ちが発生する可能性があります。メインスレッドで実行すると警告がでるので、スレッドを作成して読み込みます。待ちの間はMBProgressHUDの待ちインジケータを表示して操作できないようにします。

- (void)loadFile
{
    // completedFirstSyncがfalseの間はreadString:が待ちになる。これはファイルごと1回だけ発生します。
    // readString:をメインスレッドで実行すると警告が出ます

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        DBError *error;
        DBFile *file = [[DBFilesystem sharedFilesystem] openFile:self.dropboxPath error:&error];

        // 待ちが発生する場合はprogress dialogを表示(メインスレッド)
        if ([file status] && !(file.status.cached)) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [MBProgressHUD showHUDAddedTo:self.view animated:YES];
            });
        }
        NSString *contents = [file readString:nil];

        // 読み込み完了後の画面表示
        dispatch_async(dispatch_get_main_queue(), ^{
            [MBProgressHUD hideHUDForView:self.view animated:YES];
            self.fileText = contents;
            self.documentTextView.text = contents;
        });

    });
}

ここまでで、ファイルの表示はできるようになります。

ファイルの保存

Backボタンで画面を閉じる際に、テキストが変更されていればファイルに上書き保存することにします。テキストファイルの保存はDBFileのwriteString:を呼び出します。エラーがあればアラートを表示します。

テキストファイルを保存するには、openFile:で開いたとにwriteString:を実行します。テキスト以外のデータを書き込むためのwriteData:というメソッドや、追加書きをするためのappendString:というメソッドもあります。

- (void)viewWillDisappear:(BOOL)animated
{
    if (![self.documentTextView.text isEqualToString:self.fileText]) {
        [self saveFile];
    }
}

- (void)saveFile
{
    DBError *error;
    DBFile *file = [[DBFilesystem sharedFilesystem] openFile:self.dropboxPath error:&error];
    BOOL ret = [file writeString:self.documentTextView.text error:nil];
    if (ret) {
        self.fileText = [NSString stringWithString:self.documentTextView.text];
    }else { // error
        UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Write Error" message:error.description delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
        [alert show];
    }
}

ファイル名の変更(ファイルの移動)

ファイル名の変更やファイルの移動をするには、DBFilesystemのmovePath:toPathを使います。ファイル名フィールドからフォーカスが外れる際に、値が変更されていればファイル名を変更することにします。

textFieldShouldEndEditing:はテキストフィールドの編集終了時に呼び出されるデリゲートです。うまく呼ばれない場合は、ヘッダファイルにUITextFieldDelegateを宣言しているか確認してください。

#pragma mark - text field delegate 

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
    if (textField == self.nameField) {
        return [self renameFile:self.nameField.text];
    }
    return YES;
}

#pragma mark -

- (BOOL)renameFile:(NSString*)newName {
    if ([newName length]==0) {
        self.nameField.text = [self.dropboxPath name];
        return YES;
    }else if ([newName isEqualToString:[self.dropboxPath name]]) {
        return YES;
    }

    // rename
    DBError *error;
    DBPath *newPath = [[DBPath root] childPath:newName];
    BOOL ret = [[DBFilesystem sharedFilesystem] movePath:self.dropboxPath toPath:newPath error:&error];
    if (ret) {
        self.dropboxPath = newPath;

        return YES;
    }else { // error
        UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Rename Error" message:error.description delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
        [alert show];

        return NO;
    }
}

いかがだったでしょうか。Dropbox Sync APIは、ファイルの一覧表示や読み込みにおいてはメインスレッドで実行してはいけないというルールさえ守れば読み込みや書き込み(追記も含めて)が簡単にできるのが分かるかと思います。

Dropboxを使うということはWindowsやMac OSXといった母艦とiOSと容易に連携できるようになります。iPhoneから撮影した写真を送ったり、タブレットでテキストファイルを編集したりと様々な利用が考えられますね。

ぜひこの連載を参考にDropbox Sync APIを使ってみてください。

Sdk
タグ:

記事をリクエストする

関連記事

コメント