简体   繁体   中英

How to use Swift generics to pass a type and return an object as that type?

I'm writing a function that, given a type, simply unarchives an object from the disk and returns it as that type. This is what it looks like:

public class func objectWithFileName<T>(fileName: String, inFolder folder: NSSearchPathDirectory) -> T? {
    // Build an NSURL var called fileURL based on the fileName and folder.
    // ...

    // If any object was found
    if let object: AnyObject = NSKeyedUnarchiver.unarchiveObjectWithFile(fileURL.path!) {
        // Attempt to return the object as an object of type T.
        if let typedObject = object as? T {
            return typedObject
        }
    }
    return nil
}

The planned way of consuming the function is this, and it doesn't work (I'm getting "Cannot specialize a non-generic definition"):

if let user = MQFileManager.objectWithFileName<User>("User", inFolder: .DocumentDirectory) {

}

How can I pull this off correctly?

If you specify the type of the variable the return value is assigned to, type inference can do the rest. So if you have a User type, simply invoke the function as follows:

if let user: User = MQFileManager.objectWithFileName("User", inFolder: .DocumentDirectory) {

}

Since the user variable is of User type, the compiler can infer the T generic to be of User type

You need pass the type into the arguments

public class func objectWithFileName<T>(fileName: String, inFolder folder: NSSearchPathDirectory, type:T.Type) -> T? {
    // Your function detail
}

Then using it like this

MQFileManager.objectWithFileName("User", inFolder: .DocumentDirectory, type:User.self)

I made a generic class to help me manager file in Swift, I believe this can help you with your question.

It is my load method

static func loadFile<T:TCFileData>(#name:String, classType:T.Type)->T!
{
    var data:T?;

    if(hasFile(name: name))
    {
        if let rawData = NSData(contentsOfFile: getPath(name) as String) {
            var object: AnyObject? = NSKeyedUnarchiver.unarchiveObjectWithData(rawData);
            data = object as? T;
        }
    }

    return data;
}

static func loadFile<T:TCFileData>(classType:T.Type)->T!
{
    return loadFile(name: getFileName(classType), classType:classType);
}

I upload this code to GitHub repository , there has complete class

Implementation

With this class, I called TCFile, you can implement this way to save many class in your drive

 //TCFileData is a "protocol" to save with TCFile
 class MySaveClass:TCFileData
 {
   //implement your class with NSCode and NSCoding pattern
 }

 TCFile.save(name:"someId", object: MySaveClass());
 let mySaveClass = TCFile.loadFile(name:"someId", classType: MySaveClass.self);

or other simple mode, this way is recommended in case you save the same object all time, you don't need many object from this object.

 let mySaveClass = MySaveClass()
 TCFile.save(mySaveClass)
 let mySaveClassFromDisc = TCFile.loadFile(MySaveClass.self)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM