Objective-C style retrieving from .plist not working in Swift?

安稳与你 提交于 2020-01-06 12:17:16

问题


I was was retrieving data in a .plist in Objective-C whenever my view loaded by the following method -

@interface ListTableViewController ()

@end

@implementation ListTableViewController
NSArray *dict;

-(void)viewDidAppear:(BOOL)animated
{
    NSString *arr= [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

    arr=[arr stringByAppendingPathComponent:@"datalist.plist"];
    if ([[NSFileManager defaultManager]fileExistsAtPath:arr])
    {
       dict=[NSArray arrayWithContentsOfFile:arr];
        NSLog(@"%@",dict);

    }
    [self.tableView reloadData];

}

Now for Swift I am doing the same thing as -

class ListTableViewController: UITableViewController{
  var arr = NSArray()
  var plistfinalpath = String()

  override func viewDidAppear(animated: Bool){
      let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, .UserDomainMask, true)[0]
      plistfinalpath = path.stringByAppendingString("/login.plist")
      print(plistfinalpath)
      print("time of appearing\(arr)")

      arr = NSArray(contentsOfFile: plistfinalpath)!
      self.tableView.reloadData()
  }
}

But since I have to unwrap the value in the line arr = NSArray(contentsOfFile: plistfinalpath)! when the plist is empty when the app is launched for the first time the array is empty and since I am unwrapping it, it shows an error. So how can I achieve what I was doing in objective C?


回答1:


Just define your arr variable as optional, like this :
var arr:NSArray? = NSArray()

When a variable is defined as non optional, you cannot make it nil. The NSArray initializer you used is defined as public convenience init?(contentsOfFile path: String) - the ? means, that it can in fact return a nil. When you used !, you force unwrapped the value, which results in runtime crash when the value is nil.

As always, you can read more in the docs


Alternatively, you can do something like this :

if let tempArr = NSArray(contentsOfFile: plistfinalpath) {
    arr = tempArr
}

This way, you don't need to have your arr defined as optional and will only assign to it, when the contents of file where not empty.




回答2:


A complete answer involves understanding the concept of "optional".

What is an optional?

In Swift you can declare a variable as optional appending a ? after the type. When you do so, it means that the variable can hold a value or not at all. While when you declare a variable as non-optional, the compiler ensures that it holds a value at all times.

  • Declaring a variable as optional: var myOptionalVariable: NSArray?
  • Declaring a variable as not optional: var myVariable = NSArray()

Note how in the non optional var, we're forced by the compiler to give it a value (that in this case is just an empty array). This because the compiler grants that when a variable is not optional, it holds a value in every moment. Notice the difference: the first statement just declares the variable as an optional NSArray, the second statement initializes and assigns a new empty NSArray to the variable.

Why optional is useful?

With the introduction of optionals we have compile time safety about existence of the data contained on our variables. When not using an optional variable, we know for sure that a variable holds a value all the time. At the same time, when using an optional variable, we're forced to deal with the case where a value might be not there, instead of dealing with it silently (that is what happens with nil in objective-c). Extracting value from an optional is called unwrapping

Unwrapping Optionals (i.e. extract value from optional)

To "extract" the value from an optional variable, you need to unwrap it. There are several ways to unwrap an optional, given myOptional is an optional variable, here some examples:

if let variable = myOptional { 
    // I can safely use variable here
}

or even this other syntax:

variable = myOptional ?? defaultNonOptionalValue
// I can safely use variable here

Also, you can do a forced unwrap with

variable = myOptional!
// crash incoming?

You used this way to do the unwrap, but really you're saying to the compiler "Trust me, I know that myOptional will never be nil" that in your case is not true, and it leads to a crash with the error Fatal error: unexpectedly found nil while unwrapping an Optional values. You should always avoid forced unwrapped, unless you're really really sure about your data.

Long Story Short

You have 2 viable solutions:

  • Do not use forced unwrap (see options above about unwrapping)
  • Convert your variable arr to an optional (by declaring it in this way: var arr: NSArray?) and then deal with a (non-forced) unwrap when you use it (i.e. in your tableView datasource methods)

Which one is more correct for your case, depends on the arr meaning, if it makes sense to be optional, then go for it, otherwise, just leave it non optional and assign some default value.




回答3:


Just use the following code,

if let array = NSArray(contentsOfFile: plistfinalpath){
   arr = array
}

In swift, (!) is used to forced unwrapping an optional values. You should use that when the optionals have a value, otherwise you should use the above code.



来源:https://stackoverflow.com/questions/34154199/objective-c-style-retrieving-from-plist-not-working-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!