如何解决有没有办法将 Swift 枚举类型的变量分配给 NSObject 类型的变量?
在下面发布的我的程序代码中,我需要将一个 Swift 枚举类型的变量分配给一个 NSObject 类型的变量。但是,编译器不允许这样做。我知道这是不允许的。所以,我想知道是否有办法以某种方式更改枚举,以便将其分配给 NSObject 变量。谢谢!
照片+CoreDataClass.swift
import Foundation
import CoreData
@objc(Photo)
public class Photo: NSManagedobject {
}
照片+CoreDataProperties.swift
import Foundation
import CoreData
extension Photo {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Photo> {
return NSFetchRequest<Photo>(entityName: "Photo")
}
@NSManaged public var datetaken: String?
@NSManaged public var datetakengranularity: NSObject?
@NSManaged public var datetakenunkNow: String?
@NSManaged public var farm: Int32
@NSManaged public var heightZ: Int32
@NSManaged public var photoID: String?
@NSManaged public var isfamily: Int32
@NSManaged public var isfriend: Int32
@NSManaged public var ispublic: Int32
@NSManaged public var owner: String?
@NSManaged public var secret: String?
@NSManaged public var server: String?
@NSManaged public var title: String?
@NSManaged public var urlZ: String?
@NSManaged public var widthZ: Int32
}
extension Photo : Identifiable {
}
FlickrPhoto.swift
import Foundation
// MARK: - Photo
struct FlickrPhoto: Codable {
let photoID,owner,secret,server: String
let farm: Int
let title: String
let ispublic,isfriend,isfamily: Int
let datetaken: String
let datetakengranularity: Datetakengranularity
let datetakenunkNown: String
let urlZ: String?
let heightZ,widthZ: Int?
enum CodingKeys: String,CodingKey {
case owner,server,farm,title,ispublic,isfamily,datetaken,datetakengranularity,datetakenunkNown
case photoID = "id"
case urlZ = "url_z"
case heightZ = "height_z"
case widthZ = "width_z"
}
}
enum Datetakengranularity: Codable {
case integer(Int)
case string(String)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let x = try? container.decode(Int.self) {
self = .integer(x)
return
}
if let x = try? container.decode(String.self) {
self = .string(x)
return
}
throw DecodingError.typeMismatch(Datetakengranularity.self,DecodingError.Context(codingPath: decoder.codingPath,debugDescription: "Wrong type for Datetakengranularity"))
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .integer(let x):
try container.encode(x)
case .string(let x):
try container.encode(x)
}
}
}
extension FlickrPhoto: Equatable {
static func == (lhs: FlickrPhoto,rhs: FlickrPhoto) -> Bool {
// Two Photos are the same if they have the same photoID
return lhs.photoID == rhs.photoID
}
}
PhotoStore.swift
import UIKit
import CoreData
class PhotoStore {
private let session: URLSession = {
let config = URLSessionConfiguration.default
return URLSession(configuration: config)
}()
let imageStore = ImageStore()
let persistenContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "Photorama")
container.loadPersistentStores { (description,error) in
if let error = error {
print("Error setting up Core Data (\(error))")
}
}
return container
}()
private func processphotosRequest (data: Data?,error: Error?) ->
Result<[FlickrPhoto],Error> {
guard let jsonData = data else {
return .failure(error!)
}
//return FlickrAPI.photos(fromJSON: jsonData)
let context = persistenContainer.viewContext
switch FlickrAPI.photos(fromJSON: jsonData) {
case let .success(flickrPhotos):
let _ = flickrPhotos.map { flickrPhoto -> Photo in
let fetchRequest: NSFetchRequest<Photo> = Photo.fetchRequest()
let predicate = nspredicate(format: "\(#keyPath(Photo.photoID)) == \(flickrPhoto.photoID)")
fetchRequest.predicate = predicate
var photo: Photo!
context.performAndWait {
photo = Photo(context: context)
photo.photoID = flickrPhoto.photoID
photo.owner = flickrPhoto.owner
photo.secret = flickrPhoto.secret
photo.server = flickrPhoto.server
photo.farm = Int32(flickrPhoto.farm)
photo.title = flickrPhoto.title
photo.ispublic = Int32(flickrPhoto.ispublic)
photo.isfriend = Int32(flickrPhoto.isfriend)
photo.isfamily = Int32(flickrPhoto.isfamily)
photo.datetaken = flickrPhoto.datetaken
photo.datetakengranularity = flickrPhoto.datetakengranularity // The compiler reports error here:
// Cannot assign value of type 'Datetakengranularity' to type 'NSObject?'
photo.datetakenunkNow = flickrPhoto.datetakenunkNown
photo.urlZ = flickrPhoto.urlZ
photo.heightZ = Int32(flickrPhoto.heightZ!)
photo.widthZ = Int32(flickrPhoto.widthZ!)
}
return photo
}
return .success(flickrPhotos)
case let .failure(error):
return .failure(error)
}
}
func fetchAllPhotos (completion: @escaping (Result<[Photo],Error>) -> Void) -> Void {
let fetchRequest: NSFetchRequest<Photo> = Photo.fetchRequest()
let sortByDataTaken = NSSortDescriptor(key: #keyPath(Photo.datetaken),ascending: true)
fetchRequest.sortDescriptors = [sortByDataTaken]
let viewContext = persistenContainer.viewContext
viewContext.perform {
do {
let allPhotos = try viewContext.fetch(fetchRequest)
completion(.success(allPhotos))
} catch {
completion(.failure(error))
}
}
}
func fetchRecentPhotos (completion: @escaping (Result<[FlickrPhoto],Error>) -> Void) {
let url = FlickrAPI.interestingPhotoURL
let request = URLRequest(url: url)
let task = session.dataTask(with: request) {
(data,response,error) in
var result = self.processphotosRequest(data: data,error: error)
if case .success = result {
do {
try self.persistenContainer.viewContext.save()
} catch {
result = .failure(error)
}
}
OperationQueue.main.addOperation {
completion(result)
}
}
task.resume()
}
func fetchImage (for photo: Photo,completion: @escaping (Result<UIImage,Error>) -> Void) {
let photoKey = photo.photoID
if let image = imageStore.image(forKey: photoKey!) {
OperationQueue.main.addOperation {
completion(.success(image))
}
return
}
guard let photoURL = photo.urlZ else { return }
guard let requestURL = URL(string: photoURL) else {
completion(.failure(PhotoError.missingImageURL))
return
}
let request = URLRequest(url: requestURL)
let task = session.dataTask(with: request) {
(data,error) in
let result = self.processImageRequest(data: data,error: error)
if case let .success(image) = result {
self.imageStore.setimage(image,forKey: photoKey!)
}
OperationQueue.main.addOperation {
completion(result)
}
}
task.resume()
}
private func processImageRequest (data: Data?,error: Error?) -> Result<UIImage,Error> {
guard let imageData = data,let image = UIImage(data: imageData) else {
// Couldn't create an image
if data == nil {
return .failure(error!)
} else {
return .failure(PhotoError.imageCreationError)
}
}
return .success(image)
}
}
enum PhotoError: Error {
case imageCreationError
case missingImageURL
}
Photorama.xcdatamodeld 界面的快照如下所示:
如有必要,将提供更多代码。非常感谢!
解决方法
您可以使用存储为 enum
中的 NSData
属性的 hacky NSObject
字节序列化来实现。
enum Test {
case testCase
case testCase2
}
func bytes<T>(of value: T) -> [UInt8]{
var value = value
let size = MemoryLayout<T>.size
return withUnsafePointer(to: &value,{
$0.withMemoryRebound(to: UInt8.self,capacity: size,{
Array(UnsafeBufferPointer(start: $0,count: size))
})
})
}
let testCase: Test = .testCase
let testCase2: Test = .testCase2
var testBytes = bytes(of: testCase)
var testBytes2 = bytes(of: testCase2)
let data = NSData(bytes: &testBytes,length: testBytes.count)
let data2 = NSData(bytes: &testBytes2,length: testBytes2.count)
let testCaseDeserialized = data.bytes.bindMemory(to: Test.self,capacity: 1).pointee
let testCase2Deserialized = data2.bytes.bindMemory(to: Test.self,capacity: 1).pointee
,
我尝试通过 AnyObject 将 flickrPhoto.datatakengranularity 变量桥接到 NSObject,如下所示:
photo.datetakengranularity = (flickrPhoto.datetakengranularity as AnyObject as! NSObject)
编译器没有抱怨。这可能是因为本质上 AnyObject 等同于 NSObject 并且 flickrPhoto.datetakengranularity 可以转换为 AnyObject。我不知道下面发生了什么,但无论如何它都有效。我不知道为什么。
感谢大家的关心和支持!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。