Ios sendEvent方法上的应用程序崩溃

Ios sendEvent方法上的应用程序崩溃,ios,swift,uievent,Ios,Swift,Uievent,当我在选择几个项目后旋转应用程序两次时,它会崩溃。我已经重写了sendEvent方法,调试器将在那里停止。当我尝试打印事件类型时,它会显示一些奇怪的信息(我认为这是一个不存在的内存位置): 编辑(回答Justin的问题): 1) 我在所有iOS8 iPad模拟器上都经历过崩溃 2) 从新开始,如果我选择6-7个项目,然后旋转两次,它就会崩溃。但我也可以选择一个项目,旋转几次,再选择一些,然后继续旋转,在某个时候它会崩溃 3) 选择项目时,将执行以下代码: func tableView(table

当我在选择几个项目后旋转应用程序两次时,它会崩溃。我已经重写了sendEvent方法,调试器将在那里停止。当我尝试打印事件类型时,它会显示一些奇怪的信息(我认为这是一个不存在的内存位置):

编辑(回答Justin的问题):

1) 我在所有iOS8 iPad模拟器上都经历过崩溃

2) 从新开始,如果我选择6-7个项目,然后旋转两次,它就会崩溃。但我也可以选择一个项目,旋转几次,再选择一些,然后继续旋转,在某个时候它会崩溃

3) 选择项目时,将执行以下代码:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    let document = getInfoForSection(indexPath.section).documents[indexPath.item]
    if document.canOpen{
        openDocument(document)

        DataManager.sharedInstance.getDocument(document.uri, after: {
            (document:Document?) -> () in
            if let documentUnwrapped = document{
                let detailVC = NavigationFlowController.sharedInstance.detailViewController;
                if detailVC.document?.uri == documentUnwrapped.uri{
                    NavigationFlowController.sharedInstance.detailViewController.documentUpdated(documentUnwrapped)
                }
            }
        })
    }
}
然后在详图视图控制器中:

func initLayout(){
    if viewForCard == nil{
        // views not yet initialized, happens when initLayout if called from the document setter before this view has been loaded
        // just return, the layouting will be done on viewDidLoad with the correct document instead
        return
    }

    self.navigationItem.rightBarButtonItems = []

    if document == nil{
        // Removed code that handles no document selected
        ...
        return
    }

    heightForCard.constant = NavigationFlowController.sharedInstance.currentState == AppState.PHONE ? CARD_HEIGHT_PHONE : CARD_HEIGHT_TABLET

    viewForCard.hidden = false
    removeAllSubviews(viewForCard)
    removeAllSubviews(viewForDetails)

    viewForDetails.translatesAutoresizingMaskIntoConstraints = false

    self.metaVC?.document = document
    //self.documentVC?.document = document
    self.navigationItem.rightBarButtonItems = []

    downloadDocumentIfNeeded()

    if NavigationFlowController.sharedInstance.currentState == AppState.PAD_LANDSCAPE || NavigationFlowController.sharedInstance.currentState == AppState.PAD_PORTRAIT{
        self.viewForDetails.backgroundColor = document?.senderStyling?.color

        addChildViewController(self.metaVC!)
        addChildViewController(self.documentVC!)

        let metaView = self.metaVC!.view
        let documentView:UIView = self.documentVC!.view

        viewForDetails.addSubview(metaView)
        viewForDetails.addSubview(documentView)

        // whole lot of layouting code removed
        ...            

        let doubleTap = UITapGestureRecognizer(target: self, action: "toggleZoom")
        documentVC!.view.addGestureRecognizer(doubleTap)

    }else{
        // Phone version code removed
        ...
    }   
}
编辑2:

func downloadDocumentIfNeeded(){
    var tmpPath:NSURL?
    if let url = document?.contentUrl{
        let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]

        if let docName = self.document?.name,
            safeName = disallowedCharacters?.stringByReplacingMatchesInString(docName, options: [], range: NSMakeRange(0, docName.characters.count), withTemplate: "-"){
                tmpPath = directoryURL.URLByAppendingPathComponent("\(safeName)_\(DetailViewController.dateFormatter.stringFromDate(self.document!.creationDate!)).pdf")

        }


        if let urlString = tmpPath?.path{
            if NSFileManager.defaultManager().fileExistsAtPath(urlString) {
                // File is there, load it
                loadDocumentInWebview(tmpPath!)
            }else{
                // Download file
                let destination: (NSURL, NSHTTPURLResponse) -> (NSURL) = {
                    (temporaryURL, response) in

                    if let path = tmpPath{
                        return path
                    }

                    return temporaryURL
                }

                download(.GET, URLString: url, destination: destination).response {
                    (request, response, data, error) in

                    if error != nil && error?.code != 516{
                        ToastView.showToastInParentView(self.view, withText: "An error has occurred while loading the document", withDuaration: 10)
                    }else if let pathUnwrapped = tmpPath {
                        self.loadDocumentInWebview(pathUnwrapped)
                    }
                }
            }
        }
    }
}

func loadDocumentInWebview(path:NSURL){
    if self.navigationItem.rightBarButtonItems == nil{
        self.navigationItem.rightBarButtonItems = []
    }

    self.documentVC?.finalPath = path

    let shareItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Action, target: self, action: "share")
    shareItem.tag = SHARE_ITEM_TAG

    addNavItem(shareItem)

}

func addNavItem(navItem:UIBarButtonItem){
    var addIt = true
    for item in self.navigationItem.rightBarButtonItems!{
        if item.tag == navItem.tag{
            addIt = false
        }
    }

    if addIt{
        self.navigationItem.rightBarButtonItems?.append(navItem)
        self.navigationItem.rightBarButtonItems!.sortInPlace({ $0.tag > $1.tag })
    }
}
EDIT3:我已重写sendEvent方法来跟踪用户是否正在触摸应用程序,但即使我取出此代码,它仍会崩溃,然后UIApplicationMain上的调试器会中断

override func sendEvent(event: UIEvent)
{        
    super.sendEvent(event)

    if event.type == UIEventType.Touches{
        if let touches = event.allTouches(){
            for item in touches{
                if let touch = item as? UITouch{
                    if touch.phase == UITouchPhase.Began{
                        touchCounter++
                    }else if touch.phase == UITouchPhase.Ended || touch.phase == UITouchPhase.Cancelled{
                        touchCounter--
                    }

                    if touchCounter == 0{
                        receiver?.notTouching()
                    }
                }
            }
        }
    }
}

困难的一点是,对这个bug之前发生的事件多了解一点可能会有所帮助

  • 它是否发生在每台设备上(如果不是,哪些设备会给您带来麻烦)
  • 它发生在“大力选择”项目之后。在那之前你的设备改变方向了吗。在你旋转之前也会发生吗
  • 当您“选择一个项目”时,您在代码中做什么
  • 除此之外,我将开始在breakupFormerViewTree()中删除子ViewController的流程。根据Apple文档,在删除视图之前,您希望告知子视图正在被删除,然后最终从父视图控制器中删除子视图

    在这里,它实际上表示您希望在执行删除之前调用willMoveToParentViewController(nil)。它没有说明如果不这样做会发生什么,但我可以想象操作系统在那里做一些生命周期管理,防止它在以后发送损坏事件

    :

    编辑(额外代码发布后)

    我在你的代码中没有看到任何其他可能导致它崩溃的东西。正如你所说,它看起来确实像是一个内存错误,但不知道它是从哪里来的。试着打开僵尸对象并保护Malloc(Scheme>Run>Diagnostics),也许你可以得到更多关于导致它的原因的信息


    除此之外,我只是注释掉实现中的负载,用空的ViewControllers交换子类,直到它不再发生。您应该能够确定创建此事件涉及到实现的哪一部分。一旦你这样做了,那么,你就可以精确地指出并评估该实现中的每一行代码。

    你能展示一下
    下载文档ifneeded()
    ?你到底在对这些事件做什么?我在那里看不到
    sendEvent
    ?我已经在Edit3中解释了您是否检查了所有的强制展开(!)选项。还没有,尽管大多数看起来是安全的,如果这是崩溃的原因,调试器不会在其中一个上停止吗?
    func downloadDocumentIfNeeded(){
        var tmpPath:NSURL?
        if let url = document?.contentUrl{
            let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
    
            if let docName = self.document?.name,
                safeName = disallowedCharacters?.stringByReplacingMatchesInString(docName, options: [], range: NSMakeRange(0, docName.characters.count), withTemplate: "-"){
                    tmpPath = directoryURL.URLByAppendingPathComponent("\(safeName)_\(DetailViewController.dateFormatter.stringFromDate(self.document!.creationDate!)).pdf")
    
            }
    
    
            if let urlString = tmpPath?.path{
                if NSFileManager.defaultManager().fileExistsAtPath(urlString) {
                    // File is there, load it
                    loadDocumentInWebview(tmpPath!)
                }else{
                    // Download file
                    let destination: (NSURL, NSHTTPURLResponse) -> (NSURL) = {
                        (temporaryURL, response) in
    
                        if let path = tmpPath{
                            return path
                        }
    
                        return temporaryURL
                    }
    
                    download(.GET, URLString: url, destination: destination).response {
                        (request, response, data, error) in
    
                        if error != nil && error?.code != 516{
                            ToastView.showToastInParentView(self.view, withText: "An error has occurred while loading the document", withDuaration: 10)
                        }else if let pathUnwrapped = tmpPath {
                            self.loadDocumentInWebview(pathUnwrapped)
                        }
                    }
                }
            }
        }
    }
    
    func loadDocumentInWebview(path:NSURL){
        if self.navigationItem.rightBarButtonItems == nil{
            self.navigationItem.rightBarButtonItems = []
        }
    
        self.documentVC?.finalPath = path
    
        let shareItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Action, target: self, action: "share")
        shareItem.tag = SHARE_ITEM_TAG
    
        addNavItem(shareItem)
    
    }
    
    func addNavItem(navItem:UIBarButtonItem){
        var addIt = true
        for item in self.navigationItem.rightBarButtonItems!{
            if item.tag == navItem.tag{
                addIt = false
            }
        }
    
        if addIt{
            self.navigationItem.rightBarButtonItems?.append(navItem)
            self.navigationItem.rightBarButtonItems!.sortInPlace({ $0.tag > $1.tag })
        }
    }
    
    override func sendEvent(event: UIEvent)
    {        
        super.sendEvent(event)
    
        if event.type == UIEventType.Touches{
            if let touches = event.allTouches(){
                for item in touches{
                    if let touch = item as? UITouch{
                        if touch.phase == UITouchPhase.Began{
                            touchCounter++
                        }else if touch.phase == UITouchPhase.Ended || touch.phase == UITouchPhase.Cancelled{
                            touchCounter--
                        }
    
                        if touchCounter == 0{
                            receiver?.notTouching()
                        }
                    }
                }
            }
        }
    }