How to use Parse.com booleans in subclasses - swift

I have subclassed PFUser and added a property isManager
class User : PFUser, PFSubclassing {
#NSManaged var isManager: Bool
override class func load() {
self.registerSubclass()
}
}
I tried
user.isManager = false
but get the run time error
[Foo.User setIsManager:]: unrecognized selector sent to instance 0x145bf550
I also tried using NSNumber because of core data
user.isManager = NSNumber(bool: false)
but get the compile time error
NSNumber is not convertible to bool

I've actually found it to be much simpler to implement "get" and "set".
class User: PFUser, PFSubclassing {
var isManager: Bool {
get { return self["isManager"] as! Bool }
set { self["isManager"] = newValue }
}
...
}

Set the bool using NSNumber
currentUser!.isManager = NSNumber(bool: true)
Then use the following for if statements
if currentUser!.isManager.isEqualToNumber(NSNumber(bool: true))
And then in your class:
class User : PFUser, PFSubclassing {
#NSManaged var isManager: NSNumber
override class func load() {
self.registerSubclass()
}
}

Related

Compile error on Property Wrapper in Swift 5.1

I'm figuring out Property Wrappers in Swift, but I seem to miss something.
This is how I wrote a property wrapper for a dependency injection framework we use:
#propertyWrapper
struct Inject<Value> {
var _value: Value
var wrappedValue: Value {
get {
return _value
}
set {
_value = newValue
}
}
init(_ container: Container = AppContainer.shared) {
do {
_value = try container.resolve(Value.self)
} catch let e {
fatalError(e.localizedDescription)
}
}
}
But when I use it in my class like below, I get a compile error. I've seen a lot of examples that to me do the exact same thing but probably there are some differences.
class X: UIViewController {
#Inject var config: AppConfiguration
....
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
config.johnDoSomething() // Compile error: 'AppConfiguration' is not convertible to 'AppConfiguration?'
}
}
I few days ago I came across a reference that Xcode had compile issues with Generic Property Wrappers, but I can't find it anymore. I'm not sure if that's relevant but maybe somebody on SO can help me out.
Using Xcode 11.3.1
As requested, hereby a reprex (one file in playground):
import UIKit
/// This class is only to mimick the behaviour of our Dependency Injection framework.
class AppContainer {
static let shared = AppContainer()
var index: [Any] = ["StackOverflow"]
func resolve<T>(_ type: T.Type) -> T {
return index.first(where: { $0 as? T != nil }) as! T
}
}
/// Definition of the Property Wrapper.
#propertyWrapper
struct Inject<Value> {
var _value: Value
var wrappedValue: Value {
get {
return _value
}
set {
_value = newValue
}
}
init(_ container: AppContainer = AppContainer.shared) {
_value = container.resolve(Value.self)
}
}
/// A very minimal case where the compile error occurs.
class X {
#Inject var text: String
init() { }
}
Just dealing with your "reprex":
Change
#Inject var text: String
to
#Inject() var text: String

Can a Swift Property Wrapper reference the owner of the property its wrapping?

From within a property wrapper in Swift, can you someone refer back to the instance of the class or struck that owns the property being wrapped? Using self doesn't obviously work, nor does super.
I tried to pass in self to the property wrapper's init() but that doesn't work either because self on Configuration is not yet defined when #propertywrapper is evaluated.
My use case is in a class for managing a large number of settings or configurations. If any property is changed, I just want to notify interested parties that something changed. They don't really need to know which value just, so use something like KVO or a Publisher for each property isn't really necessary.
A property wrapper looks ideal, but I can't figure out how to pass in some sort of reference to the owning instance that the wrapper can call back to.
References:
SE-0258
enum PropertyIdentifier {
case backgroundColor
case textColor
}
#propertyWrapper
struct Recorded<T> {
let identifier:PropertyIdentifier
var _value: T
init(_ identifier:PropertyIdentifier, defaultValue: T) {
self.identifier = identifier
self._value = defaultValue
}
var value: T {
get { _value }
set {
_value = newValue
// How to callback to Configuration.propertyWasSet()?
//
// [self/super/...].propertyWasSet(identifier)
}
}
}
struct Configuration {
#Recorded(.backgroundColor, defaultValue:NSColor.white)
var backgroundColor:NSColor
#Recorded(.textColor, defaultValue:NSColor.black)
var textColor:NSColor
func propertyWasSet(_ identifier:PropertyIdentifier) {
// Do something...
}
}
The answer is no, it's not possible with the current specification.
I wanted to do something similar. The best I could come up with was to use reflection in a function at the end of init(...). At least this way you can annotate your types and only add a single function call in init().
fileprivate protocol BindableObjectPropertySettable {
var didSet: () -> Void { get set }
}
#propertyDelegate
class BindableObjectProperty<T>: BindableObjectPropertySettable {
var value: T {
didSet {
self.didSet()
}
}
var didSet: () -> Void = { }
init(initialValue: T) {
self.value = initialValue
}
}
extension BindableObject {
// Call this at the end of init() after calling super
func bindProperties(_ didSet: #escaping () -> Void) {
let mirror = Mirror(reflecting: self)
for child in mirror.children {
if var child = child.value as? BindableObjectPropertySettable {
child.didSet = didSet
}
}
}
}
You cannot do this out of the box currently.
However, the proposal you refer to discusses this as a future direction in the latest version:
https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md#referencing-the-enclosing-self-in-a-wrapper-type
For now, you would be able to use a projectedValue to assign self to.
You could then use that to trigger some action after setting the wrappedValue.
As an example:
import Foundation
#propertyWrapper
class Wrapper {
let name : String
var value = 0
weak var owner : Owner?
init(_ name: String) {
self.name = name
}
var wrappedValue : Int {
get { value }
set {
value = 0
owner?.wrapperDidSet(name: name)
}
}
var projectedValue : Wrapper {
self
}
}
class Owner {
#Wrapper("a") var a : Int
#Wrapper("b") var b : Int
init() {
$a.owner = self
$b.owner = self
}
func wrapperDidSet(name: String) {
print("WrapperDidSet(\(name))")
}
}
var owner = Owner()
owner.a = 4 // Prints: WrapperDidSet(a)
My experiments based on : https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md#referencing-the-enclosing-self-in-a-wrapper-type
protocol Observer: AnyObject {
func observableValueDidChange<T>(newValue: T)
}
#propertyWrapper
public struct Observable<T: Equatable> {
public var stored: T
weak var observer: Observer?
init(wrappedValue: T, observer: Observer?) {
self.stored = wrappedValue
}
public var wrappedValue: T {
get { return stored }
set {
if newValue != stored {
observer?.observableValueDidChange(newValue: newValue)
}
stored = newValue
}
}
}
class testClass: Observer {
#Observable(observer: nil) var some: Int = 2
func observableValueDidChange<T>(newValue: T) {
print("lol")
}
init(){
_some.observer = self
}
}
let a = testClass()
a.some = 4
a.some = 6
The answer is yes! See this answer
Example code for calling ObservableObject publisher with a UserDefaults wrapper:
import Combine
import Foundation
class LocalSettings: ObservableObject {
static var shared = LocalSettings()
#Setting(key: "TabSelection")
var tabSelection: Int = 0
}
#propertyWrapper
struct Setting<T> {
private let key: String
private let defaultValue: T
init(wrappedValue value: T, key: String) {
self.key = key
self.defaultValue = value
}
var wrappedValue: T {
get {
UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
public static subscript<EnclosingSelf: ObservableObject>(
_enclosingInstance object: EnclosingSelf,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, T>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Setting<T>>
) -> T {
get {
return object[keyPath: storageKeyPath].wrappedValue
}
set {
(object.objectWillChange as? ObservableObjectPublisher)?.send()
UserDefaults.standard.set(newValue, forKey: object[keyPath: storageKeyPath].key)
}
}
}

Swift - How to set a singleton to nil

I am writing an app in swift and use a singleton to share a class object, User, across the app.
I want to be able to set this singleton to 'nil' when the user logs out, so that when they log back in the old properties no longer exists (i.e. name, username, etc).
I am hoping there is an easy way to just set the singleton back to nil, instead of having to set each property to nil.
Here is my User class that is used in the app as User.activeUser:
class User: NSObject
{
class var activeUser : User? {
struct Static {
static let instance : User = User()
}
return Static.instance
}
}
How can I change this so that the below code does not give me a warning and actually nils out the singleton object:
User.activeUser = nil
This should work:
private var _SingletonSharedInstance:MyClass! = MyClass()
class MyClass {
let prop = "test"
class var sharedInstance : MyClass {
return _SingletonSharedInstance
}
init () {}
func destroy() {
_SingletonSharedInstance = nil
}
}
But then the references to the object are still kept, so you need to do some additional things to invalidate method calls in the class.
Your activeUser is set up as a read-only computed property. Every time you call User.activeUser it is going to recompute the activeUser for you. In order to set it to nil you'll have to add some logic to determine whether or not a user is logged in outside of the computed property. Something like this would work:
class User: NSObject
{
private struct userStatus { static var isLoggedIn: Bool = true }
class var activeUser : User? {
get {
if userStatus.isLoggedIn {
struct Static {
static let instance : User = User()
}
return Static.instance
} else {
return nil
}
}
set(newUser) {
if newUser != nil {
userStatus.isLoggedIn = true
} else {
userStatus.isLoggedIn = false
}
}
}
}
Here has a solution I used in java, but also works in swift:
class Manager {
private static var manager: Manager?
static func instance() -> Manager {
if Manager.manager == nil {
Manager.manager = Manager()
}
return Manager.manager!
}
func destroy() {
Manager.manager = nil
}
}

How do I create a weak stored property in a Swift extension?

Swift doesn't support stored properties in extensions. A way around that is to use objc_setAssociatedObject as suggested here. What I'm trying to do is create a stored property that is a zeroing weak reference. Note that using OBJC_ASSOCIATION_ASSIGN is not enough because it will not zero the reference when the object is deallocated.
I need something equivalent to
extension MyClass {
weak var myVar: NSObject?
}
I explored using obj_storeWeak and objc_loadWeak but ended up simply using a wrapper class:
internal class WeakWrapper : NSObject {
weak var weakObject : NSObject?
init(_ weakObject: NSObject?) {
weakObject = weakObject
}
}
extension MyClass {
var myVar: NSObject? {
get {
var weakWrapper: WeakWrapper? = objc_getAssociatedObject(self, &associationKey) as? WeakWrapper
return weakWrapper?.weakObject
}
set {
var weakWrapper: WeakWrapper? = objc_getAssociatedObject(self, &associationKey) as? WeakWrapper
if weakWrapper == nil {
weakWrapper = WeakWrapper(newValue)
objc_setAssociatedObject(self, &associationKey, weakWrapper, UInt(OBJC_ASSOCIATION_RETAIN))
} else {
weakWrapper!.weakObject = newValue
}
}
}
}

Is there a way to set associated objects in Swift?

Coming from Objective-C you can call function objc_setAssociatedObject between 2 objects to have them maintain a reference, which can be handy if at runtime you don't want an object to be destroyed until its reference is removed also. Does Swift have anything similar to this?
Here is a simple but complete example derived from jckarter's answer.
It shows how to add a new property to an existing class. It does it by defining a computed property in an extension block. The computed property is stored as an associated object:
import ObjectiveC
// Declare a global var to produce a unique address as the assoc object handle
private var AssociatedObjectHandle: UInt8 = 0
extension MyClass {
var stringProperty:String {
get {
return objc_getAssociatedObject(self, &AssociatedObjectHandle) as! String
}
set {
objc_setAssociatedObject(self, &AssociatedObjectHandle, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
EDIT:
If you need to support getting the value of an uninitialized property and to avoid getting the error unexpectedly found nil while unwrapping an Optional value, you can modify the getter like this:
get {
return objc_getAssociatedObject(self, &AssociatedObjectHandle) as? String ?? ""
}
The solution supports all the value types as well, and not only those that are automagically bridged, such as String, Int, Double, etc.
Wrappers
import ObjectiveC
final class Lifted<T> {
let value: T
init(_ x: T) {
value = x
}
}
private func lift<T>(x: T) -> Lifted<T> {
return Lifted(x)
}
func setAssociatedObject<T>(object: AnyObject, value: T, associativeKey: UnsafePointer<Void>, policy: objc_AssociationPolicy) {
if let v: AnyObject = value as? AnyObject {
objc_setAssociatedObject(object, associativeKey, v, policy)
}
else {
objc_setAssociatedObject(object, associativeKey, lift(value), policy)
}
}
func getAssociatedObject<T>(object: AnyObject, associativeKey: UnsafePointer<Void>) -> T? {
if let v = objc_getAssociatedObject(object, associativeKey) as? T {
return v
}
else if let v = objc_getAssociatedObject(object, associativeKey) as? Lifted<T> {
return v.value
}
else {
return nil
}
}
A possible
Class extension (Example of usage)
extension UIView {
private struct AssociatedKey {
static var viewExtension = "viewExtension"
}
var referenceTransform: CGAffineTransform? {
get {
return getAssociatedObject(self, associativeKey: &AssociatedKey.viewExtension)
}
set {
if let value = newValue {
setAssociatedObject(self, value: value, associativeKey: &AssociatedKey.viewExtension, policy: objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
}
I wrote a modern wrapper available at https://github.com/b9swift/AssociatedObject
You may be surprised that it even supports Swift structures for free.
Obviously, this only works with Objective-C objects. After fiddling around with this a bit, here's how to make the calls in Swift:
import ObjectiveC
// Define a variable whose address we'll use as key.
// "let" doesn't work here.
var kSomeKey = "s"
…
func someFunc() {
objc_setAssociatedObject(target, &kSomeKey, value, UInt(OBJC_ASSOCIATION_RETAIN))
let value : AnyObject! = objc_getAssociatedObject(target, &kSomeKey)
}
Update in Swift 3.0
For example this is a UITextField
import Foundation
import UIKit
import ObjectiveC
// Declare a global var to produce a unique address as the assoc object handle
var AssociatedObjectHandle: UInt8 = 0
extension UITextField
{
var nextTextField:UITextField {
get {
return objc_getAssociatedObject(self, &AssociatedObjectHandle) as! UITextField
}
set {
objc_setAssociatedObject(self, &AssociatedObjectHandle, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
Klaas answer just for Swift 2.1:
import ObjectiveC
let value = NSUUID().UUIDString
var associationKey: UInt8 = 0
objc_setAssociatedObject(parentObject, &associationKey, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
let fetchedValue = objc_getAssociatedObject(parentObject, &associationKey) as! String
Just add #import <objc/runtime.h> on your brindging header file to access objc_setAssociatedObject under swift code
The above friend has answered your question, but if it is related to closure properties, please note:
```
import UIKit
public extension UICollectionView {
typealias XYRearrangeNewDataBlock = (_ newData: [Any]) -> Void
typealias XYRearrangeOriginaDataBlock = () -> [Any]
// MARK:- associat key
private struct xy_associatedKeys {
static var originalDataBlockKey = "xy_originalDataBlockKey"
static var newDataBlockKey = "xy_newDataBlockKey"
}
private class BlockContainer {
var rearrangeNewDataBlock: XYRearrangeNewDataBlock?
var rearrangeOriginaDataBlock: XYRearrangeOriginaDataBlock?
}
private var newDataBlock: BlockContainer? {
get {
if let newDataBlock = objc_getAssociatedObject(self, &xy_associatedKeys.newDataBlockKey) as? BlockContainer {
return newDataBlock
}
return nil
}
set(newValue) {
objc_setAssociatedObject(self, xy_associatedKeys.newDataBlockKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
}
convenience init(collectionVewFlowLayout : UICollectionViewFlowLayout, originalDataBlock: #escaping XYRearrangeOriginaDataBlock, newDataBlock: #escaping XYRearrangeNewDataBlock) {
self.init()
let blockContainer: BlockContainer = BlockContainer()
blockContainer.rearrangeNewDataBlock = newDataBlock
blockContainer.rearrangeOriginaDataBlock = originalDataBlock
self.newDataBlock = blockContainer
}
```
For 2022, now very simple:
// Utils-tags.swift
// Just a "dumb Swift trick" to add a string tag to a view controller.
// For example, with UIDocumentPickerViewController you need to know
// "which button was clicked to launch a picker"
import UIKit
private var _docPicAssociationKey: UInt8 = 0
extension UIDocumentPickerViewController {
public var tag: String {
get {
return objc_getAssociatedObject(self, &_docPicAssociationKey)
as? String ?? ""
}
set(newValue) {
objc_setAssociatedObject(self, &_docPicAssociationKey,
newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
}