Search code examples
iosswiftuisearchbartypeerrornspredicate

Cast from 'String' to unrelated type 'LocationModel' always fails warning


In an NSArray, I need to filter all elements containing a searchKey (eg 39013). For now, I can print and see the values on Xcode but I want them on my device. I have two arrays. First one is:

var feedItems: NSArray = NSArray()

and the filtered one is

var filteredData:[String] = [] 

I print the filteredData and everything is as I wanted. Here is the problem I made a mistake on viewController while printing the lines.

if resultSearchController.isActive {

     let item: LocationModel = feedItems[indexPath.row] as! LocationModel 

I need to change .. = feedItems to .. = filteredData But when I change, since the filteredData is a String Array (Not an NSarray) I get an error:

Cast from 'String' to unrelated type 'LocationModel' always fails

Can you help me to fix the last problem? Thank you so much!!

Following is the Code:

Here is the object:

import UIKit
class LocationModel: NSObject {
    //properties
     var DesenNo: String?
     var Dolar: String?
     var Zemin: String?
     var En: String?
     var Euro: String?
     var Renk: String?
}

Solution

  • In Swift 3+ try to avoid (NS)Stuff like NSArray. Prefers the Swift version when available.

    You declared:

    var filteredData:[String] = [] 
    

    So filteredData will be an array of String, of ONLY String objects.

    Then you do

    let item: LocationModel = filteredData[indexPath.row] as! LocationModel 
    

    But you said previously that filteredData will be an array of String objects. So filteredData[indexPath.row] should be a String object. But you are trying to force cast it into a LocationModel object. The compiler is saying: That's not happening, I can't convert a String object into a LocationModel object.

    With NSArray, objects inside are of type Any. If you declare filteredData as NSArray but put inside LocationModel objects:

    let item: LocationModel = filteredDataAsNSArray[indexPath.row] as! LocationModel 
    

    That will crash, no doubt about it.

    There are still some issues, I think you want ta filteredData being of LocationModel objects

    Do this:

    var filteredData:[LocationModel] = []()
    var feedItems:[LocationModel] = []()
    

    The filtering: You want to filter on each values of your LocationModel so the predicate format should be:

    (SELF.DesenNo CONTAINS[c] %@) OR (SELF.Dolar CONTAINS[c] %@) OR (SELF.Zemin CONTAINS[c] %@) OR (SELF.En CONTAINS[c] %@) OR (SELF.Euro CONTAINS[c] %@) OR (SELF.Renk CONTAINS[c] %@)
    

    You could also use a Swift filter in pseudo code (not tested):

    let textToSearch = searchController.searchBar.text
    filteredData = feedItems.filter({$0.DesenNo.lowercased().contains(textToSearch.lowercased()) || $0.DesenNo.lowercased().contains(textToSearch.lowercased()) || ...})
    

    Also in tableView(_ tableView:, cellForRowAt:) you do the same thing again and again, that could should be factorized and for better clarity put into the MyTableCell code. This way you could do something like cell.updateWith(item:item) and it will be clearer.

    Edit: Last recommendation: Please rename your var starting with a lowercase (DesenNo => desenNo, etc.).