Search code examples
iosobjective-cswiftplist

Error Cannot subscript a value of type 'Dictionary<NSObject, AnyObject>' with an index of type 'String'


Can someone help me? I am just reprogramming my small project from Objective-C to Swift and get the following error:

Cannot subscript a value of type 'Dictionary' with an index of type 'String'

eins, zwei, drei,and vier are strings that get their data from another view controller.

Objective-C Code:

@property (strong, nonatomic) IBOutlet UISwitch *bluetoothSwitch;

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSString *SwitchState;
    NSArray *myStrings = [[NSArray alloc] initWithObjects:eins,zwei,drei, vier, nil];
    SwitchState = [myStrings componentsJoinedByString:mad:" | | "];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:mad:"store.plist"];

    NSFileManager *fileManager = [NSFileManager defaultManager];

    if (![fileManager fileExistsAtPath: path]) {
        path = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat:mad:"store.plist"] ];
    }

    NSMutableDictionary *savedValue = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
    if ([[savedValue objectForKey:SwitchState] boolValue]) {
        self.bluetoothSwitch.on = [[savedValue objectForKey:SwitchState] boolValue];
    } else {
    }
}

My Swift Code:

var eins = "Test"
var zwei = "Text"
var drei = "Test"
var vier = "Text"
var SwitchState = ""
let myStrings = [eins, zwei, drei, vier]
SwitchState = myStrings.joined(separator: " | | ")
let paths = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
var path = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("store.plist").absoluteString

let fileManager = FileManager.default

if !fileManager.fileExists(atPath: path) {
    path = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("store.plist").absoluteString
}

var savedValue = NSDictionary(contentsOfFile: path) as Dictionary?
print("Das bekommt viewdid: \(SwitchState)")
if (savedValue?[SwitchState] as? NSNumber)?.boolValue ?? false {
    bluetoothSwitch.isOn = (savedValue?[SwitchState] as? NSNumber)?.boolValue ?? false
} else {
    print("nein")
}

This two Lines "produce" the Errors

if (savedValue?[SwitchState] as? NSNumber)?.boolValue ?? false {
    bluetoothSwitch.isOn = (savedValue?[SwitchState] as? NSNumber)?.boolValue ?? false

Solution

  • Please don't try to translate Objective-C code literally to Swift. There are many, many bad practices from the Swift perspective.

    Basically don't use NS... classes in Swift if there is a native counterpart.

    The error occurs because the result of a bridge cast from NSDictionary to Dictionary (without specifying the Swift types) is Dictionary<NSObject, AnyObject> which is not compatible with value type String

    This is a real Swift version:

    let eins = "Test"
    let zwei = "Text"
    let drei = "Test"
    let vier = "Text"
    let myStrings = [eins, zwei, drei, vier]
    let switchState = myStrings.joined(separator: " | | ")
    let fileManager = FileManager.default
    do {
        let applicationSupportDirectory = try fileManager.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
        let storeURL = applicationSupportDirectory.appendingPathComponent("store.plist")
    
        let data = try Data(contentsOf: storeURL)
        print("Das bekommt viewdid: \(switchState)")
        if let savedDictionary = try PropertyListSerialization.propertyList(from: data, format: nil) as? [String:Any],
            let savedState = savedDictionary[switchState] as? Bool {
            bluetoothSwitch.isOn = savedState
        } else {
            bluetoothSwitch.isOn = false
            print("nein")
        }
    } catch { print(error) }
    

    The fileExists(atPath check is redundant so I left it out.