【问题标题】:Cannot form weak reference to instance of class NSTextView无法形成对类 NSTextView 实例的弱引用
【发布时间】:2014-07-26 13:53:57
【问题描述】:

仅使用 Swift,这是我在 AppDelegate.swift 中的代码:

import Cocoa

class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet var window: NSWindow
    @IBOutlet var textField: NSTextView

    @IBAction func displaySomeText(AnyObject) {
        textField.insertText("A string...")
    }

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

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


}

在界面构建器中,我连接了一个对象以接收来自按钮的输入,然后将输出转到文本视图。当我点击按钮时,我试图让文本视图填充一些文本。

我也尝试使用文本字段进行此操作,但没有收到错误,但听到“dong”错误声音并且没有执行任何其他操作。在 Objective-C 中,您必须使用 (assign) 参数才能根据我的理解使其工作。

我做错了什么?

【问题讨论】:

  • This question 描述了如何在 swift 中使用弱引用。
  • 尝试在var前面使用weak,但没有区别。

标签: swift


【解决方案1】:

由于 Cocoa 和 AppKit 的历史问题,您无法存储对 NSTextView 的弱引用。见details in the Clang documentationNSTextViewNSTextView.h中标记为NS_AUTOMATED_REFCOUNT_WEAK_UNAVAILABLE,还有a few other classes要注意。

您是否尝试过使用 Swift 无主引用而不是弱引用,这有点像 Objective-C 的分配(您在 Objective-C 中用于 NSTextView 出口)?

【讨论】:

  • 哇,这太晦涩了:Google 上有 243 个结果。这是完整的 Swift 错误消息,以防人们在谷歌上感到困惑:“无法形成对 NSTextView 类的实例(0x ...)的弱引用。这个对象可能被过度释放,或者正在释放过程中。 "甚至看不到 Swift“标题”中的 NS_AUTOMATED_REFCOUNT_WEAK_UNAVAILABLE 标签!
  • Swift 3.1 似乎解除了这个限制。
  • @Feldur 仍然在 10.11,behaviour changed in 10.12
【解决方案2】:

使用@IBOutlet var scrollView: NSScrollView 而不是@IBOutlet var textField: NSTextView
然后在scrollView中创建一个返回documentView的属性。

import Cocoa

class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet var window: NSWindow
    @IBOutlet var scrollView: NSScrollView

    var textField: NSTextView {
        get {
            return scrollView.contentView.documentView as NSTextView
        }
    }

    @IBAction func displaySomeText(AnyObject) {
        textField.insertText("A string...")
    }

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

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

【讨论】:

  • 谢谢 - 又遇到一个错误。 'NSTextView' 不能转换为 'NSScrollView'
  • 你是用Interface Builder做scrollView的链接吗?我已经成功执行了上面的代码。
  • 可以分享一下项目文件吗?
  • @Steve See this helloworld.zip 使用 XCode 6 Beta (6A215l) 创建。
  • 谢谢!所以你真的做到了完全不同。这本书让我在按钮和与该功能相关的文本视图之间创建引用,但我在您的 xib 中只看到一个引用。我今天要更详细地研究这个。
【解决方案3】:

我已尝试复制您所描述的内容。我使用 Xcode 6 beta 7 创建了一个新的 OS X 应用程序。我在主窗体中放置了一个按钮和文本视图。

我认为您的问题是由于某种原因与文本视图对象的连接不正确。为了使事情更容易,我使用控制拖动连接了对象,它会自动添加所需的代码。所以首先我连接了文本视图。为此,请单击文本视图对象,直到选择文本视图。当我在我的 Xcode 版本中执行此操作时,第一次单击对象时,Bordered Scroll View 被选中。再次单击它然后选择剪辑视图。最后,再次单击它会选择 Text View。现在我从对象控制拖动到 AppDelegate.swift 代码(它有助于显示助手编辑器,以便您的表单 UI 和代码并排显示)。

通过这样做,我得到了这个小窗口:

注意类型为NSTextView,存储为Weak。我只需要添加名称并单击连接。这会在 AppDelegate.swift 中添加以下代码:

@IBOutlet var textField: NSTextView!

除了行尾的! 之外,该代码几乎与您的代码一模一样,它强制解开textField 的值。

就这样,您在问题中的代码应该可以工作。

我建议的另一件事是不要使用insertText。根据 Apple 的 NSTextView.insertText 文档:

此方法是插入用户键入的文本的入口点 并且一般不适合其他用途。程序化 文本的修改最好通过对文本存储进行操作来完成 直接。

据我了解,通过直接对文本存储进行操作来对文本进行编程修改意味着处理 NSText,NSTextView 继承自 NSText。所以改为使用NSText.string。这是我的代码中单击按钮操作的外观:

@IBAction func displaySomeText(sender: NSButton) {
    // If you want to add a new 'A string... ' every time you click the button
    textField.string! += "A string... "
    // otherwise just use
    //textField.string = "A string..."
} 

我以与添加文本视图出口相同的方式添加按钮操作,通过控制拖动,在这种情况下,选择NSButton 作为发送者,而不是保留默认的AnyObject .

【讨论】:

    【解决方案4】:

    @IBOutlet 自动使属性变弱 IIRC,但弱不会自动使属性成为可选。但是需要将弱属性设为可选,因为该属性可以随时被释放并设为 nil。所以你必须将你的@IBOutlets 声明为可选的。

    import Cocoa
    
    class AppDelegate: NSObject, NSApplicationDelegate {
    
        @IBOutlet var window: NSWindow? // Optional
        @IBOutlet var textField: NSTextView?
    
        @IBAction func displaySomeText(AnyObject) {
            textField?.insertText("A string...") // Only call the method if the object exists
        }
    
        func applicationDidFinishLaunching(aNotification: NSNotification?) {
            // Insert code here to initialize your application
        }
    
        func applicationWillTerminate(aNotification: NSNotification?) {
            // Insert code here to tear down your application
        }
    }
    

    【讨论】:

    • 谢谢。我也尝试了此代码,但仍然遇到相同的错误。
    【解决方案5】:

    “dong”错误是否表明响应者链有问题?如果在插入文本之前在文本字段上调用becomeFirstResponder 会怎样?

    【讨论】:

    • 首先在文本字段上尝试该方法时删除“dong”时运气不佳。这是代码的粘贴箱:pastebin.com/A2ZaXXPD
    【解决方案6】:

    要创建弱引用用户,请使用 weak 关键字:

    示例:

    @IBOutlet weak var myView: UIView
    

    你的情况

    @IBOutlet weak var textField: NSTextView
    

    【讨论】:

    • @IBOutlets 在 swift 中自动变弱。
    • 我遇到了同样的错误,不得不remove weak,此时它工作正常。我的源代码中的确切文本是@IBOutlet var CommentsTextView: NSTextView!
    猜你喜欢
    • 2017-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多