1

Apple 将 NSPathControl 更改为与 Yosemite 中的 NSPathControlItem 一起使用。

但是从我坐的地方来看,这些新课程根本不起作用。我正在尝试在我的数据结构中显示自定义路径,但我在使用常规文件路径时遇到了类似的问题。是我还是苹果?

这是我的代码:

第一个片段的工作方式如下,它将显示一条路径。但这就是所有有效的方法。

//MARK: notifications
func selectionDidChange(notification : NSNotification)
{
    if let item = notification.object as? Group
    {
        //get "path" components
        var components : [String] = [item.title ?? "a"]
        var ancestor : Group? = item.parent
        while (ancestor != nil)
        {
            components.append(ancestor?.title ?? "b")
            ancestor = ancestor?.parent
        }
        components.append("")

       //convert to url
        let path = ("MyScheme:/" + "/".join(components.reverse()))
        pathControl?.URL = NSURL(string: path.stringByAddingPe
     }
 }

单击路径的任何部分以尝试从 NSPathControlItem 中获取任何属性根本不起作用。一切都返回零。

@IBAction func select(sender : AnyObject)
{
    println(sender.clickedPathItem??.title)
    println(sender.clickedPathItem??.URL)
}

如果我尝试使用 NSPathControlItem 构建路径,我无法设置任何属性(标题、url)。

    pathComponent.URL = NSURL(string: path.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!)
    //let url : NSURL? = NSURL(string: "/")
    //let path = NSURL(fileURLWithPath: "/") 
    //pathComponent.URL = path as NSURL
    pathComponent.attributedTitle = NSAttributedString(string: "/atttributes")
    self.pathControl?.pathItems = [pathComponent]
    println(pathComponent.description)

NSPathControlItem 也不应该被子类化。

这里发生了什么?

编辑

据我所知,NSPathControlItem 存在问题。创建 NSPathControlItem 的辅助函数。

    func pathItem(title: String, imageName: String) -> NSPathControlItem
{
    let item = NSPathControlItem()
    item.title = title
    item.image = NSImage(named: imageName)
    return item
}

创建 NSPathControlItem 并打印出它们的标题的测试函数。

    var pathItems : [NSPathControlItem] = []
    for title in ["a","b","c"]
    {
        pathItems.append(self.pathItem(title, imageName: NSImageNameFolder))
    }

    for item in pathItems
    {
        println(item.title)
    }

预期的输出是 a、b 和 c 的三行。我得到零,b,零。

如果您直接在 NSPathControl 上设置 pathItems,它将起作用。

self.pathControl?.pathItems = [
self.pathItem("a", imageName: NSImageNameFolder),
self.pathItem("b", imageName: NSImageNameFolder),
self.pathItem("c", imageName: NSImageNameFolder)]

但是,如果您间接设置 pathItems,那么一切都将陷入困境。

self.pathControl?.pathItems = pathItems //array of NSPathControl (see above)

编辑 2

我又看了一遍。我在 pathItem 函数中配置了一个 NSPathControlItem。这里我设置了标题。如果我设置属性标题没有区别。使用 lldb 检查项目会显示正确的(归属的)title 值。

但是当我将 NSPathControlItem 的数组分配给 NSPathControl 时,标题的值为“”,并且属性标题未初始化。

4

2 回答 2

8

NSPathControlItem严重损坏。从 10.11.3 开始,它包含以下由 Hopper 反编译的方法:

int -[NSPathControlItem release](int arg0) {
    [arg0->_secretCell autorelease];
    objc_assign_ivar(0x0, arg0, *_OBJC_IVAR_$_NSPathControlItem._secretCell);
    rax = [[arg0 super] release];
    return rax;
}

这显然应该是一个标准dealloc覆盖,它释放 ivar,将其清零,然后调用 super。但相反,由于某些可能与非法药物有关的未知原因,这是一种release超越。这意味着一旦这些物体之一被释放,即使在一些无害的操作过程中,它也会自毁并变得无法使用。

我创建了一些代码来使用运行时来消除错误的release覆盖并替换为正确的dealloc覆盖。这几乎没有经过测试,使用风险自负:

extension NSPathControl {
    class func fix() {
        let itemClass = NSPathControlItem.self
        let superclass: AnyClass = class_getSuperclass(itemClass)

        let releaseSelector = Selector("release")
        let releaseMethod = class_getInstanceMethod(itemClass, releaseSelector)
        let superReleaseIMP = class_getMethodImplementation(superclass, releaseSelector)

        if method_getImplementation(releaseMethod) != superReleaseIMP {
            method_setImplementation(releaseMethod, superReleaseIMP)

            let ivars = class_copyIvarList(itemClass, nil)
            var offsets: [Int] = []
            var cursor = ivars
            while cursor.memory != nil {
                let ivar = cursor.memory
                if String.fromCString(ivar_getTypeEncoding(ivar))?.hasPrefix("@") == true {
                    offsets.append(ivar_getOffset(ivar))
                }
                cursor++
            }
            free(ivars)

            let superDeallocIMP = class_getMethodImplementation(superclass, "dealloc")

            let dealloc: @convention(block) UnsafeMutablePointer<Int8> -> Void = { obj in
                for offset in offsets {
                    let ivarPtr = UnsafeMutablePointer<COpaquePointer>(obj + offset)
                    let unmanaged = Unmanaged<AnyObject>.fromOpaque(ivarPtr.memory)
                    unmanaged.release()
                    ivarPtr.memory = nil
                }

                typealias DeallocF = @convention(c) (UnsafeMutablePointer<Int8>, Selector) -> Void
                let superDeallocF = unsafeBitCast(superDeallocIMP, DeallocF.self)
                superDeallocF(obj, "dealloc")
            }
            let deallocIMP = imp_implementationWithBlock(unsafeBitCast(dealloc, AnyObject.self))

            class_addMethod(itemClass, "dealloc", deallocIMP, "v@:")
        }
    }
}
于 2016-02-09T18:00:54.513 回答
1

我认为它不仅充满了错误,而且也没有记录在案。AppKit 框架参考NSPathControlItem中缺少文档.. 太奇怪了。

我得到和你一样的结果。不过,这种使用的替代方法sender.clickedPathComponentCell()对我来说还可以:

class ViewController: NSViewController {
    @IBOutlet weak var pathControl: NSPathControl!

    override func viewDidLoad() {
        super.viewDidLoad()
        pathControl.URL = NSURL(fileURLWithPath: "/System/Library/Fonts")
    }

    @IBAction func pathItemSelected(sender: NSPathControl) {
        if let cell = sender.clickedPathComponentCell() {
            println(cell.URL)
        }
    }
}

这会正确打印我单击的部分路径。

于 2015-03-30T00:28:24.723 回答