How do you initialize a singleton with properties - Swift? - swift

I am trying to create a singleton that gets initialized with properties.. I know you can initialize by default:
class ApiSharedHelper {
var someValue:String
static let sharedInstance : ApiSharedHelper = {
let instance = ApiSharedHelper()
return instance
}()
ApiSharedHelper.sharedInstance...
And I would just call that sharedInstance and it'll call the constructor. How would I call that shared instance where I'm passing a value for that someValue string to initialize a value?

class APIManager {
class var shared :APIManager {
struct Singleton {
static let instance = APIManager()
}
return Singleton.instance
}
func login(username: String, password: String, success:#escaping (LoginModel?)->()) { ... }
You can call it by :
APIManager.shared.login(username: txtUsername.text ?? "", password: txtPassword.text ?? "") { (response) in
print(response ?? "")
}

you can try this
class ApiSharedHelper {
var someValue:String
static let sharedInstance = ApiSharedHelper()
private init(){
}
}
ApiSharedHelper.sharedInstance...

Related

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)
}
}
}

Is class func possible to return class itself?

Is class func possible to return class itself? And what does the currentUser function use for?Thanks
class FUser: FObject {
class func currentUser() -> FUser {
if let dictionary = UserDefaults.standard.object(forKey: "CurrentUser") as? [String: Any] {
return FUser(path: "User", dictionary: dictionary)
}
return FUser(path: "User")
}
class FObject: NSObject {
init(path: String, subpath: String?) {
super.init()
pathX = path
subpathX = subpath
}
convenience init(path: String) {
self.init(path: path, subpath: nil)
}
}
If you mean singleton object, then this is the way to do it:
class ClassA {
static let shared = ClassA()
private init() {
// Init
}
}
Since init is private, there will only be one instance.
First possible option is that you want to create static factory method. Yes, you can do this. Just return new instance of FUser object
class FUser: FObject {
private override init() {...} // then make your init `private`
class func currentUser() -> FUser {
return FUser()
}
}
Or maybe you're looking for singleton, static instance of the class
class FUser: FObject {
static var current = FUser()
}
then you can use it like this
FUser.current

Unable to create Singleton

i want to make contact book to i made a class of contact.
there is no compile error but when i run the init i do not get to the "init"pass stage.
what can be the problem ?
here is my code:
import UIKit
public class contact {
var originalNumber: String = ""
var e164Number: String = ""
var contactImage: String = ""
var name: String = ""
init (originalNumber: String, name: String) {
self.originalNumber = originalNumber
self.name = name
}
}
then in my contactDataClass i made:
import UIKit
import AddressBook // imports the framework
class contactsDataClass {
var adbk : ABAddressBook!
var localContacts = [contact]()
init() {
print("get to init")
contactsDataClass.sharedInstance.localContacts.append(contact(originalNumber: "0525222022", name: "try appent"))
print("init pass")
}
struct Static {
static var onceToken : dispatch_once_t = 0
static var instance : contactsDataClass? = nil
}
class var sharedInstance : contactsDataClass {
dispatch_once(&Static.onceToken){
Static.instance = contactsDataClass()
}
return Static.instance!
}
}
You have created infinite recursion
Infact this block
class var sharedInstance : contactsDataClass {
dispatch_once(&Static.onceToken){
Static.instance = contactsDataClass()
}
return Static.instance!
}
calls this
init() {
print("get to init")
contactsDataClass.sharedInstance.localContacts.append(contact(originalNumber: "0525222022", name: "try appent"))
print("init pass")
}
which again calls the first block...
Let's clean up your code
public class Contact {
var originalNumber: String
var e164Number = ""
var contactImage = ""
var name: String
init (originalNumber: String, name: String) {
self.originalNumber = originalNumber
self.name = name
}
}
class ContactManager {
static let sharedInstance = ContactManager()
private init() {}
var adbk : ABAddressBook! // this is dangerous...
var contacts = [Contact]()
}
As you can see defining a Singleton class in Swift is much easier than in Objective-C.
You just need to hide the default initializer and create the static constant sharedInstance as shown above.
Usage
ContactManager.sharedInstance.contacts.append(Contact(originalNumber: "0525222022", name: "Test name"))
print(ContactManager.sharedInstance.contacts[0].name) // "Test name"

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
}
}

Singleton in Swift

I've been trying to implement a singleton to be used as a cache for photos which I uploaded to my iOS app from the web. I've attached three variants in the code below. I tried to get variant 2 working but it is causing a compiler error which I do not understand and would like to get help on what am I doing wrong. Variant 1 does the caching but I do not like the use of a global variable. Variant 3 does not do the actual caching and I believe it is because I am getting a copy in the assignment to var ic = ...., is that correct?
Any feedback and insight will be greatly appreciated.
Thanks,
Zvi
import UIKit
private var imageCache: [String: UIImage?] = [String : UIImage?]()
class ImageCache {
class var imageCache: [String : UIImage?] {
struct Static {
static var instance: [String : UIImage?]?
static var token: dispatch_once_t = 0
}
dispatch_once(&Static.token) {
Static.instance = [String : UIImage?]()
}
return Static.instance!
}
}
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = UIImage(data: NSData(contentsOfURL: NSURL(string: "http://images.apple.com/v/iphone-5s/gallery/a/images/download/photo_1.jpg")!)!)
//variant 1 - this code is working
imageCache["photo_1"] = imageView.image
NSLog(imageCache["photo_1"] == nil ? "no good" : "cached")
//variant 2 - causing a compiler error on next line: '#lvalue $T7' is not identical to '(String, UIImage?)'
//ImageCache.imageCache["photo_1"] = imageView.image
//NSLog(ImageCache.imageCache["photo_1"] == nil ? "no good" : "cached")
//variant 3 - not doing the caching
//var ic = ImageCache.imageCache
//ic["photo_1)"] = imageView.image
//NSLog(ImageCache.imageCache["photo_1"] == nil ? "no good" : "cached")
}
}
The standard singleton pattern is:
final class Manager {
static let shared = Manager()
private init() { ... }
func foo() { ... }
}
And you'd use it like so:
Manager.shared.foo()
Credit to appzYourLife for pointing out that one should declare it final to make sure it's not accidentally subclassed as well as the use of the private access modifier for the initializer, to ensure you don't accidentally instantiate another instance. See https://stackoverflow.com/a/38793747/1271826.
So, returning to your image cache question, you would use this singleton pattern:
final class ImageCache {
static let shared = ImageCache()
/// Private image cache.
private var cache = [String: UIImage]()
// Note, this is `private` to avoid subclassing this; singletons shouldn't be subclassed.
private init() { }
/// Subscript operator to retrieve and update cache
subscript(key: String) -> UIImage? {
get {
return cache[key]
}
set (newValue) {
cache[key] = newValue
}
}
}
Then you can:
ImageCache.shared["photo1"] = image
let image2 = ImageCache.shared["photo2"])
Or
let cache = ImageCache.shared
cache["photo1"] = image
let image2 = cache["photo2"]
Having shown a simplistic singleton cache implementation above, we should note that you probably want to (a) make it thread safe by using NSCache; and (b) respond to memory pressure. So, the actual implementation is something like the following in Swift 3:
final class ImageCache: NSCache<AnyObject, UIImage> {
static let shared = ImageCache()
/// Observer for `UIApplicationDidReceiveMemoryWarningNotification`.
private var memoryWarningObserver: NSObjectProtocol!
/// Note, this is `private` to avoid subclassing this; singletons shouldn't be subclassed.
///
/// Add observer to purge cache upon memory pressure.
private override init() {
super.init()
memoryWarningObserver = NotificationCenter.default.addObserver(forName: .UIApplicationDidReceiveMemoryWarning, object: nil, queue: nil) { [weak self] notification in
self?.removeAllObjects()
}
}
/// The singleton will never be deallocated, but as a matter of defensive programming (in case this is
/// later refactored to not be a singleton), let's remove the observer if deallocated.
deinit {
NotificationCenter.default.removeObserver(memoryWarningObserver)
}
/// Subscript operation to retrieve and update
subscript(key: String) -> UIImage? {
get {
return object(forKey: key as AnyObject)
}
set (newValue) {
if let object = newValue {
setObject(object, forKey: key as AnyObject)
} else {
removeObject(forKey: key as AnyObject)
}
}
}
}
And you'd use it as follows:
ImageCache.shared["foo"] = image
And
let image = ImageCache.shared["foo"]
For Swift 2.3 example, see previous revision of this answer.
Swift 3:
class SomeClass
{
static let sharedInstance = SomeClass()
fileprivate override init() {
//This prevents others from using the default '()' initializer
super.init()
}
func sayHello()
{
print("Hello!")
}
}
Invoke some Method:
SomeClass.sharedInstance.sayHello() //--> "Hello"
Invoke some Method by creating a new class instance (fails):
SomeClass().sayHello() //--> 'SomeClass' cannot be constructed it has no accessible initailizers
Swift-5
To create a singleton class:
import UIKit
final class SharedData: NSObject {
static let sharedInstance = SharedData()
private override init() { }
func methodName() { }
}
To access
let sharedClass = SharedClass.sharedInstance
OR
SharedClass.sharedInstance.methodName()
Following are the two different approaches to create your singleton class in swift 2.0
Approach 1) This approach is Objective C implementation over swift.
import UIKit
class SomeManager: NSObject {
class var sharedInstance : SomeManager {
struct managerStruct {
static var onceToken : dispatch_once_t = 0
static var sharedObject : SomeManager? = nil
}
dispatch_once(&managerStruct.onceToken) { () -> Void in
managerStruct.sharedObject = SomeManager()
}
return managerStruct.sharedObject!
}
func someMethod(){
print("Some method call")
}
}
Approach 2) One line Singleton, Don't forget to implement the Private init (restrict usage of only singleton)
import UIKit
class SomeManager: NSObject {
static let sharedInstance = SomeManager()
private override init() {
}
func someMethod(){
print("Some method call")
}
}
Call the Singleton method like :
SomeManager.sharedInstance.someMethod()