-2

it's been 1.5 years i've been writing in obj-c, its a good language.. so i saw a medium article today about swift, really looking onto it, right now i am trying to convert all my obj-c codes to swift, fortunately everything is done expect for this part..

NSString *path = [[NSBundle mainBundle] pathForResource:@"list" ofType:@"plist"];
    NSArray *plistData = [NSArray arrayWithContentsOfFile:path];

    NSPredicate *filter = [NSPredicate predicateWithFormat:@"english ==[c] %@", self.userQuery.text]; // something like "Abbey"
    NSArray *filtered = [plistData filteredArrayUsingPredicate:filter];



    NSLog(@"found matches: %@ : %@", filtered,[filtered valueForKey:@"kurdi"]);

    if (filtered.count>0) {
        NSDictionary *dic  = filtered[0];
        self.theMeaningLabel.text = dic[@"kurdi"];


    } else {
         self.theMeaningLabel.text = @"Yay!‌";
    }

i am not being able to properly convert this into the new swift 4, it gives random errors

EDIT

after a few searches, i could just write two lines of code here's my swift code

    var path: String? = Bundle.main.path(forResource: "list", ofType: "plist")
    var plistData = [Any](contentsOfFile: path!)
    var filter = NSPredicate(format: "english ==[c] %@", searchText)
    // something like "Abbey"
    var filtered = plistData?.filter { filter.evaluate(with: $0) }
    print("found matches: \(filtered) : \(filtered?.value(forKey: "kurdi"))")
    if filtered?.count > 0 {
        var dic = filtered[0]
       // theMeaningLabel.text = dic["kurdi"]
    }
    else {
        //theMeaningLabel.text = "Yay!‌"
    }

but getting the

Argument labels '(contentsOfFile:)' do not match any available overloads

Final edit

 var path = Bundle.main.path(forResource:"list", ofType: "plist")
var plistData = NSArray(contentsOfFile: path!)

let filter = NSPredicate(format: "english ==[c] %@", searchText)
var filtered = plistData?.filtered(using: filter)
// [error 9:10] no viable alternative at input 'NSLog(@"found matches: %@ : %@"'
if filtered?.count > 0 {
    var dic = filtered![0]
   // theMeaningLabel.text = dic["kurdi"]
}
else {
   // theMeaningLabel.text = "Yay!‌"
}

the code above is fine, but one error comes

if filtered?.count > 0 { // here
    var dic = filtered![0]
   // theMeaningLabel.text = dic["kurdi"]
}
else {
   // theMeaningLabel.text = "Yay!‌"
}

getting

Binary operator '>' cannot be applied to operands of type 'Int?' and 'Int'

rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • Don’t show the Objective-C, show the Swift and the errors you are getting. – Paulw11 Nov 07 '17 at 08:17
  • @Paulw11, actually can't get my head around it, stuck in the predicate format, waiting for someone to give a proper clean code –  Nov 07 '17 at 08:18
  • The predicate format is exactly the same since that is part of the foundation library, not Swift or Objective-C. – Paulw11 Nov 07 '17 at 08:20
  • `let resultPredicate = NSPredicate(format: "english ==[c] %@", searchText)` , yeah i got this but the line after this is complex –  Nov 07 '17 at 08:21
  • If you are still using `NSArray` then the next line is essentially the same too. – Paulw11 Nov 07 '17 at 08:23
  • @Paulw11, just updated the question –  Nov 07 '17 at 08:26
  • @RawandAhmedShaswar you can use https://objectivec2swift.com/#/converter/ for converting your objective c code into swift. – KAR Nov 07 '17 at 08:27
  • @KAR, thank you, but i don't think that this site would be that much smart, so updated the question, the one i converted with them returns an error too –  Nov 07 '17 at 08:31
  • you had the right code before using `Data`. – Paulw11 Nov 07 '17 at 08:33
  • @Paulw11, same property list –  Nov 07 '17 at 08:35
  • @RawandAhmedShaswar is `plistData` is array of keypair? – Jack Nov 07 '17 at 08:48
  • @Jack, question updated –  Nov 07 '17 at 08:50
  • 3
    Possible duplicate of [How to use native Swift way to Read Plist in Swift 3?](https://stackoverflow.com/questions/40436895/how-to-use-native-swift-way-to-read-plist-in-swift-3) – Vishal Patel Nov 07 '17 at 08:55
  • 1
    @VishalPatel, do not mark questions without truly reading both sides, you gave a wrong code, i appreciate it, but this is not a duplicate, i solved it myself ! –  Nov 07 '17 at 09:02

1 Answers1

2

A literal translation from Objective-C to Swift is not recommended because in many cases it does not take advantage of the improved semantics of Swift.

As Apple removed all path manipulating API from String and added more URL related API to other classes use always URL if possible

let url = Bundle.main.url(forResource: "list", withExtension: "plist")!

The forced unwrapped url is safe since the file is required to be in the bundle. A crash will reveal a design error and must not happen at runtime.


Unlike the Foundation collection types the Swift collection types don't support the implicit property list conversion so the Swift way is to use Data and PropertyListSerialization

let data = try! Data(contentsOf: url)
let dataArray = try! PropertyListSerialization.propertyList(from: data, format: nil) as! [Any]

The forced try! is as safe as forced unwrapping the url for the same reasons.

[Any] is the most unspecified Swift Array. If the array is supposed to be an array of dictionaries write [[String:Any]] or even [[String: String]] if all values are String. If it's supposed to be an array of Strings write [String]. Swift encourages the developer to be as type specific as possible.


An NSPredicate can be replaced with the filter function in Swift. For example an array of strings can be filtered case insensitively with

let filtered = dataArray.filter { $0.compare(searchText, options:.caseInsensitive) == .orderedSame }

If the array contains dictionaries you need to specify the keys (same as NSPredicate)

let filtered = dataArray.filter { ($0["foo"] as! String).compare(searchText, options:.caseInsensitive) == .orderedSame }

Finally the ObjC expression

 if (filtered.count > 0) { ...

can be written much more descriptive in Swift

 if filtered.isEmpty == false { ...

or

 if !filtered.isEmpty { ...

If you are looking for only one item you can even write

if let foundObject = dataArray.first(where: { $0.compare(searchText, options:.caseInsensitive) == .orderedSame }) { ...
vadian
  • 274,689
  • 30
  • 353
  • 361
  • the last time i had a problem with obj-c you helped, and again, sof needs more people like you –  Nov 07 '17 at 09:14