2004년에 했던 주제 + 새로운 API추가로 인한 세션
파일의 타입을 어떻게 인식하는가?
POSIX 용어로 파일이란 연속된 바이트열이다.
파일의 바이트열을 직접 확인하는 방법은 비용이 크고, 일반적인 프로그램의 권한을 넘어가는 일이다.
시스템에서는 확장자를 사용한다. -> 애플 시스템에서는 보여주지 않지만.
웹서버에서는 mimetype이라는 것을 사용한다.
애플에서는 이를 단일화한 Uniform Type Ideitifier를 사용한다.
UTI는 계층 구조를 이룬다(jpg,png,tiff 등은 모두 동일한 이미지 타입이다)
Type은 다른 타입을 채택(conform)할 수 있다.
한 타입은 여러개의 타입을 채택할 수 있다.
이는 swift/obj-c의 프로토콜 같은 거다.
ex(public.jpeg -> public.image -> public.data -> public.item)
특별한 UTI
UTI가 사용되는 곳
시스템에 자신의 타입을 알려주는 방법
타입 선언: 해당 타입이 존재한다고 선언하는 것. 해당 타입을 다룰 수 있다는 선언은 아니다.
타입 지원: 해당 타입을 다룰 수 있다는 선언. 자기가 타입을 정의하지 않아도 지원은 가능하다.
타입 import&export
Xcode 프로젝트 - info - exported Type Identifiers로 타입을 정의한다. 혹은 imported Type Identifiers로 타입을 가져온다. -> 두개 다 생긴 건 동일하다.
Document Type에 Document로 다룰 UTI 등록
코드에서 UTI 다루기
for fileURL in /* ... */ {
let resourceValues = try fileURL.resourceValues(forKeys: [.typeIdentifierKey])
if let type = resourceValues.typeIdentifier {
let description = UTTypeCopyDescription(type as CFString)?.takeUnretainedValue()
print("\\\\(fileURL)'s type: \\\\(description)")
if UTTypeConformsTo(type as CFString, kUTTypeImage) {
drawPicture(at: fileURL)
} else if UTTypeConformsTo(type as CFString, kUTTypeAudio) {
playSong(at: fileURL)
}
}
}
import UniformTypeIdentifiers
for fileURL in /* ... */ {
let resourceValues = try fileURL.resourceValues(forKeys: [.contentTypeKey])
if let type = resourceValues.contentType {
let description = type.localizedDescription
print("\\\\(fileURL)'s type: \\\\(description)")
if type.conforms(to: .image) {
drawPicture(at: fileURL)
} else if type.conforms(to: .audio) {
playSong(at: fileURL)
}
}
}
extension UTType {
// export는 이 앱이 해당 타입을 만들고, 관련 책임을 가지고 있다는 것
public static let myFileFormat = UTType(exportedAs: "com.example.myfileformat")
// 해당 타입을 알긴 하지만, 나보다 더 잘 아는 앱이 있을 것이다.
// 만약 owner가 내가 원하는 속성과 다르게 UTI를 정의했다면 시스템이 즉석에서 바꿔준다.
public static var competitiorFileFormat: UTType {
UTType(importedAs: "com.competitor.fileformat")
}
}
/// URL 타입의 새로운 프로퍼티
let resourceValues = try fileURL.resourceValues(forKeys: [.contentTypeKey])
if let type = resourceValues.contentType {/* ... */}
/// 파일 이름 생성
var fileURL = directoryURL.appendingPathComponent("My Doctoral Thesis", comformingTo: .rtf)
fileURL.appendingPathExtension(for: .html)
_ = ("Space Kitty 2004 FINAL v10.4 DRAFT" as NSString).appendingPathExtension(for: .pdf)
struct MyGreatView: View {
@State var text: String? = nil
var body: some View {
MyGreatView(content: $text)
.onDrop(of: [.text], isTergeted: nil){ providers in
_ = providers.first?.loadObject(ofClass: String.self) { string, error in
text = string
}
return true
}
}
let icon = NSWorkSpace.shared.icon(for: .vCard)
NSOpenPanel().allowedContentTypes = [.usd, .usdz, realityFile] // NSSavePanel도 동일