在 Swift 中为特定方法调用实现闭包

Posted

技术标签:

【中文标题】在 Swift 中为特定方法调用实现闭包【英文标题】:Implementing closure for specific method call in Swift 【发布时间】:2014-06-17 06:19:41 【问题描述】:

我遇到了以下 UITableViewController 代码,并想实现相关联的 classes 和与之配套的函数,以便我了解更多关于 Swift 的知识。

我不确定api.getRooms() 的实现是什么样的。我认为这可能是一个关闭,但我不完全确定?

我的问题是,考虑到 的使用情况,api.getRooms() 会返回什么?如果有人能向我解释发生了什么,将不胜感激。

api.getRooms(User.currentUser()!)  (roomsObj, error) in
    if let rooms = roomsObj as? Array<Room> 
        self.rooms = rooms
        self.tableView.reloadData()
        if (viaPullToRefresh) 
            self.refreshControl.endRefreshing()
        
    

PullViewController.swift

class PullViewController: UITableViewController 
    var rooms = Array<Room>()

    init(coder aDecoder: NSCoder!) 
        super.init(coder: aDecoder)

        // Custom initialization
        assert(User.currentUser())
    

    override func viewDidLoad() 
        self.refreshControl = UIRefreshControl()
        self.refreshControl.addTarget(self, action: Selector("refreshInvoked"), forControlEvents: UIControlEvents.ValueChanged)
        refresh()
    

    override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int 
        return rooms.count
    

    override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath:NSIndexPath!) -> UITableViewCell! 
        var cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
        if !cell 
            cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier:"Cell")
        

        let room = rooms[indexPath.row]
        cell!.textLabel.textColor = UIColor.blackColor()
        cell!.textLabel.text = "\(room.name)(\(room.messageCount))"
        return cell
    

    func refreshInvoked() 
        refresh(viaPullToRefresh: true)
    

    func refresh(viaPullToRefresh: Bool = false) 
        let api = API()
        api.getRooms(User.currentUser()!)  (roomsObj, error) in
            if let rooms = roomsObj as? Array<Room> 
                self.rooms = rooms
                self.tableView.reloadData()
                if (viaPullToRefresh) 
                    self.refreshControl.endRefreshing()
                
            
        
    

User.swift

class User 

    init() 
    

    class func currentUser() -> Bool 
        return true
    

Room.swift

class Room 

    var name: String
    var messageCount: Int

    init() 
    

API.swift (不确定这是否正确实现)。

class API 

    init() 
    

    func getRooms(user: User) -> (Array<Room>, String)  // ??
        // ??
    

【问题讨论】:

您不需要在 Swift 中的 Selector() 中包装选择器,只需提供带引号的目标方法名称(其中尾随 ':' 字符 = 参数占位符,没有 ':' = 没有参数目标函数) 【参考方案1】:

在你的房间类中,你没有初始化 name 和 message count 变量,在 swift 中只有可选变量可以是 nil

class Room 

    var name: String
    var messageCount: Int

    init(name:String, messageCount:Int) 
        self.name = name
        self.messageCount = messageCount
    

还断言需要评估为布尔所以

assert(User.currentUser() != nil)

【讨论】:

感谢您的回答。 assert() 现在有意义了。只是想知道api.getRooms()这个函数现在是怎么实现的。 在init完成前需要设置name和mesageCount,可以在init中设置或者使用可选变量var name:String?【参考方案2】:

1) 您正在发送 assert 一个 void ,因为您的 currentUser 方法不返回任何内容,因此 assert 不知道这是好是坏。因此,如果你想像这样使用它,你需要让 currentUser 返回一个 BOOL 或其他东西,但它需要某种 BOOL 结果来判断它是否正确断言。希望这是有道理的。

2)您试图为您的 getRooms 函数提供一个 lambda 函数,而不是在结果之后运行一个函数。

--更新-- 如果你想要一个完成 lambda,那么你需要像这样编写 getRooms:

func getRooms(user: User, completion: ((Array<Room>,String?) -> Void)?) -> Array<Room> //String because I have no idea what type they want for errors
    var room = Room()

    room.messageCount = 0
    room.name = "Room1"

    var rooms = Array<Room>()
    rooms.append(room)

    completion?(rooms,nil)

    return rooms

或者类似的东西

【讨论】:

这对于assert() 来说非常有意义。 getRooms() 函数。我必须阅读有关 Swift 中的 lambda 的内容,看看如何才能实现与此代码一起工作的一个。 我猜对了你的意图吗?如果是这样,您可以添加一个可选的 lambda 参数来获取房间。 希望这个例子有点帮助 这实际上很有帮助并且非常有意义,但是我必须在 completion: 之前添加一个逗号,并且在 ?callback? completion() 方法说:Cannot convert the expression's type '$T3' to type '(Array&lt;Room&gt;, String?)?' 从函数中删除?'s 然后抛出这个错误:'(@lvalue Array&lt;Room&gt;, $T2) -&gt; $Y3 'is not identical to '(Array&lt;Room&gt;, String)'【参考方案3】:

这就是我实现api.getRooms() 函数的方式:

API.swift

class API 

    func getRooms(user: User, completion: (Array<Room>, String) -> ()) 
        var room = Room(name: "Room1", messageCount: 0)

        var rooms = Array<Room>()
        rooms.append(room)

        completion(rooms, "error")
    


PullViewController.swift

func refresh(viaPullToRefresh: Bool = false) 

    let api = API()

    if let user = User.currentUser() 
        api.getRooms(user)  (roomsObj, error) in
            self.rooms = roomsObj
            self.tableView.reloadData()
            if (viaPullToRefresh) 
                self.refreshControl.endRefreshing()
            
        
    


【讨论】:

以上是关于在 Swift 中为特定方法调用实现闭包的主要内容,如果未能解决你的问题,请参考以下文章

在 swift 包管理器中为 API 调用编写单元测试

Swift函数和闭包

在 iOS Swift 中实现方法时如何为闭包命名(语法问题)

js利用闭包封装自定义模块的几种方法

Swift - 在闭包内调用 segue

Swift:为啥调用闭包函数到晚