Tôi đang sử dụng GPUImage và nhiều phiên bản GPUImageView. Mục đích là để hiển thị hình ảnh gốc, lớp một vài lát của hình ảnh được lọc trên đầu trang, và cuối cùng animate các bộ lọc slice từ từ trên hình ảnh ban đầu. Hãy tưởng tượng một hình ảnh với một số thanh Sepia lăn qua để hiển thị hình ảnh bình thường và hình ảnh màu nâu đỏ trong các phần.GPUImage và GPUImageView: Ứng dụng bị chấm dứt do lỗi bộ nhớ
tôi quấn chức năng này trong một lớp con của UIView như bên dưới:
import Foundation
import QuartzCore
class FilteredImageMaskView : UIView {
init(frame: CGRect, image: UIImage){
super.init(frame: frame);
let imageViewFrame = CGRectMake(frame.origin.x, 0.0, frame.size.width, frame.size.height);
let origImage = GPUImagePicture(image: image);
origImage.forceProcessingAtSizeRespectingAspectRatio(imageViewFrame.size);
// Display the original image without a filter
let imageView = GPUImageView(frame: imageViewFrame);
origImage.addTarget(imageView);
origImage.processImageWithCompletionHandler(){
origImage.removeAllTargets();
var contentMode = UIViewContentMode.ScaleAspectFit;
imageView.contentMode = contentMode;
// Width of the unfiltered region
let regularWidth: CGFloat = 30.0;
// Width of filtered region
let filterWidth: CGFloat = 30.0;
// How much we are moving each bar
let totalXMovement = (regularWidth + filterWidth) * 2;
// The start X position
var currentXForFilter: CGFloat = -totalXMovement;
// The filter being applied to an image
let filter = GPUImageSepiaFilter();
filter.intensity = 0.5;
// Add the filter to the originalImage
origImage.addTarget(filter);
let filteredViewCollection = FilteredViewCollection(filteredViews: [GPUImageView]());
// Iterate over the X positions until the whole image is covered
while(currentXForFilter < imageView.frame.width + totalXMovement){
let frame = CGRectMake(currentXForFilter, imageViewFrame.origin.y, imageViewFrame.width, imageViewFrame.height);
var filteredView = GPUImageView(frame: frame);
filteredView.clipsToBounds = true;
filteredView.layer.contentsGravity = kCAGravityTopLeft;
// This is the slice of the overall image that we are going to display as filtered
filteredView.layer.contentsRect = CGRectMake(currentXForFilter/imageViewFrame.width, 0.0, filterWidth/imageViewFrame.width, 1.0);
filteredView.fillMode = kGPUImageFillModePreserveAspectRatio;
filter.addTarget(filteredView);
// Add the filteredView to the super view
self.addSubview(filteredView);
// Add the filteredView to the collection so we can animate it later
filteredViewCollection.filteredViews.append(filteredView);
// Increment the X position
currentXForFilter += regularWidth + filterWidth;
}
origImage.processImageWithCompletionHandler(){
filter.removeAllTargets();
// Move to the UI thread
ThreadUtility.runOnMainThread(){
// Add the unfiltered image
self.addSubview(imageView);
// And move it behind the filtered slices
self.sendSubviewToBack(imageView);
// Animate the slices slowly across the image
UIView.animateWithDuration(20.0, delay: 0.0, options: UIViewAnimationOptions.Repeat, animations: { [weak filteredViewCollection] in
if let strongfilteredViewCollection = filteredViewCollection {
if(strongfilteredViewCollection.filteredViews != nil){
for(var i = 0; i < strongfilteredViewCollection.filteredViews.count; i++){
strongfilteredViewCollection.filteredViews[i].frame.origin.x += totalXMovement;
strongfilteredViewCollection.filteredViews[i].layer.contentsRect.origin.x += (totalXMovement/imageView.frame.width);
}
}
}
}, completion: nil);
}
}
}
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder);
}
}
class FilteredViewCollection {
var filteredViews: [GPUImageView]! = [GPUImageView]();
init(filteredViews: [GPUImageView]!){
self.filteredViews = filteredViews;
}
}
Một thể hiện của FilteredImageMaskView
được thêm theo chương trình vào một cái nhìn trong một viewController. Khi viewController đó được loại bỏ, giả định là các tài nguyên sẽ được xử lý - tôi đã cẩn thận để tránh giữ lại chu kỳ. Khi tôi xem mức tiêu thụ bộ nhớ trong trình gỡ rối trên thiết bị thực, bộ nhớ sẽ giảm một cách thích hợp khi viewController bị loại bỏ. Tuy nhiên, nếu tôi liên tục tải viewController đó để xem hình ảnh, sau đó loại bỏ nó, sau đó tải lại nó, tôi cuối cùng sẽ gặp phải "Ứng dụng bị chấm dứt do lỗi bộ nhớ"
Nếu tôi đợi một lát sau khi loại bỏ viewController, lỗi bộ nhớ có vẻ ít thường xuyên hơn dẫn tôi tin rằng bộ nhớ vẫn đang được phát hành sau khi viewController được miễn nhiệm ...? Nhưng tôi cũng đã nhìn thấy lỗi chỉ sau một vài lần không mở và đóng cửa nhanh chóng của viewController.
Tôi phải đang sử dụng GPUImage và/hoặc GPUImageView không hiệu quả và tôi đang tìm kiếm hướng dẫn.
Cảm ơn!
EDIT: Xem bên dưới để thực hiện bộ điều khiển chế độ xem.
import UIKit
class ViewImageViewController: UIViewController, FetchImageDelegate {
var imageManager = ImageManager();
@IBOutlet var mainView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
imageManager.fetchImageAsync(delegate: self);
}
// This callback is dispatched on the UI thread
func imageFetchCompleted(imageData: [UInt8]) {
let imageView = FilteredImageMaskView(frame: self.mainView.frame, image: UIImage(data: imageData));
mainView.addSubview(imageView);
var timer = NSTimer.scheduledTimerWithTimeInterval(NSTimeInterval(10.0), target: self, selector: Selector("displayReminder"), userInfo: nil, repeats: false);
}
func displayReminder(){
// Show an alert or message here
}
}
class ImageManager {
func fetchImageAsync(delegate: FetchImageDelegate) {
// This dispatches a high priority background thread
ThreadUtility.runOnHighPriorityBackgroundThread() { [weak delegate] in
// Get the image (This part could take a while in the real implementation)
var imageData = [UInt8]();
// Move to the UI thread
ThreadUtility.runOnMainThread({
if let strongDelegate = delegate {
strongDelegate.imageFetchCompleted(imageData);
}
});
}
}
}
Bây giờ tôi đang tìm kiếm thông qua phiên bản rút gọn này, không đi qua self
đến ImageManager
tạo ra một chu kỳ giữ lại mặc dù tôi tham khảo nó weak
ly để thread nền? Tôi có thể chuyển nó như là một tham chiếu yếu ngay từ ViewImageViewController
không? Chắc chắn rằng ViewImageViewController
bị loại bỏ trước khi phương thức fetchImageAsync
hoàn tất và gọi lại được gọi.
EDIT: Tôi nghĩ rằng tôi đã tìm thấy sự cố. Nếu bạn nhìn vào số ViewImageViewController
trong hàm gọi lại, tôi tạo một NSTimer và tự chuyển. Nghi ngờ của tôi là tạo ra một chu kỳ giữ lại nếu viewController được loại bỏ trước khi bộ đếm thời gian thực hiện. Điều đó sẽ giải thích tại sao nếu tôi đợi thêm vài giây nữa, tôi không nhận được lỗi bộ nhớ - bởi vì bộ đếm thời gian đã kích hoạt và viewController được xử lý đúng cách. Đây là bản sửa lỗi (tôi nghĩ).
// This is on the ViewImageViewController
var timer: NSTimer!;
// Then instead of creating a new variable, assign the timer to the class variable
self.timer = NSTimer.scheduledTimerWithTimeInterval(NSTimeInterval(10.0), target: self, selector: Selector("displayReminder"), userInfo: nil, repeats: false);
// And finally, on dismiss of the viewcontroller (viewWillDisappear or back button click event, or both)
func cancelTimer() {
if(self.timer != nil){
self.timer.invalidate();
self.timer = nil;
}
}
Bạn có thể cung cấp thêm thông tin về bộ điều khiển chế độ xem không? Có thực tế là đang được deallocated?Nếu bạn bị rò rỉ bộ nhớ, vấn đề sẽ không phải là mã mà bạn đã hiển thị. – matt
Chắc chắn. Tôi sẽ cập nhật OP. – a432511
@matt được thêm vào theo yêu cầu của bạn ... và bạn có thể đúng ... xem ở trên – a432511