2016-10-15 56 views
1

我有问题想弄清楚如何使用NSUserDefaults保存我的“RiskEntry”类型的字符串。我已经通过其他一些帖子,但不知何故,我仍然无法解决这个问题。使用NSUserDefaults和结构类型数组

让我来解释一下下面的代码吧:我在下面的代码片段中从我的类CustomCell中获取一些数据。在这里,我首先检查一个“标识符”要更新哪个数组,使用新的数组值“结果”。

它一切正常,更新后的数组存储在riskEntry中。 但是,我现在无法解决如何使用NSUserDefaults进行存储。当我尝试用例如riskItemDefaults.set(riskEntry, forKey: "riskItem")我收到一个异常错误。

任何想法我在做什么错在这里?

SWIFT3(我删除了这个问题不相关的所有代码)

class: RiskPlan: UIViewController, UITableViewDelegate, UITableViewDataSource, CustomCellUpdaterDelegate { 

var riskEntry = [RiskEntry]() 
var riskItemDefaults = UserDefaults.standard 

// ------ start of delegate function (receiving from CustomCell) --------- 
     func transferData(consequencesTranferred: String, identifier: String) { 
     if let index = riskEntry.index(where: {$0.title as String == identifier}) { 
      riskEntry[index].consequences = consequencesTranferred 
    } else { 
     print ("nothing") 
    } 

// save with NSUserDefaults 
     riskItemDefaults.set(riskEntry, forKey: "riskItem") 
    } 
} 

这是我的结构:

public struct RiskEntry { 
    let title: String 
    var consequences: String 
} 

我自定单元

// ---------------- delegate to transfer entered data to VC ----------------- 
protocol CustomCellUpdaterDelegate { 
    func transferData(consequencesTranferred: String, identifier: String) 
} 

// ---------------- start of class CellCustomized ----------------- 
class CustomCell: UITableViewCell, UIPickerViewDataSource, UIPickerViewDelegate, UITextViewDelegate { 

    var delegate: CustomCellUpdaterDelegate? 

    // text fields, text views and picker views 
    @IBOutlet weak var riskTitle: UITextView! 
    @IBOutlet weak var consequences: UITextView! 

    // ---------------- listener for text view to save input in string when editing is finished ----------------- 
    func textViewDidEndEditing(_ textView: UITextView) { 
     if textView.tag == 1 { 
      textConsequences = consequences.text 
      nameIdentifier = riskTitle.text 
      delegate?.transferData(consequencesTranferred: self.textConsequences, identifier: nameIdentifier) 
     } else { 
      print ("nothing") 
     } 
    } 
} 
+0

你收到的例外是什么? –

+0

我的控制台输出是:'libC++ abi.dylib:以'NSException类型的未捕获异常终止,而我的AppDelegate.swift类被选为'线程1:信号SIGABRT' – Jake2Finn

+1

可能的http://stackoverflow.com/重复问题/ 38406457 /如何保存一个自定义数组结构到nsuserdefault-with-swift?rq = 1 – hotpaw2

回答

1

的问题是你不能将自定义数组保存在NSUserDefaults中。要做到这一点,你应该改变他们的NSData然后将其保存在NSUserDefaults的 这是我在项目中使用它在迅速2语法,我不认为这会是很难将其转换为SWIFT 3

let data = NSKeyedArchiver.archivedDataWithRootObject(yourObject); 
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "yourKey") 
NSUserDefaults.standardUserDefaults().synchronize() 
代码

,并在获取部分使用这种组合

if let data = NSUserDefaults.standardUserDefaults().objectForKey("yourKey") as? NSData { 
    let myItem = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? yourType 
} 

希望这将有助于

0

最接近的类型到UserDefaults支持可能是一个NSDictionary迅捷的结构。您可以在保存数据之前将结构元素复制到Objective C NSDictionary对象中。在UserDefaults

1

保存对象有非常具体的限制:

set(_:forKey:) reference:

值参数可以是唯一的财产清单对象:NSData的,的NSString,NSNumber的,NSDate的,NSArray的,或者NSDictionary的。对于NSArray和NSDictionary对象,其内容必须是属性列表对象。

您需要序列化您的模型,使用NSCoding或作为使用JSON的替代方法映射到UserDefaults支持的值。

0

我能够基于@ahruss编程解决方案(How to save an array of custom struct to NSUserDefault with swift?)。不过,我将其修改为swift 3,并且还显示了如何在UITableView中实现此解决方案。我希望它能够帮助别人的未来:

  1. 从下面的扩展添加到您的结构(它调整到你自己的变量)

  2. 保存所需的阵列项目是这样的:

    让编码= riskEntry.map {$ 0.encode()} riskItemDefaults.set(编码,forKey: “后果”) riskItemDefaults.synchronize()

  3. 加载您的项目像这样

    let dataArray = riskItemDefaults.object(forKey:“effects”)as! [NSData] let savedFoo = dataArray.map {RiskEntry(data:$ 0)! }

  4. 如果你想显示保存的数组元素在你的细胞,进行这样:

    cell.consequences.text = savedFoo [indexPath.row] .consequences作为字符串

下面是完整的代码,修改后用于Swift3

结构

// ---------------- structure for table row content ----------------- 
struct RiskEntry { 
    let title: String 
    var consequences: String 
} 

分机号码

extension RiskEntry { 
     init?(data: NSData) { 
      if let coding = NSKeyedUnarchiver.unarchiveObject(with: data as Data) as? Encoding { 
       title = coding.title as String 
       consequences = (coding.consequences as String?)! 
      } else { 
       return nil 
      } 
     } 

     func encode() -> NSData { 
      return NSKeyedArchiver.archivedData(withRootObject: Encoding(self)) as NSData 
     } 

     private class Encoding: NSObject, NSCoding { 
      let title : NSString 
      let consequences : NSString? 


      init(_ RiskEntry: RiskEntry) { 
       title = RiskEntry.title as NSString 
       consequences = RiskEntry.consequences as NSString? 
      } 

      public required init?(coder aDecoder: NSCoder) { 
       if let title = aDecoder.decodeObject(forKey: "title") as? NSString { 
        self.title = title 
       } else { 
        return nil 
       } 
       consequences = aDecoder.decodeObject(forKey: "consequences") as? NSString 
      } 

      public func encode(with aCoder: NSCoder) { 
       aCoder.encode(title, forKey: "title") 
       aCoder.encode(consequences, forKey: "consequences") 
      } 

     } 
    }