当我使用 Swift 发出核心数据提取请求时,我遇到了内存泄漏。但是,我在应用程序的不同部分发出了几乎相同的提取请求,但它不会导致泄漏。在这两种情况下,提取请求都是在 View Controller 的 viewDidLoad 中发出的,提取请求的结果被分配给 View Controller 的可选属性。
以下是不会造成任何泄漏的获取请求的方法:
class LocationFilter {
//Lots of other code...
class func getAllPlacesOfRegionType<T: Region>(regionType: RegionType) -> [T] {
let fetchRequest = NSFetchRequest(entityName: regionType.rawValue)
var places: [T]
do {
places = try CoreDataStack.sharedInstance.context.executeFetchRequest(
fetchRequest) as! [T]
} catch let error as NSError {
NSLog("Fetch request failed: %@", error.localizedDescription)
places = [T]()
}
places.sortInPlace({ (firstPlace, nextPlace) -> Bool in
//Ingenious sorting code...
})
return places
}
}
该方法在viewController的viewDidLoad中调用,结果赋值给属性var allRegions: [Region]?
没有任何泄漏。这是代码:
class PlacesTableViewController: UITableViewController {
var allRegions: [Region]?
@IBOutlet weak var segmentedRegions: UISegmentedControl!
@IBAction func selectRegionSegment(sender: UISegmentedControl) {
// When the segmented control is tapped, the appropriate list will be loaded.
switch sender.selectedSegmentIndex {
case 0: //Country Segment
allRegions = LocationFilter.getAllPlacesOfRegionType(RegionType.Country)
case 1: //States segment
allRegions = LocationFilter.getAllPlacesOfRegionType(RegionType.Province)
case 2: //Cities segment
allRegions = LocationFilter.getAllPlacesOfRegionType(RegionType.City)
case 3: //Addresses segment
allRegions = LocationFilter.getAllPlacesOfRegionType(RegionType.Address)
default:
break
}
// Then reload the cells with animations.
let index = NSIndexSet(index: 0)
tableView.reloadSections(index, withRowAnimation: UITableViewRowAnimation.Automatic)
}
override func viewDidLoad() {
super.viewDidLoad()
selectRegionSegment(segmentedRegions)
}
}
下面的方法在不同viewController的viewDidLoad中调用来设置属性var allDays: [Day]!
.
class DateFilter {
//Lots of other code in the class...
class func getAllDays() -> [Day] {
let fetchRequest = NSFetchRequest(entityName: "Day")
let days: [Day]
do {
days = try CoreDataStack.sharedInstance.context.executeFetchRequest(
fetchRequest) as! [Day]
} catch let error as NSError {
NSLog("Fetch request failed: %@", error.localizedDescription)
days = [Day]()
}
return days
}
}
这就是它的名字:
class SearchViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var allDays: [Day]!
override func viewDidLoad() {
super.viewDidLoad()
allDays = DateFilter.getAllDays()
let backgroundView = UIView(frame: CGRectZero)
tableView.tableFooterView = backgroundView
tableView.backgroundColor = UIColor.groupTableViewBackgroundColor()
}
}
Xcode 工具在调用时检测到内存泄漏。据说负责的图书馆是libswiftFoundation.dylib
, 负责的框架是 static Array<A>._forceBridgeFromObjectiveC<A>(NSArray, result:inout [A]?) -> ()
.当我查看 Cycles & Roots 时,它显示一个 NSArray
在根部,带有 +16 list: (null)
和 +24 [no ivar]: (null)
分支。
我存储提取请求结果的方式有问题吗?或者这是 Swift 与 Core Data 交互方式中的错误?
编辑:根据 Mundi 的建议整理代码。 编辑 2:添加了调用获取请求函数的代码。
最佳答案
在尝试了很多事情之后,我很确定这是在获取我的 Day
实体时 Core Data 如何将 NSArray 转换为 Swift 数组的错误。也许它与 Day
实体的关系或属性有关。我会继续研究它。
目前,我找到了解决方法。 Instruments 不断指向将 NSArray 转换为 Array 的 libswiftFoundation 方法,Cycles & Roots 不断显示一个没有 no ivar
的 NSArray。根据我的研究,这与获取请求创建的 NSArray 的初始化有关,它在后台转换为 Swift 数组。由于我无法更改它,因此我根据获取结果创建了一个新数组:
override func viewDidLoad() {
super.viewDidLoad()
let fetchResults: [Day] = DateFilter.getAllDays()
allDays = fetchResults.map({$0})
let backgroundView = UIView(frame: CGRectZero)
tableView.tableFooterView = backgroundView
tableView.backgroundColor = UIColor.groupTableViewBackgroundColor()
}
神奇的是,内存泄漏消失了!我不完全确定为什么 fetchResults
数组会泄漏,但这似乎是问题的根源。
关于ios - 使用 Swift 获取核心数据请求中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33574867/