[英]Is there a way to assign a variable of Swift enum type to a variable of NSObject type?
In my program code which is posted below, I need to assign a variable of Swift enum type to a variable of NSObject type.在下面发布的程序代码中,我需要将 Swift 枚举类型的变量分配给 NSObject 类型的变量。 However, the compiler doesn't allow this.
但是,编译器不允许这样做。 I know this is not allowed.
我知道这是不允许的。 So, I wonder whether there is a way to change the enum somehow so that it can be assigned to an NSObject variable.
所以,我想知道是否有办法以某种方式更改枚举,以便可以将其分配给 NSObject 变量。 Thank you!
谢谢!
Photo+CoreDataClass.swift照片+CoreDataClass.swift
import Foundation
import CoreData
@objc(Photo)
public class Photo: NSManagedObject {
}
Photo+CoreDataProperties.swift照片+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 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, secret, server, farm, title, ispublic, isfriend, 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 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, response, 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
}
A snapshot of the Photorama.xcdatamodeld interface is shown below: Photorama.xcdatamodeld 接口的快照如下所示:
More code will be provided if necessary.如有必要,将提供更多代码。 Thanks very much!
非常感谢!
You could do it using hacky enum
byte serialization stored as NSData
property in your NSObject
.您可以使用
NSObject
中存储为NSData
属性的 hacky enum
字节序列化来完成此操作。
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
I tried bridging the flickrPhoto.datatakengranularity variable to NSObject via AnyObject like this:我尝试通过 AnyObject 将 flickrPhoto.datatakengranularity 变量桥接到 NSObject,如下所示:
photo.datetakengranularity = (flickrPhoto.datetakengranularity as AnyObject as! NSObject)
And the compiler made no complaints.编译器没有抱怨。 This may be because in essence AnyObject is equivalent to NSObject and flickrPhoto.datetakengranularity is convertible to AnyObject.
这可能是因为本质上 AnyObject 等价于 NSObject,而 flickrPhoto.datetakengranularity 可以转换为 AnyObject。 I don't know what happened underneath but it worked anyway.
我不知道下面发生了什么,但它仍然有效。 I don't know why.
我不知道为什么。
Thanks to all for your concern and support!感谢大家的关心和支持!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.