Swiftで遊ぼう! on Hatena

あしたさぬきblogでやってた初心者オヤジのiOSプログラミング奮闘記がHatenaに来ました

Swiftで遊ぼう! - 610 - Multiple Managed Object Contextsチュートリアル 14

長ったらしいJournalViewControllerのコードを見ています。

www.raywenderlich.com

クラス宣言のとろこで悩んでしまう人間なのでコードを理解するのは骨が折れます。

ここは素直にチュートリアルで説明されている部分に注目します。実は、データベースの内容を書き出すコードを勉強しているので 「// MARK: - Export」を探すと、コードの後半に4つのメソッドが並んでいます。

  1. activityIndicatorBarButtonItem()
  2. exportBarButtonItem()
  3. showExportFinishedAlertView(exportPath: String)
  4. exportCSVFile()

この中で「exportXCVFile()」を取りあげています。

  func exportCSVFile() {
    
    navigationItem.leftBarButtonItem =
      activityIndicatorBarButtonItem()
    
    // 1
    let results: [AnyObject]
    do {
      results = try coreDataStack.context.executeFetchRequest(
            self.surfJournalFetchRequest())
    } catch {
      let nserror = error as NSError
      print("ERROR: \(nserror)")
      results = []
    }

    // 2
    let exportFilePath =
      NSTemporaryDirectory() + "export.csv"
    let exportFileURL = NSURL(fileURLWithPath: exportFilePath)
    NSFileManager.defaultManager().createFileAtPath(
      exportFilePath, contents: NSData(), attributes: nil)
    
    // 3
    let fileHandle: NSFileHandle?
    do {
      fileHandle = try NSFileHandle(forWritingToURL: exportFileURL)
    } catch {
      let nserror = error as NSError
      print("ERROR: \(nserror)")
      fileHandle = nil
    }

    if let fileHandle = fileHandle {
      // 4
      for object in results {
        let journalEntry = object as! JournalEntry
        
        fileHandle.seekToEndOfFile()
        let csvData = journalEntry.csv().dataUsingEncoding(
          NSUTF8StringEncoding, allowLossyConversion: false)
        fileHandle.writeData(csvData!)
      }
      
      // 5
      fileHandle.closeFile()
  
      print("Export Path: \(exportFilePath)")
      self.navigationItem.leftBarButtonItem =
        self.exportBarButtonItem()
      self.showExportFinishedAlertView(exportFilePath)
    } else {
      self.navigationItem.leftBarButtonItem =
        self.exportBarButtonItem()
    }

  }

このメソッドだけでも複雑に見えてしまいます(T_T)

まず最初の「navigationItem.leftBarButtonItem = activityIndicatorBarButtonItem()」を考えます。実はNavigation Controllerの扱いに慣れていないので少々混乱することがあります。 この「navigationItem」というプロパティは「UINavigationItem」で左側のボタンがUIBarButtonItem型の「leftBarButtonItem」です。しかし、MainStroryboardのナビゲーションバーの左ボタンは「Export」になっていて、これはコード内に「@IBOutlet」付の「UIBarButtonItem型」のプロパティ「exportButton」になっています。

あれ?

実はNavigation Controllerは、VIew Controllerにメニューの「Editor」->「Embed In」->「Navigation Controller」で簡単に組み込むことができるように関連するプロパティも自動的に組み込まれます。したがって、アプリケーションが立ち上がる時にまず、navigationItemが起動して、その上にViewControllerが起動するのに併せてUIBarButoonItem型のexportButtonに切り替わるようです。

コード上のnavigationItemを「Opt + クリック」してみると次のような説明文が出てきます。

f:id:yataiblue:20160311184917j:plain

このNavigation Controller上のBarButtonItemにメソッド「activityIndicatorBarButtonItem()」を使ってBarButtonItemを加えています。このメソッドはカスタムメソッドです。

  func activityIndicatorBarButtonItem() -> UIBarButtonItem {
    let activityIndicator =
      UIActivityIndicatorView(activityIndicatorStyle:
        UIActivityIndicatorViewStyle.Gray)
    let barButtonItem =
      UIBarButtonItem(customView: activityIndicator)
    activityIndicator.startAnimating()
    
    return barButtonItem
  }

アクティビティ・インディケータの使い方は以前、スタンフォードのポール先生の授業にありました。

なんとも理解するのが難しい。中途半端ですが今日はここまで。