你可以帮我解决这个记忆问题。所以我根据项目预设“基于页面的应用程序”构建了一个应用程序,一切运行良好,但随着时间的推移,单个视图将每个Viewcontroller加载到物理内存中,而不是释放它们。如果内存已满,应用程序将崩溃。
这是我的代码:
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 :(得分:0)
iOS上存在一种方法,只要设备的内存受到限制就会被调用。默认情况下,只调用UIApplicationDelegate
,但您可以使用NSNotificationCenter
添加任何类和/或对象,以便调用它们。
当调用该方法时,它会为您的应用释放一些内存提供信号。然后,您可以清除不再需要的数据。
答案 1 :(得分:0)
我解决了我的问题。很抱歉,解决方案是在DataViewController中,我没有发布我的DataViewController文件,所以无论如何。
这是我的解决方案:
旧的DataViewController:
package meg.zach.d;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
public class Main extends JavaPlugin {
// Got rid of onEnable(), simply sent a message to show the plugin was
// enabled, but is done automatically by the server
// Got rid of onDisable(), not necessary if empty
Logger log = Logger.getLogger("Minecraft");
@SuppressWarnings("deprecation")
public boolean onCommand(CommandSender sender, Command cmd, String label, String args[]) {
// The below checks if the sender is a player
if (!(sender instanceof Player)) {
log.info("error message : sender isnt player");
return true;
}
// I can now safely cast sender to type Player
Player p;
if (cmd.getName().equalsIgnoreCase("commandnamehere")) {
// Checking if there are enough arguments
if (args.length != 1) {
// Message to send when there isn't enough arguments
p.sendMessage("Look! Not enough arguments!");
return true;
}
if (args[0] == "lookaspecialthingy") {
// Instead of looping through all the online players, I just try
// to cast the player name to a Player, and check if the object
// is null
Player target = Bukkit.getPlayer(args[0]);
if (target == null) {
// Player is offline
return true;
}
String modN = ChatColor.GRAY + "[Mod] ";
target.setDisplayName(modN + target.getDisplayName());
String modb = ChatColor.YELLOW + " has been promoted into a ";
String mod = ChatColor.GOLD + "Mod!";
Bukkit.getServer().broadcastMessage(target + modb + mod);
}
}
return false;
}
}
这是新的DataViewController:
import UIKit
class DataViewController: UIViewController {
@IBOutlet weak var myImageView: UIImageView!
var dataObject: String?
override func viewDidLoad() {
super.viewDidLoad()
self.myImageView.image = UIImage(named: dataObject!)
// my Images was cached because I used "named:"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}