Where do I register a ValueTransformer in Swift?
You are right, you can register your value transformers in the AppDelegate
. If you want something that closer resembles ObjectiveC's +initialize
you can use lazy initialization of a class variable. E.g:
class AppDelegate: NSObject, NSApplicationDelegate {
static let doInitialize: Void = {
// register transformers here
}()
override init() {
super.init()
AppDelegate.doInitialize
}
}
This pattern should also work for classes other than the AppDelegate
if you want to keep the transformers things closer to the classes that actually use them.
CoreData ValueTransformer.transformedValueClass() is never called in Swift 3
Apparently, Core Data only supports transforming to NSData. I couldn't find the original documentation for this in the Core Data programming guide but after much searching other users have encountered the same issue.
The idea behind transformable attributes is that you access an
attribute as a non-standard type, but behind the scenes Core Data uses
an instance of NSValueTransformer to convert the attribute to and from
an instance of NSData. Core Data then stores the data instance to the
persistent store.By default, Core Data uses the NSKeyedUnarchiveFromDataTransformerName
transformer, however you can specify your own transformer if you want.
If you specify a custom transformer, it must transform an instance of
the non-standard data type into an instance of NSData and support
reverse transformation. You should not specify a name if you are using
the default transformer.
Custom NSValueTransformer in xcode 6 with swift
After you initialise newTransformer you should also include the line:
NSValueTransformer.setValueTransformer(newTransformer, forName: "myTransformer")
Then in your Interface Builder you should use myTransformer instead of newTransformer under the Value Transformer dropdown.
Where do I register a ValueTransformer in Swift?
You are right, you can register your value transformers in the AppDelegate
. If you want something that closer resembles ObjectiveC's +initialize
you can use lazy initialization of a class variable. E.g:
class AppDelegate: NSObject, NSApplicationDelegate {
static let doInitialize: Void = {
// register transformers here
}()
override init() {
super.init()
AppDelegate.doInitialize
}
}
This pattern should also work for classes other than the AppDelegate
if you want to keep the transformers things closer to the classes that actually use them.
CoreData: ValueTransformer functions are not called
You haven't overridden the correct methods of ValueTransformer
. Your methods are:
func transformedValue(value: String?) -> NSData?
func reverseTransformedValue(value: NSData?) -> String?
The correct methods are:
func transformedValue(_ value: Any?) -> Any?
func reverseTransformedValue(_ value: Any?) -> Any?
The big hint that you're implementing the wrong methods is that you didn't need to add the override
keyword.
BTW, this expression:
encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))!
can be replaced with:
encoding: .uf8
It would also likely be better to replace your return "nil"
with return nil
; it's a String?
, so it can be nil
if things go wrong.
RestKit valueTransformer not being called
So I managed to finally figure out what the problem was.
My podfile was configured to use RestKit 0.20.3. And then I had added RKValueTransformers
as another Pod. However, RestKit 0.20.3 and earlier come with their own version of RKValueTransformer (.h and .m) files. And those older versions of RestKit doesn't support adding your own Transformers, because it doesn't make use of the newer RKValueTransformers
library.
When I upgraded my RestKit version to the newest version (actually anything above 0.21.0 would work), things started working fine. I didn't need to add the pod RKValueTransformers, because it gets added automatically as a dependency of RestKit.
Where to implement NSValueTransformer for Core Data in Swift
The "where" is just anywhere in your project. Anywhere that ensures that your NSValueTransformer
subclass will exist at run time. Implement the NSValueTransformer
subclass, and enter the class name in the Core Data model as the value transformer.
However there is a default transformer. Any class that adopts the NSCoding
protocol can be automatically transformed by Core Data. In that case you mark the attribute as transformable but don't include a class name. This includes NSURL
, so you don't need to transform that or convert it to a string.
For your NSDocument
subclass then, you have the option of either implementing NSCoding
in the class or of implementing an NSValueTransformer
subclass for the document type.
Related Topics
Swift Xcode 7 Beta 5 Type Cannot Refer to Itself as a Requirement
How Does Swift Disambiguate Type Arguments in Expression Contexts
Http Status 415 When Using Alamofire Multipart Upload
Swift 4 "Extra Argument in Call" Rxswift
Covert Realm List to Realm Result
Dictionary Becomes Nil When Trying to Pass Back Cllocation Object to iOS App Extension
Getting Reference to a Dictionary Value
Problem with Frameworks in Command Line Tool
Avspeechsynthesizer Isspeaking Not Working in Swift
Extract Reality Composer Scene for Arquicklook
Dynamictype of Optional Chaining Not The Same as Assignment
What Is The Reason to Store Subscription into a Subscriptions Set
Parsing JSON from Url Ends Up with an Error - Swift 5
Using a Timer in The Background Thread to Update UI
Cannot Use Mutating Member ... Because Append
Understanding Optional Global Variables in Swift
Why Is Swift Giving Me Inaccurate Floating Point Arithmetic Results