2016-03-17 97 views
0

你可以幫我解決這個內存問題。所以我建立了一個基於項目預設「基於頁面的應用程序」的應用程序,一切正常,但隨着時間的推移,單個視圖會將每個Viewcontroller加載到物理內存中,而不會釋放它們。如果內存已滿,應用程序將崩潰。基於頁面的應用程序過載內存ARC不釋放頁面

這裏北京時間我的代碼:

的RootViewController的(CatalougeViewController):

import UIKit 

class CatalougeViewController: UIViewController, UIPageViewControllerDelegate, UIGestureRecognizerDelegate { 

    var pageViewController: UIPageViewController? 
    var zoomTransform: CGAffineTransform? 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     // Do any additional setup after loading the view, typically from a nib. 
     // Configure the page view controller and add it as a child view controller. 
     self.pageViewController = UIPageViewController(transitionStyle: .PageCurl, navigationOrientation: .Horizontal, options: nil) 
     self.pageViewController!.delegate = self 

     let startingViewController: DataViewController = self.modelController.viewControllerAtIndex(0, storyboard: self.storyboard!)! 
     let viewControllers = [startingViewController] 
     self.pageViewController!.setViewControllers(viewControllers, direction: .Forward, animated: true, completion: {done in }) 

     self.pageViewController!.dataSource = self.modelController 

     self.addChildViewController(self.pageViewController!) 
     self.view.addSubview(self.pageViewController!.view) 


     // Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages. 
     var pageViewRect = self.view.bounds 
     if UIDevice.currentDevice().userInterfaceIdiom == .Pad { 
      pageViewRect = CGRectInset(pageViewRect, 0.0, 0.0) 
     } 
     self.pageViewController!.view.frame = pageViewRect 
     self.pageViewController!.didMoveToParentViewController(self) 

     /* 
     // Add the page view controller's gesture recognizers to the book view controller's view so that the gestures are started more easily. 
     self.view.gestureRecognizers = self.pageViewController!.gestureRecognizers 
     */ 

     self.view.gestureRecognizers = self.pageViewController?.gestureRecognizers 


     let pinchRecognizer = UIPinchGestureRecognizer(target: self, action: "pinchDetected:") 
     self.view.addGestureRecognizer(pinchRecognizer) 

     let panRecognizer = UIPanGestureRecognizer(target: self, action: "handlePan:") 
     panRecognizer.minimumNumberOfTouches = 2 
     panRecognizer.maximumNumberOfTouches = 2 

     self.view.addGestureRecognizer(panRecognizer) 
    } 

    func pinchDetected(pinchRecognizer: UIPinchGestureRecognizer) { 

     if (UIGestureRecognizerState.Began == pinchRecognizer.state) || (UIGestureRecognizerState.Changed == pinchRecognizer.state) { 


      // Use the x or y scale, they should be the same for typical zooming (non-skewing) 
      let curScale = pinchRecognizer.view!.layer.valueForKeyPath("transform.scale.x")!.floatValue 
      let currentScale = CGFloat(curScale!) 

      // Variables to adjust the max/min values of zoom 
      let minScale: CGFloat = 1.0; 
      let maxScale: CGFloat = 2.0; 
      let zoomSpeed: CGFloat = 0.5; 

      var deltaScale: CGFloat = pinchRecognizer.scale 

      // You need to translate the zoom to 0 (origin) so that you 
      // can multiply a speed factor and then translate back to "zoomSpace" around 1 
      deltaScale = ((deltaScale - 1) * zoomSpeed) + 1 

      // Limit to min/max size (i.e maxScale = 2, current scale = 2, 2/2 = 1.0) 
      // A deltaScale is ~0.99 for decreasing or ~1.01 for increasing 
      // A deltaScale of 1.0 will maintain the zoom size 
      deltaScale = min(deltaScale, maxScale/currentScale) 
      deltaScale = max(deltaScale, minScale/currentScale) 

      zoomTransform = CGAffineTransformScale(pinchRecognizer.view!.transform, deltaScale, deltaScale); 
      pinchRecognizer.view!.transform = zoomTransform!; 

      // Reset to 1 for scale delta's 
      // Note: not 0, or we won't see a size: 0 * width = 0 
      pinchRecognizer.scale = 1; 

     } 

    } 

    func handlePan(recognizer:UIPanGestureRecognizer) { 
     let translation = recognizer.translationInView(self.view) 
     if let view = recognizer.view { 
      view.center = CGPoint(x:view.center.x + translation.x, 
       y:view.center.y + translation.y) 
     } 
     recognizer.setTranslation(CGPointZero, inView: self.view) 



     if recognizer.state == UIGestureRecognizerState.Ended { 
      // 1 
      let velocity = recognizer.velocityInView(self.view) 
      let magnitude = sqrt((velocity.x * velocity.x) + (velocity.y * velocity.y)) 
      let slideMultiplier = magnitude/200 
      // print("magnitude: \(magnitude), slideMultiplier: \(slideMultiplier)") 

      // 2 
      let slideFactor = 0.1 * slideMultiplier  //Increase for more of a slide 
      // 3 
      var finalPoint = CGPoint(x:recognizer.view!.center.x + (velocity.x * slideFactor), 
       y:recognizer.view!.center.y + (velocity.y * slideFactor)) 
      // 4 
      finalPoint.x = min(max(finalPoint.x, 0), self.view.bounds.size.width) 
      finalPoint.y = min(max(finalPoint.y, 0), self.view.bounds.size.height) 

      // 5 
      UIView.animateWithDuration(Double(slideFactor), 
       delay: 0, 
       // 6 
       options: UIViewAnimationOptions.CurveEaseOut, 
       animations: {recognizer.view!.center = finalPoint }, 
       completion: nil) 
     } 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 

    var modelController: CatalougeViewControllerModel { 
     // Return the model controller object, creating it if necessary. 
     // In more complex implementations, the model controller may be passed to the view controller. 
     if _modelController == nil { 
      _modelController = CatalougeViewControllerModel() 
     } 
     return _modelController! 
    } 

    var _modelController: CatalougeViewControllerModel? = nil 

    // MARK: - UIPageViewController delegate methods 

    func pageViewController(pageViewController: UIPageViewController, spineLocationForInterfaceOrientation orientation: UIInterfaceOrientation) -> UIPageViewControllerSpineLocation { 
     if (orientation == .Portrait) || (orientation == .PortraitUpsideDown) || (UIDevice.currentDevice().userInterfaceIdiom == .Phone) { 
      // In portrait orientation or on iPhone: Set the spine position to "min" and the page view controller's view controllers array to contain just one view controller. Setting the spine position to 'UIPageViewControllerSpineLocationMid' in landscape orientation sets the doubleSided property to true, so set it to false here. 
      let currentViewController = self.pageViewController!.viewControllers![0] 
      let viewControllers = [currentViewController] 
      self.pageViewController!.setViewControllers(viewControllers, direction: .Forward, animated: true, completion: {done in }) 

      self.pageViewController!.doubleSided = false 
      return .Min 
     } 

     // In landscape orientation: Set set the spine location to "mid" and the page view controller's view controllers array to contain two view controllers. If the current page is even, set it to contain the current and next view controllers; if it is odd, set the array to contain the previous and current view controllers. 
     let currentViewController = self.pageViewController!.viewControllers![0] as! DataViewController 
     var viewControllers: [UIViewController] 

     let indexOfCurrentViewController = self.modelController.indexOfViewController(currentViewController) 
     if (indexOfCurrentViewController == 0) || (indexOfCurrentViewController % 2 == 0) { 
      let nextViewController = self.modelController.pageViewController(self.pageViewController!, viewControllerAfterViewController: currentViewController) 
      viewControllers = [currentViewController, nextViewController!] 
     } else { 
      let previousViewController = self.modelController.pageViewController(self.pageViewController!, viewControllerBeforeViewController: currentViewController) 
      viewControllers = [previousViewController!, currentViewController] 
     } 
     self.pageViewController!.setViewControllers(viewControllers, direction: .Forward, animated: true, completion: {done in }) 

     return .Mid 
    } 

} 

多數民衆贊成在ViewControllerModel(CatalougeViewControllerModel):

class CatalougeViewControllerModel: NSObject, UIPageViewControllerDataSource { 

    override init() { 
     super.init() 
    } 

    func viewControllerAtIndex(index: Int, storyboard: UIStoryboard) -> DataViewController? { 
     // Return the data view controller for the given index. 
     if (PDF3.imagePath.count == 0) || (index >= PDF3.imagePath.count) { 
      return nil 
     } 

     // Create a new view controller and pass suitable data. 
     let dataViewController = storyboard.instantiateViewControllerWithIdentifier("DataViewController") as! DataViewController 
     dataViewController.dataObject = PDF3.imagePath[index] 
     return dataViewController 
    } 

    func indexOfViewController(viewController: DataViewController) -> Int { 
     // Return the index of the given data view controller. 
     // For simplicity, this implementation uses a static array of model objects and the view controller stores the model object; you can therefore use the model object to identify the index. 
     return PDF3.imagePath.indexOf(viewController.dataObject!) ?? NSNotFound 
    } 

    // MARK: - Page View Controller Data Source Seiten werden hochgezählt 

    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? { 
     var index = self.indexOfViewController(viewController as! DataViewController) 
     if (index == 0) || (index == NSNotFound) { 
      return nil 
     } 

     index-- 
     return self.viewControllerAtIndex(index, storyboard: viewController.storyboard!) 
    } 

    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? { 
     var index = self.indexOfViewController(viewController as! DataViewController) 
     if index == NSNotFound { 
      return nil 
     } 

     index++ 
     if index == PDF3.imagePath.count { 
      return nil 
     } 
     return self.viewControllerAtIndex(index, storyboard: viewController.storyboard!) 
    } 

} 

謝謝您的時間來幫助我.. 。

+0

你最有可能有一個地方保留週期。嘗試使用儀器幫助找到泄漏的地方。當你這樣做時,嘗試使用'weak'變量來打破保留週期。 – MaddTheSane

+0

不是內存泄漏。我的週期轉換PDF到UIImages與autorelease {}這是不是問題。儀器不會顯示泄漏。問題是,pageviewcontroller中的每個頁面都會加載到內存中,並且在打開兩個或三個pdf後,內存已滿,因爲每個頁面都加載在內存中,並且永遠不會釋放。 – Tom

回答

0

我解決了我的問題。所以,不好意思的人解決方案是在DataViewController中,我也沒有發佈我的DataViewController文件。

這裏是我的解決方案:

老DataViewController:

​​

那新DataViewController:

import UIKit 

class DataViewController: UIViewController { 


    @IBOutlet weak var myImageView: UIImageView! 

    var dataObject: String? 


    override func viewDidLoad() { 
     super.viewDidLoad() 
     autoreleasepool {() ->() in 
      self.myImageView.image = UIImage(contentsOfFile: dataObject!) // with "contentsOfFile:" the images are uncached... 
     } 


    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 



} 
0

iOS上存在一個獲取calle的方法d每當設備的內存受到限制時。默認情況下,只有UIApplicationDelegate被調用,但您可以使用NSNotificationCenter添加任何類和/或對象,以便它們也被調用。

當調用該方法時,它是您的應用程序釋放一些內存的信號。然後,您可以清除您不再需要的數據。

+0

這聽起來不錯,這是這種方法的名稱。我在5分鐘前解決了我的問題,但你的技巧非常有趣。 – Tom

+0

'applicationDidReceiveMemoryWarning:'其他文檔應該在'UIApplicationDelegate'的協議引用中。 – MaddTheSane