5

I am developing in Swift. I want to store the custom data via nsuserdefaults.

My custom data is like the following

In ConnectedDevice.swift

import UIKit
import Foundation
import CoreBluetooth
import CoreLocation

class ConnectedDevice : NSObject , NSCoding{

    var RSSI_threshold:NSNumber=0

    var Current_RSSI:NSNumber=0

    var name:String?

    var bdAddr:NSUUID?

    var ConnectState:Bool=false

    var AlertState:Int=0

    var BLEPeripheral : CBPeripheral!

    var DisconnectAddress:[String] = [String]()

    var DisconnectTime:[String] = [String]()

    var Battery:NSInteger=0

    var Location:[CLLocation] = [CLLocation]()

    var AlertStatus:Int!



    func encodeWithCoder(aCoder: NSCoder) {

        aCoder.encodeObject(RSSI_threshold, forKey: "RSSI_threshold")
        aCoder.encodeObject(Current_RSSI, forKey: "Current_RSSI")
        aCoder.encodeObject(name, forKey: "name")
        aCoder.encodeObject(bdAddr, forKey: "bdAddr")
        aCoder.encodeBool(ConnectState, forKey: "ConnectState")
        aCoder.encodeInteger(AlertState, forKey: "AlertState")
        aCoder.encodeObject(BLEPeripheral, forKey: "BLEPeripheral")
        aCoder.encodeObject(DisconnectAddress, forKey: "DisconnectAddress")
        aCoder.encodeObject(DisconnectTime, forKey: "DisconnectTime")
        aCoder.encodeObject(Battery, forKey: "Battery")
        aCoder.encodeObject(Location, forKey: "Location")
        aCoder.encodeObject(AlertStatus, forKey: "AlertStatus")


    }

    override init() {


    }

    required init?(coder aDecoder: NSCoder) {

        self.RSSI_threshold = aDecoder.decodeObjectForKey("RSSI_threshold") as! NSNumber
        self.Current_RSSI = aDecoder.decodeObjectForKey("Current_RSSI") as! NSNumber
        self.name = aDecoder.decodeObjectForKey("name") as? String
        self.bdAddr = aDecoder.decodeObjectForKey("bdAddr") as? NSUUID
        self.ConnectState = aDecoder.decodeObjectForKey("ConnectState") as! Bool
        self.AlertState = aDecoder.decodeObjectForKey("AlertState") as! Int
        self.BLEPeripheral = aDecoder.decodeObjectForKey("BLEPeripheral") as! CBPeripheral
        self.DisconnectAddress = aDecoder.decodeObjectForKey("DisconnectAddress") as! [String]
        self.DisconnectTime = aDecoder.decodeObjectForKey("DisconnectTime") as! [String]
        self.Battery = aDecoder.decodeObjectForKey("Battery") as! NSInteger
        self.Location = aDecoder.decodeObjectForKey("Location") as! [CLLocation]
        self.AlertStatus = aDecoder.decodeObjectForKey("AlertStatus") as! Int
    }
}

In ViewController.swift

var userDefault = NSUserDefaults.standardUserDefaults()
var BLEConnectedDevice:[ConnectedDevice] = [ConnectedDevice]()

When I try to store the data , I use the following code:

let data = NSKeyedArchiver.archivedDataWithRootObject(BLEConnectedDevice)
        NSUserDefaults.standardUserDefaults().setObject(data, forKey: "BLEConnectedDevice")
       userDefault.synchronize()

When I try to load the data , I use the following code:

if let Data = NSUserDefaults.standardUserDefaults().objectForKey("BLEConnectedDevice") as? NSData {

    if let devcie = NSKeyedUnarchiver.unarchiveObjectWithData(Data) as? ConnectedDevice {

        print("NSUserDefaults = \(devcie.name)")

    }

}

But it will show the error at aCoder.encodeObject(BLEPeripheral, forKey: "BLEPeripheral") , and the error log is

2016-08-24 18:37:57.022 Anti-Lost[476:222607] -[CBPeripheral encodeWithCoder:]: unrecognized selector sent to instance 0x14e9fc60
2016-08-24 18:37:57.024 Anti-Lost[476:222607] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CBPeripheral encodeWithCoder:]: unrecognized selector sent to instance 0x14e9fc60'

How to encode the CBPeripheral ?

Did I missing something ? How to store the custom data via nsuserdefaults in swift ?

Wun
  • 6,211
  • 11
  • 56
  • 101
  • `CBPeripheral` is not `NSCoding` compliant. You can't save it. You may want to save only "interesting informations" about it, but you can't store it like this. – Larme Aug 24 '16 at 11:26

1 Answers1

6

It's because CBPeripheral do not implement NSCoding. So, you will not be able to archive your BLEPeripheral object into NSUserDefaults.

I think the best solution is to store the properties directly you are interested in (like name or identifier):

aCoder.encodeObject(BLEPeripheral.name, forKey: "BLEPeripheralName")
aCoder.encodeObject(BLEPeripheral.identifier, forKey: "BLEPeripheralIdentifier")

Edit:

I think you will not be able to store and build again your CBPeripheral, no matter how. Apple presents the CBPeripheral object like that:

So, that seems very logical that you cannot store this object and build it back later ... I think the best solution is to store the BLEPeripheral.identifier and fetch back the CBPeripheral later using the CBCentralManager. You can do it by using the retrievePeripherals(withIdentifiers:) method. Here is the documentation. And I think you should never build a CBPeripheral object by yourself.

Julien Quere
  • 2,407
  • 16
  • 21
  • And I also try `self.BLEPeripheral.name = aDecoder.decodeObjectForKey("BLEPeripheralName") as! String` But it show `Cannot assign to property: 'name' is a get-only property` – Wun Aug 25 '16 at 05:35
  • Indeed. I don't think you will be able to build again your BLEPeripheral object from NSUserDefaults. And when we think about it, it seems normal no ? – Julien Quere Aug 25 '16 at 05:47
  • I just edited my answer to explain why `BLEPeripheral` should not be stored and build again directly. – Julien Quere Aug 25 '16 at 07:26
  • 1
    This is the correct answer. Only store the identifier and then recreate the CBPeripheral using the CBCentralManager. That is how you do it! :) – Anton Aug 31 '16 at 07:55