I've started a document-base macOS app in SwiftUI and am using a FileDocument (not a Reference FileDocument) as the type of document. In every tutorial I've seen, even in Apple's own WWDC video discussing it (https://developer.apple.com/wwdc20/10039), a struct is always used to define the FileDocument.
My question is: is there an issue with using a class in the struct defining the document. Doing so doesn't result in any Xcode warnings but I wanted to be sure I'm not creating any issues for my app before going down this path.
Below is some example code for what I'm talking about: declaring TestProjectData
as a class for use within the DocumentDataAsClassInsteadOfStructDocument
- struct as a FileDocument?
public class TestProjectData: Codable{
var anotherString: String
init(){
anotherString = "Hello world!"
}
}
struct DocumentDataAsClassInsteadOfStructDocument: FileDocument, Codable {
var project: TestProjectData
init() {
project = TestProjectData()
}
static var readableContentTypes: [UTType] { [.exampleText] }
init(configuration: ReadConfiguration) throws {
guard let data = configuration.file.regularFileContents,
let _ = String(data: data, encoding: .utf8)
else {
throw CocoaError(.fileReadCorruptFile)
}
let fileContents = try JSONDecoder().decode(Self.self, from: data)
self = fileContents
}
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
let data = try JSONEncoder().encode(self)
return .init(regularFileWithContents: data)
}
}
SwiftUI's architecture is all about using value types for speed and consistency. E.g. on a state change we create all the
View
structs and then SwiftUI diffs and uses the result to init/update/deinitUIView
objects.I believe the same thing happens with
FileDocument
. The struct is diffed on a change and the difference is used to init/update/deinit aUIDocument
object.If you init object vars inside these structs then basically it is a memory leak because a new object will be init every time the struct is created which is every time something changes. Also chances are you'll end up using the wrong instance of the object because there will be so many. You can see this type of problem surface when blocks are used inside
body
, the callback usually happens on an older version of theView
struct, which isn't a problem when everything is value types but it is a big problem if referencing old objects.Try to stick to value types in SwiftUI if you can, if you use objects you'll run into all kinds of headaches. And I don't think
ReferenceFileDocument
even works yet - I seem to remember it needs some kind of undo manager workaround.