引き続き、ImageCell.swiftファイルに手を加えていきます。
以下のように「UIImage?」型の「assetImage」プロパティを追加し、このプロパティを介してクラス外から画像を設定するようにします(7〜10行目までを追加)。
import UIKit class ImageCell: UITableViewCell { @IBOutlet private weak var assetImageView: UIImageView! // ここから var assetImage :UIImage? { willSet { self.assetImageView.image = newValue } } // ここまで追加 override func awakeFromNib() { super.awakeFromNib() // Initialization code } override func setSelected(selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state } }
assetImageプロパティは格納型プロパティです。assetImageプロパティのコードブロック内の「willSet節」(willSet {...})は値が格納される直前に呼び出されます。
格納型プロパティの値が更新されるときに処理が行われる仕組みは「プロパティオブザーバー」と呼ばれ、willSet節以外にも、値が格納された直後に呼ばれる「didSet節」(didSet {...})があります。
ImageCellの実装例では、willSet節を使用して、画像オブジェクトをUIImageViewに設定しています。また、willSet節の仮引数を省略しているので、格納されようとしている新しい値は「newValue」という名前で取得できます。
以下のように仮引数を指定することもできます。
willSet (newImage) { // 処理 self.assetImageView.image = newImage }
ImageCell.swiftファイルの修正は以上で完了です。
Storyboadの編集に戻ります。Storyboard上の「Asset View Controller」の「ImageCell」を選択して、「Identifier」項目に「ImageCell」と入力します(図32)。
この「Identifier」はAssetViewControllerからCellを扱う際に使用します。
続いて、もう一方の「Address Cell」の設定を行います。「Address Cell」の修正はStoryboad上の操作で完結します。
「ImageCell」のと同様に「Identifier」の設定を行います。
Storyboard上の「Asset View Controller」の二つ目のセルを選択します(図33)。
「Identifier」項目に「AddressCell」と入力します(図34)。
最後に、「Address Cell」の左側のラベルにテキストを設定します(図35)。
Cellの実装は以上で完了です。
実装する内容は以下の通りです。順に説明していきます。
import UIKit import Photos class AssetViewController: UITableViewController { var annotation :PhotoAnnotation? // MARK: - Life cycle override func viewDidLoad() { super.viewDidLoad() // Uncomment the following line to preserve selection between presentations // self.clearsSelectionOnViewWillAppear = false // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // self.navigationItem.rightBarButtonItem = self.editButtonItem() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // MARK: - Table view delegate override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { if indexPath.row == 0 { return self.imageCellSize().height } else { return super.tableView(tableView, heightForRowAtIndexPath: indexPath) } } override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 0.01 } // MARK: - Table view data source override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if let aAnnotation = self.annotation { return 2 } else { return 0 } } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { if indexPath.row == 0 { let cell = tableView.dequeueReusableCellWithIdentifier("ImageCell", forIndexPath: indexPath) as! ImageCell let cellSize = self.imageCellSize() if let aAnnotation = self.annotation { PHImageManager().requestImageForAsset( aAnnotation.asset, targetSize: cellSize, contentMode: .AspectFill, options: nil, resultHandler: {(aImage, info) -> Void in if let image = aImage { cell.assetImage = image } } ) } return cell } else { let cell = tableView.dequeueReusableCellWithIdentifier("AddressCell", forIndexPath: indexPath) as! UITableViewCell cell.detailTextLabel?.text = self.annotation?.address return cell } } // MARK: - private private func imageCellSize() -> CGSize { if let annotation = self.annotation { if let asset = annotation.asset { let imageRatio = CGFloat(asset.pixelHeight) / CGFloat(asset.pixelWidth) let cellWidth = self.tableView.bounds.size.width let cellHeight = cellWidth * imageRatio + (1.0 / UIScreen.mainScreen().scale) return CGSize(width: cellWidth, height: cellWidth * imageRatio) } } return CGSizeZero } }
Photosフレームワークをimportする記述を追加します。
「PhotoAnnotation?」型の「annotation」プロパティを追加します。「PhotoAnnotation」は前回の記事で実装したクラスです。
AssetViewController.swiftファイル作成時に自動追加される「viewDidLoad」「didReceiveMemoryWarning」メソッドは、そのまま残します。修正箇所は、ありません。
8行目の「// MARK: - Life cycle」というコメントは、メソッドを種類ごとに分類するためのコメントで、AssetViewController.swiftファイルではメソッドの役割ごとに分類しています。このコメントを追加することによってXcodeのエディター上で、分類されたメソッドのリストを表示できるようになります(図36)。
UITableViewDelegateのメソッドを実装することによって「UITableViewのセルがタップされたときの処理」や「UITableView のセルやヘッダーの高さの指定」を記述できます。
27〜33行目の「tableView:heightForRowAtIndexPath:」メソッドはセルの高さを指定するためのメソッドです。0番目のセル(ImageCell)の場合は、後ほど説明する「imageCellSize」メソッドで計算した高さを返却します。0番目の以外のセル(AddressCell)場合は、スーパークラス(UITableViewController)の同名のメソッドで返却される値をそのまま返却します。
35〜37行目の「tableView:heightForHeaderInSection:」メソッドはセクションヘッダーの高さを指定するためのメソッドです。
UITableViewDelegateのメソッドを実装することによって「UITableViewの行の数」「UITableViewで使用するセルオブジェクト」などを指定できます。
41〜47行目の「tableView:numberOfRowsInSection:」メソッドでは「行の数」を返却します。
49〜75行目の「tableView:cellForRowAtIndexPath:」メソッドでは「セルオブジェクト」を返却します。
52行目と71行目で使用している「dequeueReusableCellWithIdentifier:forIndexPath:」メソッドは、引数で指定する「識別子」に関連したセルオブジェクトを取得するためのメソッドです。この「識別子」はStoryboard上で設定した「ImageCell」や「AddressCell」のことです。
MKMapViewが管理する注釈ビューと同様に、セルは必要に応じて使い回されます。「dequeueReusableCellWithIdentifier:forIndexPath:」メソッドを使用することで、セルの管理をUITableViewに任せることができます。
「imageCellSize」メソッドはImageCellのサイズを返却するメソッドです。セルのアスペクト比が写真のアスペクト比と等しくなるように計算して返却します。
Copyright © ITmedia, Inc. All Rights Reserved.