无法使用类型为“(字符串)”的参数列表调用 <method>

Posted

技术标签:

【中文标题】无法使用类型为“(字符串)”的参数列表调用 <method>【英文标题】:Cannot invoke <method> with and argument list of type '(String)' 【发布时间】:2015-04-12 00:46:09 【问题描述】:

我正在尝试编写一个 OSX 应用程序。这个应用程序的一个功能是它显示机器 IP 地址。 程序打开时获取地址(AppDelegate.swift):

@NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate 

      var ipadd:String = ""
      var path:String = ""
      var status:String = ""


      func applicationDidFinishLaunching(aNotification: NSNotification) 
             ipadd = getIFAddress()  //<-- ip stored in here as String
             println(ipadd)   //successfully prints out the ip
             ViewController.setIpDisp(ipadd)   //error on this line

      
   ...
 

在 ViewController.swift 中:

class ViewController: NSViewController 

    @IBOutlet weak var ip: NSTextField!
    ...

    func setIpDisp(ipin: String)
         ip.stringValue = ipin 
    

确切地说,错误是“无法使用类型为'(String)'的参数列表调用'setIpDisp'

谢谢

【问题讨论】:

函数不是静态的。您需要一个实例来调用它。我认为正确的想法是发送一条消息并在您的控制器中处理该消息。 【参考方案1】:

AppDelegate 正在尝试调用 ViewController 方法,该方法正在更新视图控制器视图中的 @IBOutlet。它需要一个有效的ViewController 实例来执行此操作。

但这是倒退的:应用程序委托不应该尝试调用视图控制器方法。视图控制器可以调用应用程序委托的方法/属性,但应用程序委托确实不应该调用视图控制器方法。

如果您需要更新视图控制器中的 IP 号字段,则视图控制器应该启动此操作(例如在 viewDidLoad 中):

class ViewController: NSViewController 

    @IBOutlet weak var ip: NSTextField!

    override func viewDidLoad() 
        super.viewDidLoad()

        updateIpDisp()
    

    func updateIpDisp() 
        let appDelegate = NSApplication.sharedApplication().delegate as! AppDelegate

        ip.stringValue = appDelegate.getIFAddress()
    


或者,如果您愿意,AppDelegate 在其init 方法(不是applicationDidFinishLaunching)中设置一些ipadd 字符串属性,然后updateIpDisp() 方法可以从应用程序委托中检索属性的值,也。 (鉴于 IP 编号是动态的并且可以更改,这对我来说似乎不正确,但可以随心所欲。)无论如何,这可能看起来像:

class AppDelegate: NSObject, NSApplicationDelegate 

    var ipadd: String!

    override init() 
        super.init()

        ipadd = getIFAddress()
    


class ViewController: NSViewController 

    @IBOutlet weak var ip: NSTextField!

    override func viewDidLoad() 
        super.viewDidLoad()

        updateIpDisp()
    

    func updateIpDisp() 
        let appDelegate = NSApplication.sharedApplication().delegate as! AppDelegate

        ip.stringValue = appDelegate.ipadd
    


但是视图控制器应该从应用代理请求 IP 号并更新它自己的视图。但应用委托在视图控制器中没有业务调用方法。

【讨论】:

这个实际上效果更好。使用第一种方法时,我遇到了一些包装问题。我在某处读到程序变量应该从那里存储在 AppDelegate 上。所以我会把它设置在那里,并在那里访问它。我将改用这种方式。谢谢@Rob【参考方案2】:

你的函数不是静态的,所以一定要初始化它的一个实例,像这样

    @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate 
      let viewController = ViewController()

      var ipadd:String = ""
      var path:String = ""
      var status:String = ""


      func applicationDidFinishLaunching(aNotification: NSNotification) 
             ipadd = getIFAddress()  //<-- ip stored in here as String
             println(ipadd)   //successfully prints out the ip
             viewController.setIpDisp(ipadd)   //error on this line

      
   ...
 

【讨论】:

这消除了编译时错误,但可能不是正确的解决方案。他不应该为了调用某个函数而实例化一个虚拟的ViewController 实例。此外,这可能会导致运行时错误,因为在 ViewController 中为 ip 隐式展开 @IBOutlet 可能会失败。 你有什么建议@Rob? @Rob,我是 xcode 开发的新手。在这种情况下,我获取了我的计算机的 IP,这个动作需要在启动时恰好一次。 applicationDidFinishLaunching 为我提供了这个。我在启动时获得 IP,并告诉视图控制器显示它。除非视图控制器有自己的“启动时运行”方法,否则我不知道我还能做什么。我愿意接受建议。 @Rob 您能否解释一下为什么在这种情况下,@IBOutlet 的隐式展开可能会在运行时失败?谢谢。 @Unheilig - 因为当您从情节提要中实例化场景时,插座已连接。但是ViewController() 的手动实例化并没有使用情节提要。它只是创建一个ViewController 实例,它与任何特定的故事板场景无关。因此,出口将是nil。因此,任何尝试使用带有隐式展开的插座(即!)都会失败。您会收到“致命错误:在展开可选值时意外发现 nil”运行时错误。

以上是关于无法使用类型为“(字符串)”的参数列表调用 <method>的主要内容,如果未能解决你的问题,请参考以下文章

无法使用类型为“(字符串)”的参数列表调用“执行选择器”

IOS9 - 无法使用类型为“(字符串)”的参数列表调用“计数”

无法使用类型为“(字符串,withIntermediateDirectories:B)的参数列表调用“createDirectoryAtPath”

SWIFT 4.1 无法使用类型为“(字符串?)”的参数列表调用类型“Double”的初始化程序

无法使用类型为“”的参数列表调用类型“”的初始化程序

无法使用类型为“(NSFetchRequest<NSFetchRequestResult>)”的参数列表调用“获取”