简体   繁体   English

带有异步代码的UInavigationController中的弱无用用法

[英]Weak,unowned usage in UInavigationController with async code

I have a classic master detail view application. 我有一个经典的主细节视图应用程序。 In detail view, I added pull to refresh capability to refresh data from network. 在详细视图中,我添加了拉动刷新功能以从网络刷新数据。 Even though I can't replicate on my end, I get crash reports related to this refresh function. 即使我无法复制,也可以获得与此刷新功能相关的崩溃报告。 I tried to throttle my connection, refreshed many times, go back and forth between view controllers, still couldn't reproduce it. 我试图限制我的连接,刷新多次,在视图控制器之间来回切换,但仍然无法重现它。 I think I should use weak or unowned self in here but I am not sure which one to choose. 我认为我应该在这里使用弱者或无主者,但我不确定该选择哪一个。 User is a Core Data object that I pass from Master View. User是我从主视图传递的核心数据对象。 My crash reports indicate during write operation to User, program crashes. 我的崩溃报告表明在对用户的写操作期间,程序崩溃了。 Crashlytics reports that User.detail.count is 0 which seems to indicate that User.detail is deallocated? Crashlytics报告User.detail.count为0,这似乎表明User.detail已被释放? I appreciate if you can help me to solve this. 如果您能帮助我解决此问题,我将不胜感激。

class User:NSManagedObject {
    @NSManaged var detail: NSOrderedSet
}

class UserDetail:NSManagedObject {
    @NSManaged var message:String?

}
class APIService {

    func getData(date:NSDate?,success: (User) -> Void, failure: (NSHTTPURLResponse?, AnyObject?, ErrorType) -> Void) {

    }
}

class ViewController {
var myUser:User!
typealias UserCompletion = (error: ErrorType?) -> Void

    func deleteDetails() {

    }

    func updateDetails() {

    }

func refreshList(completion: UserCompletion) {
    let downloadGroup = dispatch_group_create()
    var storedError: ErrorType?


    let service = APIService()
    dispatch_group_enter(downloadGroup)

    service.getData(nil,
        success: { user in
            var isitNew = false

            //first check if the amount of details changed.
            if user.detail.count == self.myUser.detail.count {
                let oldDetail = self.myUser.detail.lastObject as! UserDetail
                let newDetail = user.detail.lastObject as! UserDetail
                if oldDetail.message != newDetail.message {

                    isitNew = true
                }

            }
            if isitNew || (user.detail.count > 0 && user.detail.count != self.myUser.detail.count) { //something is changed

                //Following log function logs detail count as 0 "Something is new count: 0"
                //CLSLogv("Something is new count: %d", getVaList([self.myUser.detail.count]))

                //Crash after this log
                // delete old details and update
                self.deleteDetails()
                self.updateDetails()

            }
            dispatch_group_leave(downloadGroup)

        },
        failure: { response, document, error in
            storedError = error
            dispatch_group_leave(downloadGroup)

    })
    // Exit from group
    dispatch_group_notify(downloadGroup, dispatch_get_main_queue()) { // 2
        completion(error: storedError)
        }
    }
}

EDIT 编辑

Oh darn - I think I misread your post a bit (having had the same issue as the one I originally answered). 哦,该死-我想我对您的帖子有误读(遇到了与我最初回答的问题相同的问题)。 Use [weak self] in the closure to get a weak reference: 在闭包中使用[weak self]获取弱引用:

success: { [weak self] user in
        var isitNew = false

        //first check if the amount of details changed.
        if user.detail.count == self?.myUser.detail.count {
            let oldDetail = self?.myUser.detail.lastObject as! UserDetail
            let newDetail = user.detail.lastObject as! UserDetail
            if oldDetail.message != newDetail.message {

                isitNew = true
            }

        }
        if isitNew || (user.detail.count > 0 && user.detail.count != self?.myUser.detail.count) { //something is changed

            //Following log function logs detail count as 0 "Something is new count: 0"
            //CLSLogv("Something is new count: %d", getVaList([self?.myUser.detail.count]))

            //Crash after this log
            // delete old details and update
            self?.deleteDetails()
            self?.updateDetails()

        }
        dispatch_group_leave(downloadGroup)

    }

ORIGINAL RESPONSE (leaving this in for now - might still be the cause of your crash) 原始响应暂时保留此状态-可能仍然是导致崩溃的原因)

I think your problem might be that the detail view controller is keeping a reference to an NSManagedObject whose underlying data is removed from the datastore by the network call ( similar issue ) 我认为您的问题可能是细节视图控制器正在保留对NSManagedObject的引用,该对象的基础数据已通过网络调用从数据存储中删除( 类似的问题

One suggestion is to not keep a reference to the NSManagedObject itself in the detail but rather keep the key properties that you are comparing with. 一个建议是不要在细节中保留对NSManagedObject本身的引用,而应保留与之比较的关键属性。

Another idea would be to let your getData return the "isitNew" value. 另一个想法是让您的getData返回“ isitNew”值。 That function would know if a new core data entry was created or not. 该功能将知道是否创建了新的核心数据条目。

But I am keeping the best solution (in my opinion) to last. 但是,我一直坚持最好的解决方案。 You can use an NSFetchedResultsController to detect changes. 您可以使用NSFetchedResultsController来检测更改。 Set your detail-view up as an NSFetchedResultsControllerDelegate . 将详细视图设置为NSFetchedResultsControllerDelegate The apple documentation actually contains a good example of how to do this. 苹果文档实际上包含了一个很好的例子。

The advantage of the last solution is that you can get rid of the closure and decouple the detail from whatever changes the data. 最后一个解决方案的优点是,您可以摆脱闭包并使细节与数据更改无关。 This may be useful one day when you need to expand the app and another source of changes are introduced. 有一天,当您需要扩展应用程序并引入其他更改源时,这可能会很有用。 This source might not know of your detail view controller and possibly shouldn't know of it either. 此源可能不知道您的详细信息视图控制器,也可能也不应该知道。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM