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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Core Data

Core DataはAppleのOS X and iOSのためのオブジェクトモデリングと持続性を持ったフレームワークです。Xcodeはエンティティー、属性そして関係性を特定するためのオブジェクトモデルの編集機能を提供します。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

Q&A

解決済

1回答

1699閲覧

CoreData に保存した NSAttributedString 内の画像がアプリキル後に再表示されない【Xcode 12.1】

Zhalen

総合スコア2

Core Data

Core DataはAppleのOS X and iOSのためのオブジェクトモデリングと持続性を持ったフレームワークです。Xcodeはエンティティー、属性そして関係性を特定するためのオブジェクトモデルの編集機能を提供します。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

0グッド

0クリップ

投稿2020/10/25 05:20

編集2020/10/25 05:36

前提・実現したいこと

現在、SNSアプリを作成しています。そのため、CoreDataを使用しています。

NSAttributedString 中に画像を挿入して、タイムラインに投稿する仕組みをその一部に実装しました。

CoreData にその画像つき文章を保存して、それをタイムラインに表示する所までは上手くいっております。

ですが下記の画像のように、アプリのキル(ホームボタンを二回押してフリップして終了)をしてまたアプリを開くと、画像だけが表示されません。

この時でも、ちゃんと画像が表示されるようにしたいと考えています。

以下、質問をする上で必要と思われる情報を記載してゆきます。

CoreData の Attribute

Attribute の type を Transformable。Custom Class を NSAttributedString にする事で保存をしています。Attribute の名前はpostedAttrTextにしました。

画像の挿入

imagePickerが画像を取得し終えたときに、テキスト内に画像を入れて、そのテキストを textView の attributedText に代入するということをしています。もしかしたらこの時にimagePickerが拾った画像のデータ(?)と、アプリを消してまた表示した際のデータにくい違いがあるのではないかとも考えました。

Swift

1func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { 2 if let image: UIImage = info[.originalImage] as? UIImage { 3 //画像選択時のカーソル位置を取得 4 var currentPosition: Int = 0 5 if let selectedTextRange = textView.selectedTextRange { 6 currentPosition = textView.offset(from: textView.beginningOfDocument, to: selectedTextRange.start) 7 } else { 8 currentPosition = textView.text.count 9 } 10 11 let fullString: NSMutableAttributedString = NSMutableAttributedString(string: "") 12 let leftString: NSAttributedString = textView.attributedText.attributedSubstring(from: NSRange(location: 0, length: currentPosition)) 13 let paddingRow: NSAttributedString = NSAttributedString(string: "\n") 14 let rightString: NSAttributedString = textView.attributedText.attributedSubstring(from: NSRange(location: currentPosition, length: textView.text.count-currentPosition)) 15 let textViewWidth: CGFloat = textView.frame.width 16 let imageSize: CGSize = image.size 17 let newImageSize: CGSize = CGSize(width: textViewWidth, height: textViewWidth * imageSize.height / imageSize.width) 18 let imageAttachment: NSTextAttachment = NSTextAttachment(image: image.reSizeImage(reSize: newImageSize))//reSizeImage...UIImageのExtension 19 let imageString: NSAttributedString = NSAttributedString(attachment: imageAttachment) 20 21 //How to image alignment to center??? 22 23 //padding がないと、画像真っ黒になる。 24 fullString.append(leftString) 25 fullString.append(paddingRow) 26 fullString.append(imageString) 27 fullString.append(paddingRow) 28 fullString.append(rightString) 29 30 textView.attributedText = fullString 31 } 32 dismiss(animated: true, completion: nil) 33}

CoreData への保存・読み込み

そのテキストのCoreDataへの保存・読み込みに関連する場面だけを切り取ってそれを簡略化すると、以下のようになります。ENTITLE は SecondTimeLineModelとしております。仮称として、保存する記述のあるクラスをSaveViewController、読み込みの記述があるクラスをReadViewControllerとしています。

Swift

1class SaveViewController: UIViewController { 2 3 //CoreDataへの保存の際に必要な記述1 4 var secondTimeLineModel: [SecondTimeLineModel] = [SecondTimeLineModel]() 5 var managedObjectcontext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 6 7 override func viewDidLoad() { 8 super.viewDidLoad() 9 10 //CoreDataへの保存の際に必要な記述2 11 let dataCondition = NSFetchRequest<SecondTimeLineModel>(entityName: "SecondTimeLineModel") 12 do{ 13 secondTimeLineModel = try managedObjectcontext.fetch(dataCondition) 14 }catch{ 15 print("Error") 16 } 17 } 18 19 //投稿ボタン押下時の処理(関係しない部分は省略) 20 @objc private func post(_ sender: UIBarButtonItem) { 21 22 let object = SecondTimeLineModel(context: managedObjectcontext) 23 24 object.postedAttrText = postAttrText//postAttrText...投稿ボタン押下時のTextView.attributedText 25 coreData.secondTimeLineModel.append(object) 26 (UIApplication.shared.delegate as! AppDelegate).saveContext() 27 } 28}

Swift

1class ReadViewController: UIViewController { 2 3 //CoreDataへの保存の際に必要な記述1 4 var secondTimeLineModel: [SecondTimeLineModel] = [SecondTimeLineModel]() 5 var managedObjectcontext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext 6 7 override func viewDidLoad() { 8 super.viewDidLoad() 9 10 //CoreDataへの保存の際に必要な記述2 11 let dataCondition = NSFetchRequest<SecondTimeLineModel>(entityName: "SecondTimeLineModel") 12 do{ 13 secondTimeLineModel = try managedObjectcontext.fetch(dataCondition) 14 }catch{ 15 print("Error") 16 } 17 } 18} 19 20//問題に無関係と思われるものは省略(heightForRowAtなど) 21extension SecondViewController: UITableViewDelegate, UITableViewDataSource { 22 23 //postedAttrTextを受け取ってTableViewCellの中のTextViewに表示する 24 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 25 26 let cell: TimeLineTableViewCell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! TimeLineTableViewCell 27 28 let datas = [ 29 "postedAttrText" : secondTimeLineModel[indexPath.row].postedAttrText! 30 ] as [String : Any] 31 32 //setUpTableViewCell...セルをセットアップするメソッド。この中の TextView の attributedText に postedAttrText を代入します。 33 cell.setUpTableViewCell(index: indexPath, datas: datas) 34 35 return cell 36 } 37}

試したこと

(追記:なぜか既に書いたはずのこの項目が消えてた・・・)

・iPhone, Xcode, Macの再起動・アップデート確認
・Use Core Dataでプロジェクトを作り直す
・英語でも日本語でも何時間か調べ尽くしたが、NSAttributedStringのCoreDataへの保存においてなぜか保存の事だけで読み込みに関する記事はなかった。
print(postedAttrText)を実行することで、文章中にしっかりとUIImageが入っていることを確認
・一方で、シミュレータ(実機)上で文章を選択するとそこには何もなく、コピー&ペーストしても空白しかない

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

macOS Catalina 10.15.7
Xcode 12.1

###回答よろしくお願いいたします
私情により時間がなく、他のコーディングを進めているうちにteratailでの回答待ちをするという形をとらせて頂きましたが、もしこのまま回答が得られなかった場合はこの問題を抽象化した簡単なプロジェクトを作成してみて、解決したら自己解決として終了。そうでなくても何か新たな事実が判明すれば追記していきたいと思います。
何かご存知の方は、是非回答をよろしくお願いしますm(_ _)m

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

確認は取ってませんが、2019年1月29日時点では画像付きのNSAttributedStringをTransformableとしてCoreDataに保存すると画像が捨てられるバグがあるようです

https://www.amerhukic.com/storing-nsattributedstring-with-uiimage-in-core-data

ワークアラウンドも書かれてるのでそれで対処してみてはどうでしょうか?

(2019年1月29日時点での話なので状況が変わっている可能性があります)

投稿2020/10/27 09:58

MasakiHori

総合スコア3384

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zhalen

2020/10/27 10:27

拝見させて頂きました。良記事提供ありがとうございます! HTML使えばいけるんですね・・・! そして実は私は既にメモリの観点からCoreDataの使用を断念していて、結局Firebaseを使って作り直すことにしました。驚いたのは、CoreDataを用いた場合だとタイムラインにほんの十個か二十個ほどの投稿をするだけで600MBくらいiPhoneのストレージ食っちゃったんですよね。Twitterとかあれだけ流れてて150MBとかなのにです。多分上級者からすれば当たり前の事なのでしょうが、やはりCoreDataをやめてよかったと思っています。 ただ、仕組み的にFirebaseでも同じようなことが起きると思いますので、HTMLを用いたこの記事の方法を試してみます。回答ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問