在Swift 4.2中使用UILocalizedIndexedCollat​​ion创建tableView部分索引时出现错误“无法识别的选择器发送到实例”

时间:2019-01-25 04:52:50

标签: ios swift uilocalizedcollation

我正在尝试构建一个模仿iPhone的“通讯录”应用程序的应用程序。在这个过程中,我试图将节索引放在联系人的tableView的右侧。 Apple的iOS文档“表格视图编程指南”建议使用UILocalizedIndexedCollat​​ion类。问题似乎出在collat​​ionStringSelector上。在Swift 4中,选择器需要公开给@objc,无论如何我都找不到,而且我尝试过的所有内容都会出现以下错误消息:

  

***由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'-[NSTaggedPointerString localizedTitle]:无法识别的选择器已发送至实例

我试图将选择器对象放入其自己的类中,以便可以将其公开给@objc,但这没有用。这是我尝试的代码:

class SelectorObj: NSObject {

    @objc var selector: Selector

    init(selector: Selector) {
        self.selector = selector
    }
}

返回基线代码。这是我正在尝试的示例代码。

class ObjectTableViewController: UITableViewController {

    let collation = UILocalizedIndexedCollation.current()
    var sections: [[AnyObject]] = []
    var objects: [AnyObject] = [] {
        didSet {
            let selector: Selector = #selector(getter: UIApplicationShortcutItem.localizedTitle)
            sections = Array(repeating: [], count: collation.sectionTitles.count)

            let sortedObjects = collation.sortedArray(from: objects, collationStringSelector: selector)
            for object in sortedObjects {
                let sectionNumber = collation.section(for: object, collationStringSelector: selector)
                sections[sectionNumber].append(object as AnyObject)
            }

            self.tableView.reloadData()
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        objects = (["One", "Two", "Three"] as [AnyObject])
    }

    // MARK: UITableViewDelegate

    override func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sections[section].count

    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        let cellData = sections[indexPath.section][indexPath.row]
        cell.textLabel!.text = (cellData as! String)
        return cell
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return collation.sectionTitles[section]
    }

    override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
        return collation.sectionIndexTitles
    }

    override func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
        return collation.section(forSectionIndexTitle: index)
    }
}

预期结果是像在iPhone的“联系人”应用程序中那样,使tableView的联系人列表的右侧下方的部分索引(A ... Z,#)

1 个答案:

答案 0 :(得分:0)

您传递给sortedArray(from:collationStringSelector:)的选择器必须是要排序的对象类型上的选择器。您在数组中的对象上没有localizedTitle属性。

通常,您将具有要排序的类或结构的数组,并且将传递类或结构的某些属性的选择器。

但是您的数组是String的数组。因此,您需要一个String属性,该属性返回用于排序的字符串。

由于选择器的使用基于旧的Objective-C框架,因此该属性需要公开给Objective-C。

String数组一起使用的一件事是使用选择器NSString.description。之所以可行,是因为Swift String可以桥接到NSString

您需要做的另一件事是将数组类型从AnyObject更改为实际的类型-String

var sections: [[String]] = []
var objects: [String] = [] {
    didSet {
        let selector: Selector = #selector(NSString.description)
        sections = Array(repeating: [], count: collation.sectionTitles.count)

        let sortedObjects = collation.sortedArray(from: objects, collationStringSelector: selector)
        for object in sortedObjects {
            let sectionNumber = collation.section(for: object, collationStringSelector: selector)
            sections[sectionNumber].append(object)
        }

        self.tableView.reloadData()
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    objects = ["One", "Two", "Three"]
}

更新您的其他尝试投射这些值as String的代码,因为不再需要这些值。