I'm trying to understand the behavior of Allows External Storage
property of Core Data attributes and see if it would save me from storing files in the file system manually. I wanted to see how would it perform when dealing with really large files. For that, I created a dummy project and stored a large file (2 GB) using Core Data. Then, I monitored the memory usage as I fetch and process the data, and to my surprise, it did not exceed 48 MB! Why is that? Does it fetch the data in chunks? If so, how? Does the Data
struct have APIs that allow Core Data to do that?
More details of what I did:
- Created an entity
File
with only two attributes,fileName
(String) anddata
(Data).
- Checked the
Allows External Storage
property for thedata
attribute. Stored a 2 GB file in the
File
entity. I put this code inviewDidLoad
method to do that.do { // Store file let fileURL = Bundle.main.url(forResource: "RawData/LargeFile", withExtension: nil)! let file = File(context: AppDelegate.viewContext) file.name = fileName file.data = try Data(contentsOf: fileURL) try AppDelegate.viewContext.save() } catch { print(error.localizedDescription) }
Closed the app, and relaunch it with new code in
viewDidLoad
that fetches and processes the large file's data.let fileData = File.files(named: name).first!.data! DispatchQueue.global(qos: .userInteractive).async { let result = self.process(data: fileData) print("The result: \(result)") }
- The
files
static method of the File class returnes all files in the File entity.
And here is the process method, which loopes through the data, byte by byte, reading and XORing then returning the result. It can be any method really, the important thing here is to read all the bytes of the data.
private func process(data: Data) -> UInt8 { print("Processsing \(data.count) bytes") var accumulator: UInt8 = 0 for byte in data { accumulator ^= byte } return accumulator }
- The
I monitored the memory usage.
I'm pretty sure it has something to do with Core Data and not Data
since doing the same steps when loading the data
from the disk (Data(contentsOf: URL)
) will result in 3+ GB memory usage (also, why the additional 1 GB?).
Lastly, is there any reason to not use Allows External Storage
feature and instead, store files manually in the file system? I know this question has been discussed a lot; but most of the points I have read that suggest using the manual way were mentioning performance issues with Core Data, even though my little experiment shows that Core Data performs well.
Any help would be appreciated!