首页 > 解决方案 > Swift - 如何使用类类型作为参数/变量

问题描述

我正在尝试创建一个有点通用的函数来根据属性的值对文件 URL 进行排序

我的目标是:

1) 将 URL 和一些参数(包括类型)传递给函数。然后将遍历文件的属性

2) 将匹配的文件属性和 URL 添加到元组数组中

3) 根据找到的属性值对元组进行排序

4)返回排序后的数组并按排序顺序显示项目

我相信我需要将属性的类型传递给排序函数,以便我能够在元组中设置它,因为我无法使用“Any”进行排序,但我不确定该怎么做

我可以将任何内容传递给排序函数并在排序函数中构造或解构我需要的值,因为这将根据用户选择的操作进行预定义

//Initial implementation to be later tied to IBActions and simplified   

func sortFiles(sortByKeyString : String, fileURLArray : [URL]) -> [URL] 
{

        switch sortByKeyString {
            case "date-created-DESC":
                let fileAttributeKeyString : String = "creationDate"
                let isSortOrderDesc = true
                let objectTypeString : String = NSDate.className()
                let sortedFileURLArray = sortFileArrayByType(fileAttributeKeyString: fileAttributeKeyString, fileURLArray: fileURLArray, type: objectTypeString, isSortOrderDesc : isSortOrderDesc)
                return sortedFileURLArray
            default:
                return fileURLArray
        }
    }

//Generic function to get a files attributes from a URL by requested 
type

    func sortFileArrayByType(fileAttributeKeyString : String, fileURLArray : [URL], type: String, isSortOrderDesc : Bool) -> [URL] {
        let fileManager = FileManager.default
        let attributeToLookFor : FileAttributeKey = FileAttributeKey.init(rawValue: fileAttributeKeyString)
        var tupleArrayWithURLandAttribute : [(url: URL, attribute: *Any*)]? = nil

        for url in fileURLArray {
            do {
                let attributes = try fileManager.attributesOfItem(atPath: url.path)
                for (key, value) in attributes {
                    if key.rawValue == fileAttributeKeyString {
                        tupleArrayWithURLandAttribute?.append((url: url, attribute: value))
                    }

                }
                let sortedTupleArrayWithURLandAttribute = tupleArrayWithURLandAttribute?.sorted(by: { $0.attribute < $1.attribute)})
                // Need to Sort dictionary into array
                return sortedTupleArrayWithURLandAttribute
            } catch {
                return fileURLArray
            }
        }
    }

标签: swiftmacoscocoa

解决方案


首先阅读The Swift Programming Language中的Metatype Type。阅读后继续回答。

从中您已经了解到,您可以将函数参数的类型声明为类型的类型(您可以交叉眼),AKA metatype,因此可以将类型传递给函数。将其与泛型和 Swift 的类型推断相结合,您可以将函数声明为:

func sortFileArrayByType<T>(fileAttributeKeyString : String,
                            attributeType : T.Type,
                            fileURLArray : [URL]
                           ) -> [(url: URL, attribute: T)]
                           where T : Comparable

这将添加attributeType类型为 where 的元类型T的参数T将被推断。例如,String.self可以传递元类型T并将被推断为String.

where子句进行了限制T,因此只有Comparable允许的类型,这是启用函数进行排序所必需的。文件属性可以是Date,StringNSNumber值; 不幸的是后者不符合,Comparable所以你需要添加一个扩展来实现它,以下就足够了:

extension NSNumber : Comparable
{
   public static func <(a : NSNumber, b : NSNumber) -> Bool { return a.compare(b) == .orderedAscending }
   public static func ==(a : NSNumber, b : NSNumber) -> Bool { return a.compare(b) == .orderedSame }
}

在函数体中,您需要将元组数组声明为具有 type 属性T

var tupleArrayWithURLandAttribute : [(url: URL, attribute: T)] = []

当您添加条目时,您需要将返回的值attributesOfItem转换为T

tupleArrayWithURLandAttribute.append((url: url, attribute: value as! T))

请注意as!这里的使用,您必须在函数调用中正确匹配属性名称及其值的类型,否则您将获得运行时中止。如果需要,将其作为软错误处理,留作练习。

您发布的代码中有许多拼写错误等,它们留给您修复,您的功能应该可以工作。调用可能如下所示:

let ans = sortFileArrayByType2(fileAttributeKeyString: "NSFileCreationDate",
                               attributeType: Date.self,
                               fileURLArray: urlArray)

在这种情况下的类型ans将是[(url: URL, attribute: Date)]

高温高压


推荐阅读