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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Xcode

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

Swift

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

Q&A

解決済

1回答

364閲覧

UserDefaultsで配列を保存したいのですが、どうしてもエラーになってしまいます

MoonDDDD

総合スコア9

Xcode

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

Swift

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

1グッド

1クリップ

投稿2018/11/07 01:48

編集2018/11/07 13:50

前提・実現したいこと

Userクラスの中のlikeという配列をUserDefaultsで使おうとした時、likeのデコード処理でnilが入ってしまい、このようなエラーが発生してしまいます。この対処法を教えてもらえませんか?

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

ソースコード(データクラス)

import Foundation class User:NSObject, NSCoding { var UserName: String? var Email: String? var Password: String? var UserImage: NSData? var lives: String? var sex: String? var age: String? var colleage: String? var event: String? var eventName: String? var like = [String]() override init() { } //デコード処理 required init?(coder aDecoder: NSCoder) { UserName = aDecoder.decodeObject(forKey: "username") as? String Email = aDecoder.decodeObject(forKey: "email") as? String Password = aDecoder.decodeObject(forKey: "password") as? String UserImage = aDecoder.decodeObject(forKey: "userimage") as? NSData lives = aDecoder.decodeObject(forKey: "lives") as? String sex = aDecoder.decodeObject(forKey: "sex") as? String age = aDecoder.decodeObject(forKey: "age") as? String colleage = aDecoder.decodeObject(forKey: "colleage") as? String like = aDecoder.decodeObject(forKey: "like") as! [String] event = aDecoder.decodeObject(forKey: "event") as? String eventName = aDecoder.decodeObject(forKey: "eventname") as? String } //エンコード処理 func encode(with aCoder: NSCoder){ aCoder.encode(UserName, forKey: "username") aCoder.encode(Email, forKey: "email") aCoder.encode(Password, forKey: "password") aCoder.encode(UserImage, forKey: "userimage") aCoder.encode(lives, forKey: "lives") aCoder.encode(sex, forKey: "sex") aCoder.encode(age,forKey: "age") aCoder.encode(colleage, forKey:"colleage") aCoder.encode(like, forKey: "like") aCoder.encode(event, forKey: "event") aCoder.encode(eventName, forKey: "eventname") } } //現在のユーザーデータと指定している本のデータを格納するシングルトン final class NowUser{ static let shared = NowUser() var nowuser = User() var tapuser = User() var searchSwich: Bool = true private init() {} }

ソースコード(HomeViewController)

import UIKit class HomeViewController: UIViewController ,UICollectionViewDelegate, UICollectionViewDataSource{ var searchUsers = [User]() var user = User() var collectionView: UICollectionView! override func viewWillAppear(_ animated: Bool) { LoginCheck() searchUsers.removeAll() tabBarController?.tabBar.isHidden = false //検索用のsearchUsersと全てのユーザーを表示するusersをsearchSwichで分ける処理 if NowUser.shared.searchSwich == false { let searchUserDefaults = UserDefaults.standard if let storedSearchusers = searchUserDefaults.object(forKey: "searchusers") as? Data { if let unarchivesearchusers = NSKeyedUnarchiver.unarchiveObject(with: storedSearchusers) as? [User] { searchUsers.append(contentsOf: unarchivesearchusers) } } NowUser.shared.searchSwich = true }else{ let userDefaults = UserDefaults.standard if let storedusers = userDefaults.object(forKey: "users") as? Data { if let unarchiveusers = NSKeyedUnarchiver.unarchiveObject(with: storedusers) as? [User] { searchUsers.append(contentsOf: unarchiveusers) } } self.navigationItem.title = "検索" } collectionView.reloadData() } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white //NavigationBarの設定 let searchImageButton: UIBarButtonItem = UIBarButtonItem(image: UIImage(named:"search1"), style: UIBarButtonItemStyle.plain, target: self, action: #selector(Search(_:))) self.navigationItem.leftBarButtonItem = searchImageButton //CollectionViewの設定 let flowLayout: UICollectionViewFlowLayout = UICollectionViewFlowLayout() flowLayout.itemSize = CGSize(width: 90, height: 120) flowLayout.minimumInteritemSpacing = 20.0 flowLayout.minimumLineSpacing = 20.0 flowLayout.sectionInset = UIEdgeInsetsMake(20,20,0,20) collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: flowLayout) collectionView.backgroundColor = UIColor.white collectionView.register(HomeCustomCell.self, forCellWithReuseIdentifier: "HomeCustomCell") collectionView.delegate = self collectionView.dataSource = self self.view.addSubview(collectionView) } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return searchUsers.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCustomCell", for: indexPath) as! HomeCustomCell cell.userNameLabel.text = searchUsers[indexPath.row].UserName cell.userImageView.image = UIImage(data: (searchUsers[indexPath.row].UserImage! as Data))?.resize(size: CGSize(width: 50, height: 50)) return cell } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { NowUser.shared.tapuser = searchUsers[indexPath.row] navigationController?.pushViewController(ProfileViewController(), animated: true) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } @objc func LoginCheck(){ if NowUser.shared.nowuser.Email == nil{ let nc = UINavigationController(rootViewController: LoginViewController()) self.present(nc, animated: true, completion: nil) } } @objc func Search(_ sender: UIButton){ self.present(SearchViewController(), animated: true, completion: nil) } } class HomeCustomCell: UICollectionViewCell { let userImageView: UIImageView = { let imageView = UIImageView() return imageView }() let userNameLabel: UILabel = { let label = UILabel() label.textColor = .white label.textAlignment = NSTextAlignment.center return label }() override func draw(_ rect: CGRect) { self.layer.cornerRadius = 10 self.layer.masksToBounds = true let viewHeight10 = self.contentView.frame.height / 10 let viewWidth22 = self.contentView.frame.width / 22 self.contentView.addSubview(userImageView) self.contentView.addSubview(userNameLabel) self.selectedBackgroundView = UIView(frame: self.bounds) self.selectedBackgroundView?.backgroundColor = .red userNameLabel.translatesAutoresizingMaskIntoConstraints = false userNameLabel.topAnchor.constraint(equalTo:contentView.topAnchor,constant: viewHeight10 * 7).isActive = true userNameLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true userNameLabel.widthAnchor.constraint(equalToConstant: viewWidth22 * 22).isActive = true userNameLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true userImageView.translatesAutoresizingMaskIntoConstraints = false userImageView.topAnchor.constraint(equalTo:contentView.topAnchor).isActive = true userImageView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true userImageView.widthAnchor.constraint(equalToConstant: viewWidth22 * 22).isActive = true userImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true } }

ここを読み込む時にUserクラスを参照してエラーが起こりました

let userDefaults = UserDefaults.standard if let storedusers = userDefaults.object(forKey: "users") as? Data { if let unarchiveusers = NSKeyedUnarchiver.unarchiveObject(with: storedusers) as? [User] {       //ここでUserクラスを参照した時にエラーが起こった searchUsers.append(contentsOf: unarchiveusers) } }

searchUsersはUser型の配列です!( var searchUsers = User )

SUGIYOSI55👍を押しています

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

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

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

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

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

takabosoft

2018/11/07 02:38 編集

「UserDefaultsで使おうとした時」とありますが、その前にNSKeyedArchiverか何かでUser↔NSDataに変換していて、問題はその辺で起こっているわけですよね?そのあたりのコードを載せてもらえますか。
MoonDDDD

2018/11/07 02:53

そうです!今、問題のコードをあげました!お願いします!!
guest

回答1

0

ベストアンサー

再現を試みているのですが、手元ではエラーはおきません。
なにか他に条件はありませんか?

swift

1class User: NSObject, NSCoding { 2 3 var UserName: String? 4 var Email: String? 5 var Password: String? 6 var UserImage: NSData? 7 var like = [String]() 8 9 override init() { 10 } 11 12 //デコード処理 13 required init?(coder aDecoder: NSCoder) { 14 UserName = aDecoder.decodeObject(forKey: "username") as? String 15 Email = aDecoder.decodeObject(forKey: "email") as? String 16 Password = aDecoder.decodeObject(forKey: "password") as? String 17 UserImage = aDecoder.decodeObject(forKey: "userimage") as? NSData 18 like = aDecoder.decodeObject(forKey: "like") as! [String] //ここでエラーが発生する 19 } 20 21 //エンコード処理 22 func encode(with aCoder: NSCoder){ 23 aCoder.encode(UserName, forKey: "username") 24 aCoder.encode(Email, forKey: "email") 25 aCoder.encode(Password, forKey: "password") 26 aCoder.encode(UserImage, forKey: "userimage") 27 aCoder.encode(like, forKey: "like") 28 } 29} 30 31 32 33class ViewController: UIViewController { 34 35 private func save() { 36 var users = [User]() 37 38 let test = User() 39 //test.like.append("hoge") 40 41 users.append(test) 42 43 let data = NSKeyedArchiver.archivedData(withRootObject: users) 44 UserDefaults.standard.set(data, forKey: "users") 45 } 46 47 private func load() { 48 let userDefaults = UserDefaults.standard 49 if let storedusers = userDefaults.object(forKey: "users") as? Data { 50 if let unarchiveusers = NSKeyedUnarchiver.unarchiveObject(with: storedusers) as? [User] { 51 print(unarchiveusers) 52 //searchUsers.append(contentsOf: unarchiveusers) 53 } 54 } 55 } 56 57 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 58 save() 59 load() 60 } 61 62 63}

投稿2018/11/07 06:27

takabosoft

総合スコア8356

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

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

MoonDDDD

2018/11/07 13:48

なるほど。エラー起こらなかったんですか。。 実はマッチんングアプリもどきを作製していて、そこのデータクラスと一番初めに出るHomeViewController.swiftを載せておきます!! どうしても解決できなかったのでよろしくお願いします泣
MoonDDDD

2018/11/07 13:51

投げやりな形になってすみません!!
takabosoft

2018/11/08 00:49

せめて私が載せたような、容易に「再現する最低限のコード」に絞って載せてもらえませんか?ダミーデータで保存、それを読み込んでエラーが発生する、というシンプルなプログラムを作ってください。それができなければ解決は難しいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問