HiveBrain v1.2.0
Get Started
← Back to all entries
patternswiftMinor

Save File Manager

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
managersavefile

Problem

I made a class to manage saved file in drive with Swift, and I tried to do the best work.

Can someone get me a feedback about this class? What can I improve? Is this a good way to save a file?

```
import UIKit

class TCFileData:NSObject, NSCoding
{
override init() {
}

required init(coder aDecoder: NSCoder) {
}

func encodeWithCoder(aCoder: NSCoder) {
fatalError("encodeWithCoder(aCoder: NSCoder:) has not been implemented");
}
}

struct TCFile {

static func save(#name:String, object:T)->Bool
{
let path = getPath(name);
let saveData = NSKeyedArchiver.archivedDataWithRootObject(object);
return saveData.writeToFile(path as String, atomically: true);
}

static func save(object:T)->Bool
{
return save(name: NSStringFromClass(object.classForCoder), object: object);
}

static func hasFile(#name:String)->Bool
{
return NSFileManager.defaultManager().fileExistsAtPath(getPath(name) as String);
}

static func hasFile(classType:T.Type)->Bool
{
return hasFile(name: getFileName(classType));
}

static func loadFile(#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(classType:T.Type)->T!
{
return loadFile(name: getFileName(classType), classType:classType);
}

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

static func remove(#name:String)->Bool
{
if(hasFile(name: name))
{
return NSFileManager.defaultManager().removeItemAtPath(getPath(name) as String, error: nil);
}

return false;
}

Solution

Your organization is a bit confusing.

TCFileData is a hacked attempt to force abstract classes into a language without abstract classes, and TCFile is a hacked attempted at creating a namespace for a language that doesn't have namespaces, and your use of generics here seems unnecessary.

I think what makes more sense here is to completely eliminate the class and make the struct more of a wrapper object. The problem with the class is that it unnecessarily eliminates using your file management code with a plethora of existing objects which already conform to NSCoding (and that's all your code actually requires).

We want a class that starts off looking something like this:

class TCFileManager {
    var contents: T?
    var path: String

    init(path: String, contents: T? = nil) {
        self.path = path
        self.contents = contents
    }
}


And now, from here, we implement all of the methods your struct already implemented, but they mostly don't take arguments or return anything. Instead, they use the set values on their properties, and they set these values.

So, for example, we might want to load a dictionary I saved as a plist to my desktop:

let fileManager = TCFileManager(path: "/Users/nhgrif/Desktop/myPlist.plist")
fileManager.load()
let plist = fileManager.contents


Of course, we could also set load to return the loaded object in addition to setting the .contents property, but you get the gist.

Once we instantiate the file manager object with a path, a small set of methods can make a lot of things much easier to do.

Consider, we could also have a move method which takes a string parameter for the path to move the file to. The method would first do what you expect (move the file), but then the object's path property changes to the path passed in.

And obviously, you'd want to implement a save method as well, etc.

But I think converting your code into this sort of shape will make a lot of things make more sense and be easier to use.

Code Snippets

class TCFileManager<T: NSCoding> {
    var contents: T?
    var path: String

    init(path: String, contents: T? = nil) {
        self.path = path
        self.contents = contents
    }
}
let fileManager = TCFileManager<NSDictionary>(path: "/Users/nhgrif/Desktop/myPlist.plist")
fileManager.load()
let plist = fileManager.contents

Context

StackExchange Code Review Q#87084, answer score: 4

Revisions (0)

No revisions yet.