Swift代码使用NSOutlineView作为文件系统目录浏览器 [英] Swift code to use NSOutlineView as file system directory browser

查看:230
本文介绍了Swift代码使用NSOutlineView作为文件系统目录浏览器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在这个Swift代码中遇到了一段时间,没有找到问题。以下代码
应为NSOutlineView提供File Directory作为DataSource。 GUI是非常简单的
只是一个带有NSOutlineView的窗口和一个用于OutlineViewController实例的对象。
当我启动应用程序时,它显示根条目,当我展开root条目时,它会显示一个短时间的子项。然后应用程序在NSApplicationMain(C_ARGC,C_ARGV) - >EXC_BAD_ACCESS(code = EXC_I386_GPFLT)的文件main.swift中出现错误?

I'm struggling with this Swift code already for some time and do not find the problem. The code below should provide the File Directory as DataSource for a NSOutlineView. The GUI is quite simple just a window with a NSOutlineView and a Object for the OutlineViewController instance. When I start the application it shows the root entry, when I expand the root entry it shows for a short period the sub items. Then the application crashes with an Error in file "main.swift" at line "NSApplicationMain(C_ARGC, C_ARGV) --> "EXC_BAD_ACCESS(code=EXC_I386_GPFLT)" ?

如果添加一些println()来证明目录结构 - 这似乎很好。

If added some println() to proof the directory structure - this seems to be fine.

快速代码:

import Cocoa
import Foundation

class FileSystemItem {

    let propertyKeys = [NSURLLocalizedNameKey, NSURLEffectiveIconKey, NSURLIsPackageKey, NSURLIsDirectoryKey,NSURLTypeIdentifierKey]
    let fileURL: NSURL

    var name: String! {
    let resourceValues = fileURL.resourceValuesForKeys([NSURLNameKey], error: nil)
        return resourceValues[NSURLNameKey] as? NSString
    }

    var localizedName: String! {
    let resourceValues = fileURL.resourceValuesForKeys([NSURLLocalizedNameKey], error: nil)
        return resourceValues[NSURLLocalizedNameKey] as? NSString
    }

    var icon: NSImage! {
    let resourceValues = fileURL.resourceValuesForKeys([NSURLEffectiveIconKey], error: nil)
        return resourceValues[NSURLEffectiveIconKey] as? NSImage
    }

    var dateOfCreation: NSDate! {
    let resourceValues = self.fileURL.resourceValuesForKeys([NSURLCreationDateKey], error: nil)
        return resourceValues[NSURLCreationDateKey] as? NSDate
    }

    var dateOfLastModification: NSDate! {
    let resourceValues = fileURL.resourceValuesForKeys([NSURLContentModificationDateKey], error: nil)
        return resourceValues[NSURLContentModificationDateKey] as? NSDate
    }

    var typeIdentifier: String! {
    let resourceValues = fileURL.resourceValuesForKeys([NSURLTypeIdentifierKey], error: nil)
        return resourceValues[NSURLTypeIdentifierKey] as? NSString
    }

    var isDirectory: String! {
    let resourceValues = fileURL.resourceValuesForKeys([NSURLIsDirectoryKey], error: nil)
        return resourceValues[NSURLIsDirectoryKey] as? NSString
    }

    var children: [FileSystemItem] {

        var childs: [FileSystemItem] = []
        var isDirectory: ObjCBool = ObjCBool(1)
        let fileManager = NSFileManager.defaultManager()
        var checkValidation = NSFileManager.defaultManager()

        if (checkValidation.fileExistsAtPath(fileURL.relativePath)) {

            if let itemURLs = fileManager.contentsOfDirectoryAtURL(fileURL, includingPropertiesForKeys:propertyKeys, options:.SkipsHiddenFiles, error:nil) {

                for fsItemURL in itemURLs as [NSURL] {

                    if (fileManager.fileExistsAtPath(fsItemURL.relativePath, isDirectory: &isDirectory))
                    {
                        if(isDirectory == true) {
                            let checkItem = FileSystemItem(fileURL: fsItemURL)
                            childs.append(checkItem)
                        }
                    }

                }
            }
        }
        return childs
    }

    init (fileURL: NSURL) {
        self.fileURL = fileURL
    }

    func hasChildren() -> Bool {
        return self.children.count > 0
    }

}


class OutlineViewController : NSObject, NSOutlineViewDataSource {

    let rootFolder : String = "/"
    let rootfsItem : FileSystemItem
    let fsItemURL : NSURL
    let propertyKeys = [NSURLLocalizedNameKey, NSURLEffectiveIconKey, NSURLIsPackageKey, NSURLIsDirectoryKey,NSURLTypeIdentifierKey]

    init() {

        self.fsItemURL = NSURL.fileURLWithPath(rootFolder)
        self.rootfsItem = FileSystemItem(fileURL: fsItemURL)

        for fsItem in rootfsItem.children as [FileSystemItem] {
            for fsSubItem in fsItem.children as [FileSystemItem] {
                println("\(fsItem.name) - \(fsSubItem.name)")
            }

        }
    }

    func outlineView(outlineView: NSOutlineView!, numberOfChildrenOfItem item: AnyObject!) -> Int {
        if let theItem: AnyObject = item {
            let tmpfsItem: FileSystemItem = item as FileSystemItem
            return tmpfsItem.children.count
        }
        return 1
    }

    func outlineView(outlineView: NSOutlineView!, isItemExpandable item: AnyObject!) -> Bool {
        if let theItem: AnyObject = item {
            let tmpfsItem: FileSystemItem = item as FileSystemItem
            return tmpfsItem.hasChildren()
        }
        return false
    }

    func outlineView(outlineView: NSOutlineView!, child index: Int, ofItem item: AnyObject!) -> AnyObject! {
        if let theItem: AnyObject = item {
            let tmpfsItem: FileSystemItem = item as FileSystemItem
            return tmpfsItem.children[index]
        }
        return rootfsItem
    }

    func outlineView(outlineView: NSOutlineView!, objectValueForTableColumn tableColumn: NSTableColumn!, byItem item: AnyObject!) -> AnyObject! {
        if let theItem: AnyObject = item {
            let tmpfsItem: FileSystemItem = item as FileSystemItem
            return tmpfsItem.localizedName
        }
        return "-empty-"
    }
}



class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet var window: NSWindow

    func applicationDidFinishLaunching(aNotification: NSNotification?) {
        // Insert code here to initialize your application

    }

    func applicationWillTerminate(aNotification: NSNotification?) {
        // Insert code here to tear down your application

    }
}

任何提示?

推荐答案

只是为了澄清发生了什么。 NSOutlineView不保留为其model提供的对象;客户一直希望保留它们。对于ARC代码,这不行,因为如果将新实例返回给NSOutlineView方法,则该对象不会被任何东西保留,并将快速释放。然后随后的outlineView委托方法触摸这些对象将导致崩溃。解决方案是将对象自己保留在自己的数组中。

So, just to clarify what is going on. NSOutlineView does not retain objects that it is given for its "model"; it was always expected that the client would retain them. For ARC code, this doesn't work well, because if you return a new instance to the NSOutlineView methods the object will not be retained by anything and will quickly be freed. Then subsequent outlineView delegate methods the touch these objects will lead to crashes. The solution to that is to retain the objects yourself in your own array.

请注意,从objectValueForTableColumn返回的对象由NSControl的objectValue保留。

Note that the objects returned from objectValueForTableColumn are retained by the NSControl's objectValue.

返回Swift:由于Thomas注意到对象必须是objc对象,因为它们被桥接到一个objc类。 Swift字符串隐式地桥接到临时NSString。由于上述问题,导致崩溃,因为没有保留NSString实例。这就是为什么要维护一个NSStrings数组解决这个问题。

Back to Swift: As Thomas noted the objects have to be objc objects since they are bridged to an objc class. A Swift string is implicitly bridged to a temporary NSString. This leads to a crash because of the above issue, since nothing retains the NSString instance. That is why maintaining an array of NSStrings "solves" this problem.

解决方案是NSOutlineView有一个选项来保留给它的项目。请考虑记录一个错误请求,以通过bugreporter.apple.com来执行此操作。

The solution would be for NSOutlineView to have an option to retain the items given to it. Please consider logging a bug request for it to do this through bugreporter.apple.com

感谢
corbin(我在NSOutlineView上工作)

Thanks, corbin (I work on NSOutlineView)

这篇关于Swift代码使用NSOutlineView作为文件系统目录浏览器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆