watchOS라던가, Widget같은 녀석들은 iOS 어플이 있어야만 만들 수 있도록 의존이 되어있고 (워치는 단독이 되긴 하지만), 사람들은 설치할땐 똑같은 앱을 설치한 것 처럼 보이지만, 실상은 그렇지 않다.
Xcode에서는 사실상 다른 앱 취급을 받기 때문에 각각 다른 Sandbox을 가지게 된다. 그러나, Xcode에서 AppGroup 옵션을 켜주어 서로 데이터를 공유할 수 있게 되는데, 이게 어디까지 공유가 되는건지, 어떤 원리로 공유가 되는건지 궁금해서 한번 실험해보았음.
App SandBox System에서 공유할만한건 Realm이나 SwiftData 같은 데이터나 UserDefaults, 사진같은걸 저장시킬 수 있다.
실험 구성은 다음과 같다.
- AppGroup을 켜지 않은채로 데이터를 저장시킨다.
- Appgroup을 키면 데이터가 남아있는지 확인한다.
- watchOS앱을 만들어 공유해본다.
- 아에 다른 프로젝트에 iOS앱을 만들어 데이터를 공유해본다.
일단 데이터는 총 3개로 잡았다.
대충 간단하게 코드를 구현해보았다.
struct ContentView: View {
@Query var test: [TestModel]
@Environment (\.modelContext) var modelContext
@State private var show = false
@State private var image: UIImage?
var body: some View {
VStack {
Text(test.first?.content ?? "no data")
Text(UserDefaults.standard.string(forKey: "test") ?? "no user")
if let saveImage = loadImageFromDirectory() {
Image(uiImage: saveImage)
.resizable()
.frame(width: 100, height: 100)
}
Button("저장임") {
modelContext.insert(TestModel(content: "Test"))
try? modelContext.save()
UserDefaults.standard.setValue("Test", forKey: "test")
if let image {
saveImageToDirectory(image: image)
}
}
Button("image") {
show.toggle()
}
.sheet(isPresented: $show, content: {
ImagePicker(image: $image)
})
}
.padding()
}
func saveImageToDirectory(image: UIImage) {
let documentsDirectory = FileManager.default.urls(for: .documentDirectory,in: .userDomainMask).first!
let imageName = "test"
// 이미지의 경로 및 확장자 형식 (conformingTo: 확장자)
let fileURL = documentsDirectory.appendingPathComponent(imageName, conformingTo: .jpeg)
// Directory 경로라고 했죠? 파일이 저장된 위치를 확인하고 싶을 때, 단순히 경로를 프린트해서 확인이 가능합니다.
print(fileURL)
do {
// 파일로 저장하기 위해선 data 타입으로 변환이 필요합니다. (JPEG은 압축을 해주므로 크기가 줄어듭니다. PNG는 비손실)
if let imageData = image.jpegData(compressionQuality: 1) {
// 이미지 데이터를 fileURL의 경로에 저장시킵니다.
try imageData.write(to: fileURL)
print("Image saved at: \(fileURL)")
}
} catch {
print("Failed to save images: \(error)")
}
}
func loadImageFromDirectory() -> UIImage? {
let fileManager = FileManager.default
// 파일 경로로 접근
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = documentsDirectory.appendingPathComponent("test", conformingTo: .jpeg)
// 이미지 파일이 존재한다면, 이미지로 변환 후 리턴
guard fileManager.fileExists(atPath: fileURL.path) else { return nil }
return UIImage(contentsOfFile: fileURL.path)
}
}
일단 데이터 저장
사진도 정상적으로 잘 들어와 있는걸 알 수 있다.
AppGroup을 켜면 App SandBox가 이동할까? 라는 의문에서 시작된 실험 내용이다.
일단 데이터가 살아있다.
이미지를 바꾸면? 이전에 저장되어 있던 곳에 덮어 씌워지게 될까? 아니면 아에 새로 생겨버릴까?
그 자리에서 이미지가 바뀌는걸 볼 수 있다.
아무것도 공유되지 않았다.
CloudKit같이 원격으로 데이터를 저장하지 않는 이상 데이터가 공유되기는 어려운 것 같다.
실험결과 SwiftData는 공유가 되었지만 UserDefaults, 사진은 공유가 되질 않았다.
App Group을 켜준다고 같은 Sandbox를 공유하는게 아니라는걸 알 수 있었다.
다음 포스팅은 같은 Sandbox가 아님에도 SwiftData는 왜 다른 iOS 프로젝트와 데이터를 공유할 수 있었는지, 저장 방식에 어떤 차이가 있는지 알아보는 포스팅이 될 것 같다.