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

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

ただいまの
回答率

90.47%

  • Swift

    7492questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • iOS

    4094questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

  • Realm

    208questions

    RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

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

解決済

回答 1

投稿 編集

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

 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 11:58 編集

    ご回答ありがとうございます。
    data to image (count= 0 となっており、 error: string to data の部分では様々な文字列が取り出されています。
    またシグバートエラーは発生していません。
    Base64のデコードで失敗しているということですが、 data.count で 0 が出てしまっているという事はString型からdata型に変換する部分で失敗していると考えてよろしいのでしょうか?
    また質問させていただいた時のコードでは強制アンラップを使用しないとエラーが出てしまっていたので、その表示に従い強制アンラップをしてしまっていたのですが、その場合は強制アンラップを使用しなくてもエラーが出ないコードに書き換える必要があったという認識で間違い無いでしょうか?

    キャンセル

  • 2018/05/14 13:01

    >>`data.count` で0が出てしまっているという事はString型からdata型に変換する部分で失敗していると考えてよろしいのでしょうか?

    そうです。全て失敗しているのでしょうか?Base64エンコードはどのようにしているのでしょうか?
    (ちなみに「様々な文字列」というのはBase64エンコードされた文字列の冒頭部分です)

    >>その場合は強制アンラップを使用しなくてもエラーが出ないコードに書き換える必要があったという認識で間違い無いでしょうか?

    はい、その認識で合っています。強制アンラップ(Forced Unwrapping)を使うと今回のような場合にアプリが落ちてしまいます。
    アンラップの方法はいくつかありますが、私のコードでは if let(Optional Binding)を使ってアンラップしています。

    キャンセル

  • 2018/05/14 17:23

    ご回答ありがとうございます。
    ご丁寧に教えていただき感謝します。
    全て失敗しているとはどういう意味なのでしょうか?

    https://gyazo.com/2e0b2aece772b2256cd41688fed9ad5b

    あと少し質問させていただきたいのですが、imageStringerにこのような Character型の値が入っていて、Character型がString型の一種というのは理解しているのですが、これは正常に値が取り出せているのでしょうか?
    申し訳ないのですが、教えていただきたいです。

    キャンセル

  • 2018/05/14 17:41 編集

    全てというのは「morningArrayの全て」という意味です。言い換えると「全ての画像で失敗しているのでしょうか?」ということです。

    >>Character型の値が入っていて...
    一つでいいので string to data の出力を教えていただけますか?
    「様々な文字列」と書いてあったのでBase64エンコードされた文字列が表示されていると思っていたのですが、もしかして一文字しか表示されていないのでしょうか?

    キャンセル

  • 2018/05/14 20:09

    ご回答ありがとうございます。
    morningArrayの全てで失敗しているかとの事ですが配列に3つの要素がある場合でも data to image (count=0なので全ての値の変換に失敗しています。

    はい、 string to data [9] のような形で複数の値が出力されています。
    error: string to data [/]
    error: string to data [9]
    error: string to data [j]
    error: string to data [/]
    error: string to data [4]
    error: string to data [A]
    error: string to data [A]
    error: string to data [Q]
    error: string to data [S]
    error: string to data [k]
    error: string to data [Z]
    error: string to data [J]
    error: string to data [R]
    error: string to data [g]
    コメントの仕方に分かりにくい点があり、申し訳ありませんでした。
    このようにいくつもの文字列が表示されています。

    キャンセル

  • 2018/05/14 21:05

    やはり一文字しかないようですね。
    .imageStringの型はStringなのでしょうか?差し支えなければMorningクラスの定義を書いて下さい。
    あとは、DB登録時のコードと。
    Realmのことをよく知らないのであまり力になれないかもしれませんが‥。

    キャンセル

  • 2018/05/14 21:29 編集

    お付き合いいただきありがとうございます。
    Morningクラスの定義は追記の通りになっております。

    またこのようにしてMorningクラスの場合、DBに書き込みも追記した通りになっております。

    キャンセル

  • 2018/05/14 21:40

    追加のコードは質問内に追記して下さい。

    で、クラス定義で型を明示するとどうなるでしょうか?
    @objc dynamic var imageString: String = ""

    キャンセル

  • 2018/05/14 21:57

    失礼致しました、以後気をつけたいと思います。
    クラス定義で型を明示して見ましたがデバックエリアに出力される値は今までの結果と同じものでした。

    キャンセル

  • 2018/05/14 21:59

    以後ではなく、今から実践して下さい。
    (質問内の追記し、コメント欄のコードは削除して下さい)

    で、保存するところからやり直しましたか?

    キャンセル

  • 2018/05/14 22:16

    失礼致しました。
    はい、アプリを削除し、保存するところからやり直して見ましたが、デバックエリアに出力される値に変化はありませんでした。
    しかし、もう一度 Morning クラスの Realmファイルを見直して見て気が付いたのですが、 id や userName や caption などのプロパティはそれぞれの値で保存がされているのですが、imageStringだけ全部の要素の値が恐らく同じで保存されていました。
    Firebaseで写真をData型に変換し、String型に変換させた部分では正しく長い文字列の後に、Lengthという部分があり、その部分が各それぞれ値が違うのですが、RealmのimageStringのプロパティを見ても全部の要素で長い文字列が同じであり、Lengthという部分が保存されていません。
    分かりにくい説明で申し訳ありません。
    このRealmに保存する際の部分が今回のエラーの原因と考えていいのでしょうか?

    キャンセル

  • 2018/05/14 22:33

    RealmもFirebaseもよく分からないのでコメント出来ません。
    今は開発環境も無いので試すことも出来ず、時間が取れたら明日試してみます。

    キャンセル

  • 2018/05/14 22:58

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

    キャンセル

  • 2018/05/15 11:46

    回答を追記しました。

    キャンセル

  • 2018/05/15 12:07

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

    キャンセル

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

  • ただいまの回答率 90.47%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    Swift2 RealmオブジェクトをJSON形式に変換する方法

    Swift2でRealmデータベースを使っています。 PHPとのデータのやり取りをJSON形式で行いたいと思っています。 PHP -> Swiftは特に問題なく行えました。

  • 解決済

    RealmSwiftでマイグレーションを実装したい

    前提・実現したいこと SwiftでRealmSwiftのマイグレーションを実装したいと思っています。Realmの公式のドキュメントを参考に以下のコードを書いたのですが、マイグレー

  • 解決済

    RLMArray に Object をappendしたい

    PersonクラスとしてRealmオブジェクトとして以下のようなものを定義していて、APIサーバーからPersonにデータをmappingさせて利用しています。 class

  • 解決済

    [Swift]カスタムセルに設置したボタンからUIを操作したい

    現在、下図の様な 画像・カスタムボタン(チェックボックス風)・テキスト を持つカスタムセルをCollectionViewに配置しています。 このカスタムセル内

  • 解決済

    URLSessionDownloadの仕組みとswiftでのzipファイルの操作に関して

    行いたいこと 前提: サーバー上にzipファイルが用意されているとする。 またそのzipファイルにはjson形式で記述された拡張子が「.json」のファイルが数個存在するものとする

  • 解決済

    swift realm xcode

    現在、UserDefaultsを使ってテキストに入力した文字をラベルに反映させ、保存するという単純なものを作りましたが。これをRealmを使って同じようにさせたいのですが、本日使い

  • 解決済

    RealmSwiftで複数のclassを一つのListで保存したい。

    現在、ユーザーの複数のSNSアカウントを管理するアプリを制作しています。 その中で、登録された複数のSNSアカウントの情報からユーザーが選択したアカウントだけを一つのListにまと

  • 解決済

    RealmSwiftについて

    import UIKit import RealmSwift class CellData { var title: String = "" var detail

同じタグがついた質問を見る

  • Swift

    7492questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • iOS

    4094questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

  • Realm

    208questions

    RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

  • トップ
  • iOSに関する質問
  • Realmで保存したString型の配列にある写真の値をloop文で回しながらUIImage型に変換をし、UICollectionViewCellに値を格納したい