NSPathStore2的UIImageView实例泄漏

时间:2020-05-16 05:54:56

标签: ios swift3 memory-leaks uiimageview uiimage

我正在将Document目录中的png图像加载到UIImageView中。使用xcode 调试内存图时,它会遇到内存问题: import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Scanner; public class LibrarySystem { /** The menu option that will cause the program to end. */ private static final int QUIT_OPTION = 4; /** The Library to use in the test program. */ private static Library myLibrary = null; /** The start point for the program. @param args no command line arguments are used in this program */ public static void main(String[] args) { /* Create a Scanner for the input file. This program assumes that Books.txt exists in the same directory as this program. */ Scanner input = null; try { input = new Scanner(new File("Books.txt")); } catch (FileNotFoundException e) { System.out.println("File \"Books.txt\" not found in the current directory."); System.out.println("Exiting the program."); System.exit(1); } /* Read the input file and create the library */ myLibrary = readFile(input); // create a Scanner for keyboard input Scanner console = new Scanner(System.in); boolean runAgain = true; //display an introduction displayIntro(); while (runAgain) { // loop until the user chooses to quit displayMenu(); // get the user's menu choice int choice = promptForMenuChoice(console, "\nEnter your choice (1 - " + QUIT_OPTION + "): "); // perform some processing based on the menu choice if (choice == QUIT_OPTION) { runAgain = false; } else { doMenuChoice(choice); } } displayExitMessage(); } // end main /** Reads the input file and returns a Library built from the data in the input file. @param input A Scanner over the input file @return a Library built from the data in the input file */ private static Library readFile(final Scanner input) { Library theLibrary = new Library(); /* read the file and populate the Library */ while (input.hasNextLine()) { //read the first line which is a book title String title = input.nextLine(); //create an ArrayList for the authors ArrayList<String> theAuthors = new ArrayList<String>(); //read the authors boolean readingAuthors = true; while (input.hasNext() && readingAuthors) { String author = input.nextLine(); if (author.length() == 0) { //blank line between books readingAuthors = false; } else { theAuthors.add(author); } } Book nextBook = null; try { nextBook = new Book(title, theAuthors); } catch (IllegalArgumentException e) { continue; //skip to next book in input file } theLibrary.add(nextBook); } return theLibrary; } //end readFile /** Displays an introduction to the program. */ private static void displayIntro() { System.out.println("\nThis program manages a library of books."); } /** Displays the menu of options for the program. */ private static void displayMenu() { System.out.println("\nProgram Options:"); System.out.println("\n1) Display books"); System.out.println("\n2) Add a book"); System.out.println("\n3) Search by title"); System.out.println("\n4) Quit"); System.out.println("\nPlease type a number and then press the Enter key."); } /** * Prompts for a menu choice in the range 1 to QUIT_OPTION. * * @param console a Scanner to read from the keyboard * @param prompt the prompt to display * @return the number entered by the user */ private static int promptForMenuChoice(final Scanner console, final String prompt) { int choice = getInt(console, prompt); while (choice < 1 || choice > QUIT_OPTION) { System.out.println("Invalid selection. Please try again."); choice = getInt(console, prompt); } return choice; } /** * Prompts for an integer until an integer is entered. * * This method is adopted from getInt() of * "Building Java Programs" by Reges and Stepp * * @param console a Scanner used to capture user input * @param prompt a prompt to the user * @return the integer entered by the user */ private static int getInt(final Scanner console, final String prompt) { System.out.print(prompt); while (!console.hasNextInt()) { console.next(); System.out.println("Invalid selection. Please try again."); System.out.print(prompt); } return console.nextInt(); } /** Initiates processing based on the user's menu choice. @param choice the user's menu choice */ private static void doMenuChoice(final int choice) { //Code for each switch option will usually be a call to some method. //By just calling a method from each case we can keep this code block clean switch (choice) { case 1: displayBooks(); break; case 2: addABook(); break; case 3: searchByTitle(); break; default : break; } } private static void displayBooks() { //System.out.println("\n" + myLibrary); myLibrary.sort(); System.out.println("\nBy title:\n" + myLibrary); } private static void addABook() { String title = getTitle(); ArrayList<String> authors = getAuthors(); Book newBook = new Book(title, authors); myLibrary.add(newBook); } private static void searchByTitle() { String title = getTitle(); List<Book> found = myLibrary.titleSearch(title); if (found.size() == 0) { System.out.println("\nSorry, \"" + title + "\" was not found."); } else { System.out.println("\n\"" + title + "\" was found!"); Iterator<Book> scan = found.iterator(); while (scan.hasNext()) { System.out.println(scan.next()); } } } private static String getTitle() { Scanner console = new Scanner(System.in); System.out.print("\nEnter the book title: "); return console.nextLine(); } private static ArrayList<String> getAuthors() { Scanner console = new Scanner(System.in); ArrayList<String> theAuthors = new ArrayList<String>(); //prompt for the authors boolean readingAuthors = true; while (readingAuthors) { System.out.println("\nEnter an author's name"); System.out.print("or just press Enter after adding the last author: "); String author = console.nextLine(); if (author.length() == 0) { //blank line readingAuthors = false; } else { theAuthors.add(author); } } return theAuthors; } /* Displays an exit message. */ private static void displayExitMessage() { System.out.println("\nThanks for trying this program. Have a nice day."); } } // end class LibrarySystem instances of NSPathStore2 leaked

我听说仪器的泄漏工具可能报告错误的leaks

内存似乎没有增加: enter image description here

问题似乎出在UIImage中,请参阅Instruments Leak报告: enter image description here

以下是生成图像的代码:

instances of NSPathStore2 leaked

产生此问题的工作项目可以在这里找到:UIImageViewNSPathStore2leaked

是否有办法更改代码以消除这些泄漏,或者这是那些虚假的报告之一?

2 个答案:

答案 0 :(得分:6)

我也有问题。

复制

只需创建干净的新项目来重现该问题。

  1. 将image.png拖到项目中,确保在复制捆绑资源中进行。
  2. 在viewDidLoad中写这两行。
import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let path = Bundle.main.path(forResource: "image", ofType: "png")!
        let _ = UIImage(contentsOfFile: path)
    }
}
  1. 构建并运行它。
  2. 在出现viewController时,单击调试内存图
  3. 您可以看到泄漏问题。

不确定是init(contentsOfFile:)的错误吗?

解决方案

我更改了API init(data:)而不是init(contentsOfFile:)来解决问题。

let url = Bundle.main.url(forResource: "image", withExtension: "png")!
let imageData = try! Data(contentsOf: url)
let _ = UIImage(data: imageData)

使用Xcode 11.5 / 11.3.1和Swift 5

答案 1 :(得分:0)

似乎是Instruments中的错误,可能是误报。在Xcode 12 beta 6中,它不再显示为泄漏。

请注意,在Xcode 11.6 / 11.7中,“泄漏”也通过UIImage(named: )方法发生:

UIImage(named: ) leak.