質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.03%

Realmで保存したString型の配列にある写真の値をloop文で回しながらUIImage型に変換をし、UICollectionViewCellに値を格納したい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 453

crea7dosSantos

score 15

 Realmで保存したString型の配列にある写真の値をloop文で回しながらUIImage型に変換して、UICollectionViewCellに値を格納したい。

こんにちは、質問失礼致します。
現在、Realmのファイルに保存されているデータを取得し、そのデータの中に保存されているimageStringという変数に写真のデータがString型の配列で保存されているので、String型の配列にあるデータをloop文で回し、 base64 を使用してUIImage型の配列に変換し、UICollectionViewのcellにUIImageViewがあるので、そこのimageViewに値を入れたいと考えています。

 該当のソースコード

import UIKit
import RealmSwift
import SVProgressHUD

class CategoryPhotoUpViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
  @IBOutlet weak var categoryCollectionView: UICollectionView!

  let realm = try! Realm()

  var morningArray = try! Realm().objects(Morning.self).sorted(byKeyPath: "id", ascending: false)

  var categoryXib: XibCategoryPhotoView!

  override func viewDidLoad() {

    // もしmorningArrayの数が0だったら遷移元の画面に戻る
    if morningArray.count == 0 {
      self.navigationController?.popViewController(animated: true)
    }
    print("DEBUG_PRINT: morningControllerが表示されました")
    print("DEBUG_PRINT: \(morningArray.count)")
    categoryCollectionView.delegate = self
    categoryCollectionView.dataSource = self

    categoryXib = XibCategoryPhotoView()
    categoryCollectionView.reloadData()

  }

  override func didReceiveMemoryWarning() {
  }

  override func viewWillAppear(_ animated: Bool) {
    categoryCollectionView.reloadData()
    print("DEBUG_PRINT: 画面を更新します")
  }

  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    print("DEBUG_PRINT: 数を返します")
    return morningArray.count
  }

  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = categoryCollectionView.dequeueReusableCell(withReuseIdentifier: "Cell2", for: indexPath) as! CategoryCollectionViewCell
    if morningArray.count == 0 {
      print("DEBUG_PRINT: morningArrayのデータが0です")
    } else if morningArray.count > 0 {
      print("DEBUG_PRINT: morningArrayのデータが0以上です")

    for morningArrayValue in morningArray {
      for imageStringer in morningArrayValue.imageString {
        var image: UIImage
        image = UIImage(data: Data(base64Encoded: String(imageStringer), options: .ignoreUnknownCharacters)!)!

          cell.imageView.image = image
          print("DEBUG_PRINT: cellのイメージに値をセットしました。")
          print("DEBUG_PRINT: \(String(describing: cell.imageView.image))")
        }
      }
    }
    return cell
  }

  // セルサイズの自動変更を設定する
  func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    let width: CGFloat = view.frame.width / 3 - 1   // self.viewを/3し、-1は隙間の部分
    let height: CGFloat = width

    return CGSize(width: width, height: height)
  }
}

 試したこと

for loop文でRealmからデータを取得している変数 morningArray を回しており、次のfor文で morningArrayから取得したデータ morningArrayValue に imageStringのデータを与え回しています。変数 imageStringer に base64 を使用しUIImage型に変換しようと考えています.
シグバートエラーが image = UIImage(data: Data(base64Encoded: String(imageStringer), options: .ignoreUnknownCharacters)!)! の部分で出ています。

![イメージ説明](37c5b94522803ed3605c54385973a597.jpeg)

デバックエリアはこのようになっていて、imageに何かしらの値は入ってるように感じるのですが、imageにString型のデータをUIImage型に変換して入れようとするところで止まってしまいます。これはなぜ変数imageにUIImage型で値が入らないのでしょうか?基本的には1つ上の部分のif文で morningArray の数が0以上であることは確認してあるのでnilが入ることはないと思ってるのですが、何かコードに不備があるのでしょうか?
ご存知の方がいらっしゃったらご教授いただけるとありがたいです。
初心者なので至らない点もあると思いますがよろしくお願い致します。

 補足情報(FW/ツールのバージョンなど)

Xcode Version 9.3.1

よろしくお願い致します。

 追記

import RealmSwift

class Morning: Object {
  // 管理用 ID。プライマリーキー
  @objc dynamic var id = 0

  // 投稿ID
  @objc dynamic var postID = ""

  // UserName
  @objc dynamic var userName = ""

  // ImageString
  @objc dynamic var imageString = ""

  // caption
  @objc dynamic var caption = ""

  // date
  @objc dynamic var time = ""


  override static func primaryKey() -> String? {
    return "id"
  }
}
// Date.timeIntervalSinceReferenceDateメソッドだけを取り出し、コードの量を減らす
    let timer = Date.timeIntervalSinceReferenceDate

    // もしもMorningSwitchがtrueだったら
    if morningSwitch.isOn == true {
      let morning = Morning()
      morning.time = String(timer)

      let morningArray = realm.objects(Morning.self)
      // もしもmorningArrayのcountプロパティが0じゃなかったら
      if morningArray.count != 0 {
        morning.id = morningArray.max(ofProperty: "id")! + 1
      }
      try! realm.write {
        // タグmorningに投稿情報が保存される時
        morning.caption = self.textField.text!
        morning.userName = (Auth.auth().currentUser?.displayName!)!
        morning.imageString = imageData!.base64EncodedString(options: .lineLength64Characters)
        // 日付の値を取得する
        morning.time = String(timer)
        realm.add(morning, update: true)
      }
    }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

 修正版の回答

内側のループが不要です。
.imageString(String型)を内側のfor文で分解してしまっていたためにCharactrer型になっていました。
内側のループを削除することにより、morningArrayValue.imageStringでBase64エンコード文字列を参照できるようになります。

for morningArrayValue in morningArray {
    //for imageStringer in morningArrayValue.imageString { //※削除
        var image: UIImage
        image = UIImage(data: Data(base64Encoded: morningArrayValue.imageString, options: .ignoreUnknownCharacters)!)!

        cell.imageView.image = image
        print("DEBUG_PRINT: cellのイメージに値をセットしました。")
        print("DEBUG_PRINT: \(String(describing: cell.imageView.image))")
    //} //※削除
}

 最初の回答

Base64のデコード(String→Data)か、Data→UIImageで失敗しています。
ひとまず、内側のループを下記のコードに置き換えてどうなるか教えて下さい。

for imageStringer in morningArrayValue.imageString {
    if let data = Data(base64Encoded: String(imageStringer), options: .ignoreUnknownCharacters) {
        if let image = UIImage(data: data) {
            print(image)
            /*
             cell.imageView.image = image
             print("DEBUG_PRINT: cellのイメージに値をセットしました。")
             print("DEBUG_PRINT: \(String(describing: cell.imageView.image))")
             */
        } else {
            print("error: data to image (count=\(data.count)")
        }
    } else {
        print("error: string to data [\(String(imageStringer).prefix(10))]")
    }
}

強制アンラップ!は使わないクセを付けた方がいいです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/14 22:58

    分かりにくい質問に対し、丁寧に教えていただきありがとうございます。
    何か分かりましたら教えていただければ幸いです。
    よろしくお願い致します。

    キャンセル

  • 2018/05/15 11:46

    回答を追記しました。

    キャンセル

  • 2018/05/15 12:07

    今ビルドをして確認したところ、正しくMoningクラスに保存をした写真のデータのみが表示されました。ここの処理でずっと引っかかっていた為本当に嬉しく感謝の気持ちでいっぱいです。
    本当にお手数をおかけして申し訳ありませんでした。
    今回ご教授いただいたことを忘れずこれからも頑張りたいと思います。
    本当にありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる
  • トップ
  • iOSに関する質問
  • Realmで保存したString型の配列にある写真の値をloop文で回しながらUIImage型に変換をし、UICollectionViewCellに値を格納したい