无法将“”类型的值转换为强制类型“记录”

我正在重写我使用C#和Xamarin制作的iOS应用程序到Swift,原因很明显是Xamarin的定价和低文档。 按照本教程在我的UITableView上包含UISearchBar ,我遇到了这个错误: Cannot convert value of type '[Record]' to type 'Record' in coercion 。 Record.swift是我创建的结构文件,用于存储我将使用cloudkit检索的数据,但我不确定这个错误是如何产生的。

这是MasterViewController.swift的问题部分:

 func updateSearchResultsForSearchController(searchController: UISearchController) { self.filteredRecords.removeAll(keepCapacity: false) let searchPredicate = NSPredicate(format: "SELF CONTAINS [c] %@", searchController.searchBar.text!) // Here is where the error shows let array = (self.records as Record).filteredArrayUsingPredicate(searchPredicate) self.filteredRecords = array as! [Record] self.tableView.reloadData() } 

下面是完整的MasterViewController.swift:

 import UIKit class MasterViewController: UITableViewController, UISearchResultsUpdating { var detailViewController: DetailViewController? = nil var resultSearchController = UISearchController() var records = [Record]() var filteredRecords = [Record]() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. self.navigationItem.leftBarButtonItem = self.editButtonItem() let addButton = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "insertNewObject:") self.navigationItem.rightBarButtonItem = addButton if let split = self.splitViewController { let controllers = split.viewControllers self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController } // #REMOVE - Testing implementation until iCloud is setup self.records = [ Record(album: "The Awakening", artist: "POD", genre: "Hardcore Rock", year: 2015, speed: "33 1/3", size: 12), Record(album: "Attack of The Killer B-Sides", artist: "A Day to Remember", genre: "Post-Hardcore", year: 2010, speed: "33 1/3", size: 7), Record(album: "All I Want", artist: "A Day to Remember", genre: "Post-Hardcore", year: 2011, speed: "33 1/3", size: 7), Record(album: "The White Stripes", artist: "The White Stripes", genre: "Rock", year: 2003, speed: "45", size: 7), Record(album: "Save Rock and Roll", artist: "Fall Out Boy", genre: "Punk Rock", year: 2013, speed: "33 1/3", size: 10), Record(album: "A Perfect Sky", artist: "Yellowcard", genre: "Pop-Punk", year: 2015, speed: "33 1/3", size: 10), Record(album: "Noise vs Beauty", artist: "Bassnectar", genre: "Dubstep", year: 2014, speed: "33 1/3", size: 12) ] // Configure the search bar controller self.resultSearchController = UISearchController(searchResultsController: nil) self.resultSearchController.searchResultsUpdater = self self.resultSearchController.dimsBackgroundDuringPresentation = false self.resultSearchController.searchBar.sizeToFit() self.tableView.tableHeaderView = self.resultSearchController.searchBar // Reload the data upon startup self.tableView.reloadData() } override func viewWillAppear(animated: Bool) { self.clearsSelectionOnViewWillAppear = self.splitViewController!.collapsed super.viewWillAppear(animated) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // func insertNewObject(sender: AnyObject) { // objects.insert(NSDate(), atIndex: 0) // let indexPath = NSIndexPath(forRow: 0, inSection: 0) // self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) // } // MARK: - Segues override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "showDetail" { if let indexPath = self.tableView.indexPathForSelectedRow { let object = records[indexPath.row] let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController controller.detailItem = object controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem() controller.navigationItem.leftItemsSupplementBackButton = true } } } // MARK: - Table View override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if (self.resultSearchController.active) { return self.filteredRecords.count } else { return self.records.count } } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell if (self.resultSearchController.active) { let object = filteredRecords[indexPath.row] cell.textLabel!.text = object.album cell.detailTextLabel!.text = object.artist cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator } else { let object = records[indexPath.row] cell.textLabel!.text = object.album cell.detailTextLabel!.text = object.artist cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator } return cell } override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { // Return false if you do not want the specified item to be editable. return true } override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if editingStyle == .Delete { records.removeAtIndex(indexPath.row) tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) } else if editingStyle == .Insert { // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view. } } func updateSearchResultsForSearchController(searchController: UISearchController) { self.filteredRecords.removeAll(keepCapacity: false) let searchPredicate = NSPredicate(format: "SELF CONTAINS [c] %@", searchController.searchBar.text!) let array = (self.records as Record).filteredArrayUsingPredicate(searchPredicate) self.filteredRecords = array as! [Record] self.tableView.reloadData() } } 

和Record.swift:

 import Foundation struct Record { let album : String let artist : String let genre : String let year : Int let speed : String let size : Int } 

希望这将是一个简单的解决方案。 如果没有,是否有任何教程建议? 或其他地方我应该问这个?

filteredArrayUsingPredicate是一个NSArray方法,因此您应该将其强制转换为NSArray:

 let array = (self.records as NSArray).filteredArrayUsingPredicate(searchPredicate) 

但是这仍然会产生错误“[Record]不能转换为NSArray”。 这是因为NSArray只能包含Objective-C对象,而Record是一个Swift结构,不能转换为对象。 有两种解决方案。

解决方案1:

将Record声明为对象

 class Record: NSObject { let album : String let artist : String let genre : String let year : Int let speed : String let size : Int init(album : String, artist : String, genre : String, year : Int, speed : String, size : Int) { self.album = album self.artist = artist self.genre = genre self.year = year self.speed = speed self.size = size } } 

那么下面的代码应该有效

 let searchPredicate = NSPredicate(format: "SELF.artist CONTAINS [c] %@", searchController.searchBar.text!) let array = (self.records as NSArray).filteredArrayUsingPredicate(searchPredicate) self.filteredRecords = array as! [Record] 

注意你的原始谓词没有意义,并且会导致运行时错误,因为Record不是String,所以我替换它。

解决方案2:

使用Swift方式过滤:

 let searchText = searchController.searchBar.text!.lowercaseString filteredRecords = self.records.filter { (aRecord) -> Bool in return aRecord.artist.lowercaseString.containsString(searchText) } 

因为我认为你的self.records类型是[Record] ,你试图把它作为单个Record而不是Array 。 所以这是不可能的。

尝试这个:

 let array = (self.records as [Record]).filteredArrayUsingPredicate(searchPredicate) 

更新:

像这样更新你的updateSearchResultsForSearchController方法:

 func updateSearchResultsForSearchController(searchController: UISearchController) { self.filteredRecords.removeAll(keepCapacity: false) self.filteredRecords = self.records.filter() { ($0.album.lowercaseString).containsString(searchController.searchBar.text!.lowercaseString) } self.tableView.reloadData() } 

如果要搜索albumartist替换此行:

 ($0.album.lowercaseString).containsString(searchController.searchBar.text!.lowercaseString) 

用这一行:

 ($0.album.lowercaseString).containsString(searchController.searchBar.text!.lowercaseString) || ($0.artist.lowercaseString).containsString(searchController.searchBar.text!.lowercaseString)