有没有办法将 Swift 枚举类型的变量分配给 NSObject 类型的变量?

如何解决有没有办法将 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 界面的快照如下所示:

enter image description here

如有必要,将提供更多代码。非常感谢!

解决方法

您可以使用存储为 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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?