2

I'm new to swift and iOS. I'm working on an app for a highschool project. I have two files, each with a class defined in them. ViewController with a class of the same name, and BLEHandler, with one class BLEManager and another BLEHandler.

BLEHandler goes out and scans for advertising BLE devices and collects the UUIDs of those devices and prints them out. For now, I'm substituting "variable" for that UUID.

I want to be able to print the value of "variable" to the console when you press a button (which is set up in ViewController). This means that I need to have the "variable"s value from BLEHandler accessible in ViewController.

My current code to set up "variable" in the userdefaults is given here.

let defaults = NSUserDefaults.standardUserDefaults()
 defaults.setObject("test", forKey: "variable")

And my code to access "variable" from ViewController is given here:

@IBAction func buttonPress(sender: AnyObject) {
        let defaults = NSUserDefaults.standardUserDefaults()
        let name = defaults.stringForKey("variable")
        println(name)
}

It seems like it should work, but all I get from the println(name) line is nil... Any suggestions?

Thanks in advance!

EDIT: Here is the full code as it currently stands:

VIEWCONTROLLER CLASS:

import UIKit
import Foundation
import CoreBluetooth
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    @IBAction func buttonPress(sender: AnyObject) {
            let defaults = NSUserDefaults.standardUserDefaults()
            let name = defaults.stringForKey("variable")
            println(name)
        }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

BLEHANDLER CLASS:

import Foundation
import CoreBluetooth
class BLEManager{
    var centralManager: CBCentralManager!
    var bleHandler: BLEHandler
    init(){
        self.bleHandler=BLEHandler()
        self.centralManager=CBCentralManager(delegate:self.bleHandler, queue:nil)
    }
}
class BLEHandler: NSObject, CBCentralManagerDelegate{
    override init(){
        super.init()
    }
    func centralManagerDidUpdateState(central: CBCentralManager!){
        switch(central.state){
        case .Unsupported:
            println("not supported")
        case .Unauthorized:
            println("not authorized")
        case .Unknown:
            println("ble unknown")
        case .Resetting:
            println("resetting")
        case .PoweredOff:
            println("powered off")
        case .PoweredOn:
            println("powered on")
            central.scanForPeripheralsWithServices(nil, options: nil)
        default:
            println("ble default")
        }
    }
    func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject:AnyObject]!,RSSI:NSNumber!)
    {
        central.connectPeripheral(peripheral, options: nil)
        var pName=peripheral.name
        println("\(pName):\(RSSI) dbm")
        let defaults = NSUserDefaults.standardUserDefaults()
        defaults.setObject("test", forKey: "variable")
    }
}
Ross M.
  • 313
  • 2
  • 13
  • Ok, I put it in the viewDidLoad method like so: `override func viewDidLoad() { let defaults = NSUserDefaults.standardUserDefaults() let name = defaults.stringForKey("variable") println(name) super.viewDidLoad()}` but I'm still getting `nil` – Ross M. Apr 19 '15 at 03:20
  • test needs to be defined in BLEHandler class because that's where the source of it is actually going to be found...if I define it in ViewController then that seemingly negates the whole purpose of NSUserDefaults, as I could just access it another way, since the reference would be from within the same class which defined `test` in the first place... – Ross M. Apr 19 '15 at 03:28
  • gotcha! well in that case, the test worked. when i define `test` within the same class i access it, NSUserDefaults works just fine. but its when I define `test` in a different class that i get `nil`. – Ross M. Apr 19 '15 at 03:36
  • When you save it to disk the class where you saved it makes no difference. Can you post the full code so that I can show you what you are doing wrong? – Leo Dabus Apr 19 '15 at 03:49
  • If you define it in a different view controller it has to be loaded before you try to access it otherwise you would be trying to access a value that has never being saved to disk – Leo Dabus Apr 19 '15 at 04:03
  • This is not a good use for user defaults. Sure, you can make it work, but user defaults are for persisting data between launches, not for passing data around within an app. – rdelmar Apr 19 '15 at 04:07
  • @rdelmar yeah, I understand it's not the orthodox way to use it. What would you recommend? – Ross M. Apr 19 '15 at 04:21
  • How to do it depends on your structure. Does ViewController create BLEManager? What does BLEManager do, and why do you need a separate class of BLEHandler (who creates that one)? – rdelmar Apr 19 '15 at 04:23
  • Not sure if I'm knowledgable enough to answer that, but as I see it, BLEManager initializes the BLEHandler class. ViewController doesn't create either of them. – Ross M. Apr 19 '15 at 04:28
  • So the method centralManager saves your string to disk. Can you see it printing to your console when it didDiscoverPeripheral? – Leo Dabus Apr 19 '15 at 04:46
  • all it prints when i press the button is `nil`. – Ross M. Apr 19 '15 at 04:50
  • I didn't asked when you press the button I asked if it prints ("\(pName):\(RSSI) dbm") when didDiscoverPeripheral gets called (if it does get called) – Leo Dabus Apr 19 '15 at 04:52
  • oh! no, it doesnt. that's a whole other issue though, from what i can see anyway. I mean...in the future I want my ViewController to be able to access the pName variable, but there's a lot of work to be done before that happens, so I'm just substituting the `test` variable for now to see if I can access _anything_ at all in BLEHandler from ViewController. – Ross M. Apr 19 '15 at 04:54
  • So you should change your question and ask how to make that method work. Your question is not about how nsuserdefaults works – Leo Dabus Apr 19 '15 at 04:59
  • Are you leaving time between storing the value and calling it? I seem to remember having a similar issue because the storage didn't happen instantly. Try having one button do the storing and another button pressed slightly later to retrieve. – sketchyTech Apr 19 '15 at 07:14
  • I don't see anywhere that you create an instance of BLEManager. Your view controller should instantiate that, in which case you would have a property that points to that instance. You can then use that to access any property or method in the BLEManager class, including bleHandler. – rdelmar Apr 20 '15 at 03:17

4 Answers4

0

Use NSNotification. Post notification in BLEHandler, add observer in your viewController, pass variable by userInfo parameter.

Allen
  • 6,745
  • 5
  • 41
  • 59
0

Like you said, you used NSUserDefaults as the way to store data. I think you probably forget the Archived/UnArchived process to unwrap the Archived data.

  • Store Data to NSUserDefaults.

    let defaults = NSUserDefaults.standardUserDefaults()
    let test = NSKeyedArchiver.archivedDataWithRootObject(the instance of your Data Class)
    defaults.setObject(test, forKey: "variable")
    defaults.synchronize()
    
  • Read the data from NSUserDefaults.

    let defaults = NSUserDefaults.standardUserDefaults()
    if let test = defaults.dataForKey("variable") {
        let name = NSKeyedUnarchiver.unarchiveObjectWithData(test) as? Card
        }
    

Hope my answer can help you.

Yichen Zhou
  • 436
  • 6
  • 21
0

Set the value in NSUserDefaults

 NSUserDefaults.standardUserDefaults().setObject(newValue, forKey: "variable")
 //NSUserDefaults.standardUserDefaults().setObject(newValue as [NSString], forKey: "variable")
 NSUserDefaults.standardUserDefaults().synchronize()

Retrive the data from NSUserDefaults

 let name = NSUserDefaults.standardUserDefaults().objectForKey("variable") as? [NSString]
Nischal Hada
  • 3,230
  • 3
  • 27
  • 57
-1

Your value or NSUserDefault is nil because you need to synchronize it after setting the value

let defaults = NSUserDefaults.standardUserDefaults() 
defaults.setObject("test", forKey: "variable")
defaults.synchronize()
Arun Gupta
  • 2,628
  • 1
  • 20
  • 37
  • Calling synchronize is unnecessary in this case and is likely not the problem. https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/index.html#//apple_ref/occ/instm/NSUserDefaults/synchronize – Mike Apr 19 '15 at 05:26
  • I think rosa can confirm on this. We used ti have the same problem and using synchronize solved our problem. – Arun Gupta Apr 19 '15 at 05:42