你可以幫我解決這個內存問題。所以我建立了一個基於項目預設「基於頁面的應用程序」的應用程序,一切正常,但隨着時間的推移,單個視圖會將每個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!)
}
}
謝謝您的時間來幫助我.. 。
你最有可能有一個地方保留週期。嘗試使用儀器幫助找到泄漏的地方。當你這樣做時,嘗試使用'weak'變量來打破保留週期。 – MaddTheSane
不是內存泄漏。我的週期轉換PDF到UIImages與autorelease {}這是不是問題。儀器不會顯示泄漏。問題是,pageviewcontroller中的每個頁面都會加載到內存中,並且在打開兩個或三個pdf後,內存已滿,因爲每個頁面都加載在內存中,並且永遠不會釋放。 – Tom