无法将“[Record]”类型的值转换为强制类型“记录” [英] Cannot convert value of type '[Record]' to type 'Record' in coercion
问题描述
我正在重写我使用C#和Xamarin制作的iOS应用程序到Swift,原因很明显是Xamarin的定价和低文档。关注本教程在我的 UITableView
上包含 UISearchBar
,我遇到了这个错误:无法转换类型'[Record]'的值在强制
中键入'Record'。 Record.swift是我创建的结构文件,用于存储我将使用cloudkit检索的数据,但我不确定这个错误是怎么回事。
Im re-writing an iOS app I made using C# and Xamarin to Swift for obvious reasons of Xamarin's pricing, and low documentation. Following this tutorial for including a UISearchBar
on my UITableView
, i ran into this error: Cannot convert value of type '[Record]' to type 'Record' in coercion
. Record.swift is a struct file I created to store the data that I will retrieve using cloudkit, but Im not sure how this error comes to be.
这是问题所在MasterViewController.swift的一部分:
Here is the problem part of 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:
Heres the full 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: "P.O.D.", 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:
And Record.swift:
import Foundation
struct Record {
let album : String
let artist : String
let genre : String
let year : Int
let speed : String
let size : Int
}
希望这将是一个简单的修复。如果没有,是否有任何教程建议?或者其他地方我应该问这个?
Hopefully it will be a simple fix. if not, are there any tutorial suggestions? or other places I should ask this instead?
推荐答案
filteredArrayUsingPredicate
是一个NSArray方法,所以你应该把它强制转换为NSArray:
filteredArrayUsingPredicate
is an NSArray method, so you should cast it to NSArray:
let array = (self.records as NSArray).filteredArrayUsingPredicate(searchPredicate)
但这仍然会产生错误[Record]无法转换为NSArray。这是因为NSArray只能包含Objective-C对象,而Record是一个Swift结构,不能转换为对象。有两种解决方案。
But this still generate an error "[Record] is not convertible to NSArray". This is because an NSArray can only contain Objective-C objects, and Record is a Swift struct and is not convertible to an object. There are two solutions.
解决方案1:
将记录声明为对象
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
}
}
然后是以下代码应该有效
Then the following code should works
let searchPredicate = NSPredicate(format: "SELF.artist CONTAINS [c] %@", searchController.searchBar.text!)
let array = (self.records as NSArray).filteredArrayUsingPredicate(searchPredicate)
self.filteredRecords = array as! [Record]
注意你的原始谓词没有意义,并且会导致运行时错误,因为记录不是字符串,所以我替换它。
Note your original predicate doesn't make sense, and would cause runtime error, because Record is not a String, so I replace it.
解决方案2:
使用Swift方式过滤:
Use the Swift way to filter:
let searchText = searchController.searchBar.text!.lowercaseString
filteredRecords = self.records.filter { (aRecord) -> Bool in
return aRecord.artist.lowercaseString.containsString(searchText)
}
这篇关于无法将“[Record]”类型的值转换为强制类型“记录”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!