(lldb) print event.type (UIEventType) $R10 = <invalid> (0xff)
不知何故,我认为这与我如何处理轮换有关.我有一个主 – 细节风格的应用程序,它使用不同类型的导航来拍摄风景,拍摄肖像和手机.我创建了一个名为NavigationFlowController的类,它处理所有导航事件并相应地设置视图.在旋转时,它会分解视图树并使用正确的导航重新组合它们
func changeViewHierarchyForDevideAndOrientation(newOrientation:UIInterfaceOrientation? = nil){ print("MA - Calling master layout method") UIApplication.myDelegate().window?.frame = UIScreen.mainScreen().bounds let idiom = UIDevice.currentDevice().userInterfaceIdiom var orientation:UIInterfaceOrientation! if let no = newOrientation{ orientation = no }else{ orientation = UIApplication.sharedApplication().statusBarOrientation } print("MA - Breaking up view tree...") breakupFormerViewTree([sidebarViewController,listViewController,detailViewController,loginViewController]) print("MA - Start init navbackbone") initNavBackboneControllers() guard let _ = UIApplication.myDelegate().currentUser else { if idiom == UIUserInterfaceIdiom.Phone{ currentState = AppState.PHONE }else if idiom == UIUserInterfaceIdiom.Pad && UIInterfaceOrientationIsLandscape(orientation){ currentState = AppState.PAD_LANDSCAPE }else if idiom == UIUserInterfaceIdiom.Pad && UIInterfaceOrientationIsPortrait(orientation){ currentState = AppState.PAD_PORTRAIT } print("MA - Current user is nil - resetting") mainViewController.addChildViewController(loginViewController) return } if idiom == UIUserInterfaceIdiom.Phone{ currentState = AppState.PHONE leftNavigationController?.viewControllers = [listViewController] slideViewController?.rearViewController = sidebarViewController slideViewController?.frontViewController = leftNavigationController slideViewController?.rearViewRevealWidth = 267; mainViewController.addChildViewController(slideViewController!) }else if idiom == UIUserInterfaceIdiom.Pad && UIInterfaceOrientationIsLandscape(orientation){ currentState = AppState.PAD_LANDSCAPE leftNavigationController!.viewControllers = [sidebarViewController,listViewController] rightNavigationController!.viewControllers = [detailViewController] detailViewController.navigationItem.leftBarButtonItems = [] detailViewController.initLayout() print("MA - Init split view controller with VCs") splitViewController!.viewControllers = [leftNavigationController!,rightNavigationController!] mainViewController.addChildViewController(splitViewController!) }else if idiom == UIUserInterfaceIdiom.Pad && UIInterfaceOrientationIsPortrait(orientation){ currentState = AppState.PAD_PORTRAIT leftNavigationController!.pushViewController(sidebarViewController,animated: false) leftNavigationController!.pushViewController(listViewController,animated: false) rightNavigationController!.pushViewController(detailViewController,animated: false) rightNavigationController?.setNavigationBarHidden(false,animated: false) slideViewController!.rearViewController = leftNavigationController slideViewController!.frontViewController = rightNavigationController detailViewController.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "< Documenten",style: UIBarButtonItemStyle.Bordered,target: slideViewController,action: "revealToggle:") detailViewController.initLayout() slideViewController!.rearViewRevealWidth = 350; mainViewController.addChildViewController(slideViewController!) } } func breakupFormerViewTree(vcs:[UIViewController?]){ for vc in vcs{ if let vcUnwrapped = vc,_ = vcUnwrapped.parentViewController { vcUnwrapped.removeFromParentViewController() vcUnwrapped.view.removeFromSuperview() } } } func initNavBackboneControllers(){ leftNavigationController = UINavigationController() leftNavigationController?.navigationBar.barTintColor = UIColor(red: 0.25,green: 0.25,blue: 0.25,alpha: 1.0) leftNavigationController?.navigationBar.tintColor = UIColor.whiteColor() leftNavigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()] leftNavigationController?.navigationBar.translucent = false rightNavigationController = UINavigationController() rightNavigationController?.navigationBar.barTintColor = UIColor(red: 0.25,alpha: 1.0) rightNavigationController?.navigationBar.tintColor = UIColor.whiteColor() rightNavigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()] rightNavigationController?.navigationBar.translucent = false slideViewController = SWRevealViewController() slideViewController?.rearViewRevealoverdraw = 0; slideViewController?.bounceBackOnOverdraw = false; slideViewController?.stableDragOnOverdraw = true; slideViewController?.delegate = self if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad{ splitViewController = UISplitViewController() } }
编辑(回应贾斯汀的问题):
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 ... } }
EDIT2:
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 }) } }
编辑方式3:我已经重写了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() } } } } } }
解决方法
>它是否会在每台设备上发生(如果没有,哪些设备会给您带来麻烦)
>它发生在“大力选择”项目之后.您的设备在此之前是否更改了方向.在你旋转之前它也会发生吗?
>当您“选择项目”时,您在代码中做什么.
除此之外,我开始在breakupFormerViewTree()中删除你的子ViewControllers.基于Apple Docs,你想告诉孩子它被删除,然后删除视图然后最终从Parent ViewController中删除子项
https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html
这里它实际上表示你想在删除之前调用willMovetoParentViewController(nil).它没有说明如果你不这样做会发生什么,但我可以想象操作系统在那里进行一些生命周期管理,防止它在以后发送腐败事件.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/index.html#//apple_ref/occ/instm/UIViewController/willMoveToParentViewController:
编辑(额外发布代码后)
我的代码中没有看到任何可能导致崩溃的内容.它确实看起来像你所说的内存错误,但不知道它来自何处.尝试打开Zombie对象和Guard Malloc(Scheme> Run> Diagnostics),也许你可以获得更多信息,了解导致它的原因.
除此之外,我只是注释掉你的实现的负载,用空的ViewControllers交换Subclasses,直到它不再发生.您应该能够确定创建此事件涉及实现的哪个部分.一旦你这样做,那就更好地指出并评估该实现中的每一行代码.