I'm an android app developer and a beginner in swift. I'm trying to implement a singleton class whose data members are shared throughout the app (like Settings).
Getting this done in android is pretty simple but I'm breaking my head to do it in swift.
Below is the code I've tried ..
public class DataSet
{
public var notificationOnOff: Bool!
public var interval: Int!
public var alert: String!
init()
{
self.notificationOnOff = true
self.interval = 1;
self.alert = nil;
}
init (onOff: Bool) {
self.notificationOnOff = onOff
}
init (time: Int) {
self.interval = time
}
init (stop: String) {
self.alert = stop
}
}
This class implementation couldn't persist the data.
Is this the right way of doing it?
EDIT
For example, when I click switch in Settings view controller, I'm setting notificationOnOff like ..
dataset.notificationOnOff = DataSet(onOff: true) // value is set and able to print it
and using this value in another class like...
if dataset.notificationOnOff
{
// do some stuff
}
So basically, the value is persisting only within the Setting class but not when I switch to other class.
Solved!
I have used the below code to successfully implement this..
var instance: DataSet?
class Dataset {
...
class var sharedInstance: DataSet {
struct Static {
static var instance: DataSet?
static var token: dispatch_once_t = 0
}
dispatch_once(&Static.token) {
Static.instance = DataSet()
}
return Static.instance!
}
}
and in the other classes ..
dataset = Dataset.sharedInstance;
Related
When developing UIKit apps it's quite easy to mock the UserDefaults by defining a protocol and injecting the needed implementation in the UIViewController.
protocol Defaults {
var numberOfHandsPlayed: Int { get set }
}
struct AppDefaults: Defaults {
static let shared = AppDefaults()
private let userDefaults = UserDefaults.standard
struct Keys {
private init() {}
static let numberOfHandsPlayed = "numberOfHandsPlayed"
}
var numberOfHandsPlayed: Int {
get {
userDefaults.integer(forKey: Keys.numberOfHandsPlayed)
}
set(numberOfHandsPlayed) {
userDefaults.setValue(numberOfHandsPlayed, forKey: Keys.numberOfHandsPlayed)
}
}
}
struct MockDefaults: Defaults {
var numberOfHandsPlayed: Int {
get {
// mocking behaviour
}
set(numberOfHandsPlayed) {
// mocking behaviour
}
}
class PracticeViewController: UIViewController {
private var defaults: Defaults?
// defaults can be set to MockDefaults or AppDefaults
}
But now with SwiftUI I can do the following using the #AppStorage property wrapper:
#AppStorage("numberOfHandsPlayed") var numberOfHandsPlayed: Int = 3
Is there a clean solution in SwiftUI to mock this property wrapper and have the same flexibility as in my UIKit example?
The AppStorage allows to specify storage to be used (by default standard UserDefaults), so this feature can be utilised for your purpose.
One of possible approaches is to subclass standard user defaults, and mock it later if/where needed.
class MyUserDefaults: UserDefaults {
// override/add anything needed here
}
struct DemoView: View {
#AppStorage("numberOfHandsPlayed", store: MyUserDefaults()) var numberOfHandsPlayed: Int = 3
// ... other code
I am working on project where I have requirements of using singleton.
while using them I stuck on following code
struct User{
var someUserProperty: String?{
willSet{
print(UserManager.shared.sharedUser ?? "")
}
}
}
class UserManager{
static var shared: UserManager = UserManager()
public var sharedUser: User?
/* Private to make this class singleton */
private init() {
self.sharedUser = User(someUserProperty: "someInitialValue")
}
}
class Managers{
static var userManager = UserManager.shared
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Managers.userManager.sharedUser?.someUserProperty = "someDifferentValue"
}
}
This code throws error in viewDidLoad as it is setting User's property and in that property's observer we are getting same User object.
To solve this, I searched and get solution, which led me to modification in UserManager as follows
class UserManager{
private let concurrentQueue = DispatchQueue(label: "ConcurrentQueue", attributes: .concurrent, target: nil)
static var shared: UserManager = UserManager()
public var sharedUser: User?{
get{
return concurrentQueue.sync {
return self.privateSharedUser
}
}set{
concurrentQueue.async(flags: .barrier){[unowned self] in
self.privateSharedUser = newValue
}
}
}
private var privateSharedUser: User?
/* Private to make this class singleton */
private init() {
self.sharedUser = User(someUserProperty: "someInitialValue")
}
}
I have used dispatch queue to allow read from different places but write in barrier mode so that it will not interrupt read operations. and it worked.
But also following solution works, and that is making me wonder because now I have removed all queuing task and just put get and set.
class UserManager{
private let concurrentQueue = DispatchQueue(label: "ConcurrentQueue", attributes: .concurrent, target: nil)
static var shared: UserManager = UserManager()
public var sharedUser: User?{
get{
return self.privateSharedUser
}set{
self.privateSharedUser = newValue
}
}
private var privateSharedUser: User?
/* Private to make this class singleton */
private init() {
self.sharedUser = User(someUserProperty: "someInitialValue")
}
}
My thinking is that what above code does is that just creating wrapper named sharedUser around actual variable privateUser. So when we set something on sharedUser behind the scenes, it will give you private privateSharedUser whose address is different than sharedUser. Is this the reason ? Or Swift is doing something great behind the scenes ? Please tell me, if any one knows
class ShareData {
class var sharedInstance: ShareData {
struct Static {
static var instance: ShareData?
static var token: dispatch_once_t = 0
}
dispatch_once(&Static.token) {
Static.instance = ShareData()
}
return Static.instance!
}
var someString : String! //Some String
var selectedTheme : AnyObject! //Some Object
var someBoolValue : Bool!
}
This is my singleton design.However , I want to know how I can clear all its data as and when required?
Also can i have more than one singleton Class??
Since you've only got 3 properties on your singleton it would be far easier just to set up a method that nils each property in turn.
Once you start getting in to how to destroy and recreate your singleton, you get in to the realm of do you actually even want a singleton or should you just be using a regular object.
You are creating a Singleton with the syntax available in... 2014
Today there's a better syntax to define a Singleton class
final class SharedData {
static let sharedInstance = SharedData()
private init() { }
var someString: String?
var selectedTheme: AnyObject?
var someBoolValue: Bool?
func clear() {
someString = nil
selectedTheme = nil
someBoolValue = nil
}
}
As you can see I also added the clearData() method you were looking for.
I am trying to write a simple property observer that can be used to see updates to a type - ie a public form of didSet. The basic implementation was easy enough, but I then wanted to use it for both strong (value and reference) types and weak (reference) types. The motivation for the latter was to serve as a lazy caching strategy wherein a shared resource would remain in use until the last observer freed it, whereupon it would query for the value again - generally from NSURLCache, but otherwise a remote server. In short, I wanted a transparent multi-tiered cache.
I have done things like this in C++, where I had stored either a type, or a type wrapped in smart pointer, through the use of a trait with typedef's for Type, StoredType, etc, so I could pass a trait for value types, or a trait for ref-counted pointer types etc.
From my understanding of Swift though, the unowned and weak modifiers are applied to the property and not to the type per se, so you can't for example do something like:
typealias StorageType = weak T
To work around this limitation, I abstracted my generic type T to always use a storage container, where the container could use either the direct type, or a weak reference to what would have to be a class-based AnyClass type. (This effort itself was cludged by the fact that you can't override assignment operators and that conversion functions were abandoned in the early betas)
Frustratingly, I ran into compiler bugs where it just segfaulted.
Given that I can't be the first person to have tried to solve this type of problem, has anybody found a clean way through it? Obviously the segfault is just another compiler bug, but perhaps there is a simpler solution?
For reference, my code (with the segfault inducing code in comments) is:
public class ObserverSubscription : Hashable {
// public (hashable)
public var hashValue: Int { return token }
// private
private init(token:Int, observable:ObservableProtocol) {
self.token = token
self.observable = observable
}
deinit {
self.observable.unsubscribe(self)
}
private var token:Int
private var observable:ObservableProtocol
}
public func ==(lhs: ObserverSubscription, rhs: ObserverSubscription) -> Bool {
return lhs.hashValue == rhs.hashValue
}
public protocol Storage {
typealias T
typealias StorageType
init(t:StorageType)
var element:StorageType { get set }
}
public class Weak<Type:AnyObject> : Storage {
typealias T = Type
typealias StorageType = T?
public required init(t:StorageType) { element = t }
public weak var element:StorageType
}
public class Strong<Type> : Storage{
typealias T = Type
typealias StorageType = T
public required init(t:StorageType) { element = t }
public var element:StorageType
}
public protocol ObservableProtocol {
func unsubscribe(subscription:ObserverSubscription)
}
public class Observable<T, Container:Storage where T == Container.T> : ObservableProtocol {
public typealias StorageType = Container.StorageType
public typealias Subscription = ObserverSubscription
public typealias ChangeNotifier = (Container.StorageType) -> ()
public init(_ t:Container.StorageType) {
self.value = Container(t:t)
}
public init(_ source:Observable<T, Container>) {
self.value = Container(t:source.value.element)
}
public func subscribe(notifier:ChangeNotifier) {
let subscription = Subscription(token: token++, observable: self)
subscriptions[subscription] = notifier
}
public func unsubscribe(subscription:Subscription) {
subscriptions.removeValueForKey(subscription)
}
public func subscription(notifier:(Container.StorageType) -> ()) -> Subscription {
let subscription = Subscription(token: token++, observable: self)
subscriptions[subscription] = notifier
return subscription
}
public func update(t:Container.StorageType) {
self.value.element = t
}
public private(set) var value:Container { didSet {
for n in subscriptions.keys {
self.subscriptions[n]!(self.value.element)
}}}
private var token:Int = 0
private var subscriptions: [Subscription: ChangeNotifier] = [:]
}
public class ValueObserver<T> : Observable<T, Strong<T>> {
override init(_ t:StorageType) {
super.init(t)
}
}
// dare ye segfault?
//public class WeakObserver<T:AnyObject> : Observable<T, Weak<T>> {
// override init(_ t:StorageType) {
// super.init(t)
// }
//}
My actual code was a little more involved, I derived a lazily loading class from the observer, but this too, induced a segfault:
//public class LazyLoader<T:AnyObject> : Observable<T, Weak<T>> {
//
// override init(_ t:StorageType) {
// super.init(t)
// }
//
// // do lazy loading here
//}
I have tested the observer in isolation, outside of the missing-trait work around, but has been many characters since I tested it. My goal at this point is to find a solution that compiles (and which could hopefully be simpler)
Thanks!
I am trying to learn testing with Quick and Nimble and I wrote simple singleton and some tests
Singleton:
public class LocationManager : NSObject {
// Singleton
public class var sharedInstance : LocationManager {
struct Static {
static var instance : LocationManager?
static var token : dispatch_once_t = 0
}
dispatch_once(&Static.token) {
Static.instance = LocationManager()
}
return Static.instance!
}
}
My tests:
class LocationManagerSpec: QuickSpec {
override func spec() {
describe("Location manager") {
let locationManager = LocationManager.sharedInstance
context("initialized") {
it("is not nil") {
expect(locationManager).notTo(beNil())
}
it("is unique") {
let tempLocationManager = LocationManager()
expect(locationManager).notTo(equal(tempLocationManager))
}
it("and shared instances are same") {
let tempLocationManager = LocationManager.sharedInstance
expect(locationManager).to(equal(tempLocationManager))
}
}
}
}
}
How can I test my singleton is thread safe?
To test that your Singleton is Thread safe I've made a little sample. You can find all code in this Github repo basically:
creating a bunch of threads asking for the singleton
storing every returned object inside an Array
checking all objects contained in that array are the same
I've found several problems (using Xcode 6.2 ergo Swift 1.1), even compiler crashes. So following this accepted SO answer I've changed your Singleton implementation avoiding the classic use of GCD. These pointers and unsafe mutable pointers you need to manage, and I was getting crashes because of that
So your Singleton class is now:
import Foundation
public class LocationManager: NSObject {
public class var sharedInstance: LocationManager {
struct Static {
static let instance: LocationManager = LocationManager()
}
return Static.instance
}
}
And to test it, you need to wait until all Threads have finished. As the test runner runs on the MainThread you need to use a expectation
describe("Accesing Location manager from multiple concurrent threads") {
context("When created") {
it("should return always the same object for every of these 500 threads") {
var allSingletons = Array<LocationManager>()
for i in 1...10 {
println("Launching thread \(i)")
dispatch_async(self.globalBackgroundQueue) {
allSingletons.append(LocationManager.sharedInstance)
}
}
expect(self.allSingletonsEqual(inArray: allSingletons, singleton: LocationManager.sharedInstance)).toEventually(beTrue(), timeout: 10)
}
}
}
The important part is this one:
expect(self.allSingletonsEqual(inArray: allSingletons, singleton: LocationManager.sharedInstance)).toEventually(beTrue(), timeout: 10)
Here I'm just calling a function to be sure if every stored object is the same as the passed Singleton, and giving a 10 seconds timeout
The whole Test class:
import Quick
import Nimble
import QuickNimbleExample
class LocationManagerSpec: QuickSpec {
var globalBackgroundQueue: dispatch_queue_t {
return dispatch_get_global_queue(Int(QOS_CLASS_BACKGROUND.value), 0)
}
func allSingletonsEqual(#inArray: Array<LocationManager>, singleton: LocationManager) -> Bool {
for loc in inArray {
if loc != singleton {
return false
}
}
return true
}
override func spec() {
describe("Accesing Location manager from multiple concurrent threads") {
context("When created") {
it("should return always the same object for every of these 500 threads") {
var allSingletons = Array<LocationManager>()
for i in 1...10 {
println("Launching thread \(i)")
dispatch_async(self.globalBackgroundQueue) {
allSingletons.append(LocationManager.sharedInstance)
}
}
expect(self.allSingletonsEqual(inArray: allSingletons, singleton: LocationManager.sharedInstance)).toEventually(beTrue(), timeout: 10)
}
}
}
}
}