I have written a helper struct for saving and loading stuff to NSUserDefaults.
import UIKit
struct Database {
static let defaults = NSUserDefaults.standardUserDefaults()
static var myVariable: AnyObject?
static func save() {
defaults.setObject(myVariable, forKey: "myVariable")
}
static func load() {
if let myVariable = defaults.objectForKey("myVariable") {
self.myVariable = myVariable
}
}
static func clear() {
defaults.removeObjectForKey("myVariable")
}
}
Now I can simply use Database.load() to load myVariable from NSUSerDefaults.
However, the same is achievable with this code:
struct Database2 {
static var sharedInstance = Database()
let defaults = NSUserDefaults.standardUserDefaults()
var myVariable: AnyObject?
func save() {
defaults.setObject(myVariable, forKey: "myVariable")
}
func load() {
if let myVariable = defaults.objectForKey("myVariable") {
self.myVariable = myVariable
}
}
func clear() {
defaults.removeObjectForKey("myVariable")
}
}
Now I would use Database2.sharedInstance.load().
Which one is seen as a better practice and why? What's the use of a sharedInstance, if I can do everything I want with the static declaration?
A shared instance is recommendable, at least for the following reasons:
class methods make unit testing harder
you need class instances for dependency injection
if later on you decide that a non-singleton is more suitable - e.g. you decide to have two persistence storages for "myVariable", then you're stuck
and not lastly, class members live in the global space, and we should avoid using globals
The real question you should ask, is if you really need a singleton (with or without a shared instance) for your problem. If the only reason to have a singleton is ease-of-access, then you don't really need a singleton.
P.S. There is a very good article on objc.io about singletons, and although it was written for Objective-C, many concepts from there apply in Swift too.
// with singleton pattern, there exist only one copy of the object
// sigleton pattern can be applied for reference type only
// let st1 = Singleton(); let st2 = Sigleton(); st1 === st2
// in your example, S is value type. All instances of S share only type properties, here only i
struct S {
static var i: Int = 100
var j: Int
func foo() {
//print(i) // error: static member 'i' cannot be used on instance of type 'S'
print(S.i)
}
init(_ j: Int) {
self.j = j
}
}
var s1 = S(1)
var s2 = S(2)
//s1.i // error: static member 'i' cannot be used on instance of type 'S'
S.i // 100
s1.foo() // 100
s1.j // 1
s2.foo() // 100
s2.j // 2
S.i = 200
s1.foo() // 200
s2.foo() // 200
by the way, this (your) approach can be very useful and could be preferred in some situations.
Related
In swift 4.2 I am facing the problem while handling the two array objects, When I am removing objects from another array, the values are removed from the all the objects.
1) Below is my closure
func GetChatBotData(completion: #escaping (_ result: ChatV_1_Model) -> Void) {
var ChatBotData : ChatV_1_Model! = nil
ApiHelper.sharedSession.postLoacl("http://localhost:3000/posts/", postData: NSDictionary(), methodtype: Constant.API.httpGet) { (isError, data, errorDescription) in
DispatchQueue.main.async(execute: {
if isError == false {
ChatBotData = ChatV_1_Model.init(fromDictionary: data!)
completion(ChatBotData)
}
else {
//completion("Error to get result" as AnyObject)
completion(ChatBotData)
}
})
}
}
Now In my controller
var PKComponents = [Chatbot_V_1_DataModel]()
var ChatMessages = [Chatbot_V_1_DataModel]()
override func viewDidLoad() {
super.viewDidLoad()
GetChatBotData() {(result: ChatbotV_1_Model!) in
print("Call Plans: \(result!)")
self.PKComponents = result.data
self.ChatMessages = result.data
self.ChatMessages[0].component.removeAll()
}
In Viewdidload I am removing objects from self.ChatMessages array but it removes from all the objects like, PKComponents and result.data as well.
Note: I have seen the reference of the result is same as PKComponents and Chatmessages.
How to resolve this?
Here's the simplified example, where I can reproduce your problem:
class Component {
}
class SomeData {
var components: [Component]
init(components : [Component]) {
self.components = components
}
}
class Result {
var data: [SomeData]
init(data: [SomeData]) {
self.data = data
}
}
let someData = SomeData(components: [Component()])
let result = Result(data: [someData])
//problem begins here
let pkCompent = result.data
var chatMsgs = result.data
print(pkCompent[0].components.count)
chatMsgs[0].components.removeAll()
print(pkCompent[0].components.count)
Inorder to avoid the reference issue, convert SomeData to struct
struct SomeData {
var components: [Component]
init(components : [Component]) {
self.components = components
}
}
You have 2 suggestions.
1- Deep copy .
2- Use struct instead of class since its value type.
Incase of deep copy this is a simple example,
when you assign something to new instance use this way.
// Deep copy
var foo = Foo()
var otherFoo = Foo(foo)
rather than this.
var fee = foo // shallow copy still the same referance
Note: this is handled by swift you don't have to add any inits to the class.
component is what you are removing it from and not the Array to
be precise.
While arrays implementation in swift is using a Struct which is a
value type and not a Object type, what your array is holding, i.e
Object of Chatbot_V_1_DataModel might as well be a class thus, the
elements held in your array are references to object of type
Chatbot_V_1_DataModel.
the way you can work around this is by having Chatbot_V_1_DataModel
defined as a struct thus, a value type OR by making a deep copy of
you array and then using that copy in you closure as you modify it.
I am talking about something on these lines:
var copie = arr.map{$0.mutableCopy()}
better yet:
var PKComponents = [Chatbot_V_1_DataModel]()
var ChatMessages = [Chatbot_V_1_DataModel]()
override func viewDidLoad() {
super.viewDidLoad()
var copie = arr.map{$0.mutableCopy()} // use this copy now elsewhere!!!
GetChatBotData() {(result: ChatbotV_1_Model!) in
print("Call Plans: \(result!)")
self.PKComponents = result.data
self.ChatMessages = result.data
self.ChatMessages[0].component.removeAll()
}
This is the problem of deep copying. Either you write a complete initializer that copies everything and create a new object and use that instead of just assignment. Or use struct instead of class. But as a quick fix you can explicitly only copy the component array like this:
self.PKCOMPONENTS = results.data
self.PKCOMPONENTS.components = Array(results.data.components)
In the book Swift Programming Language 3.0, it says that we can't use extension to add stored property.
I tried it out with instance stored variable and Xcode displayed an error as expected.
But when I tried with static stored variable, everything compiled just fine.
Is there something that I'm missing or doing wrong?
class MyClass {}
extension MyClass {
static var one: Int {
return 1
}
static var two = 2 //compiled just fine
}
let myVariable = MyClass()
MyClass.two
You can't put stored properties in instances of an extension, you can cheat a little though and get the same effect with Objective-C associated objects. Give the following code a try:
private var associationKey: UInt8 = 0
var validationTypes: ValidationTypes {
get {
return objc_getAssociatedObject(self, &associationKey) as? ValidationTypes ?? []
}
set(newValue) {
objc_setAssociatedObject(self, &associationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
Obviously replacing ValidationTypes as appropriate.
I've defined a global struct with static properties with values I use in many of my view controllers, like this:
public struct AppGlobal {
static var currentUser = UserModel()
static let someManager = SomeManager()
// Prevent others from initializing
private init() { }
}
Then in my UIViewController, I can do something like this:
class MyController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
AppGlobal.currentUser.prop1 = "abc123"
AppGlobal.someManager.startUpdating()
}
}
This is obviously very convenient, but smells really bad. I believe dependency injection would come in handy here, but not sure how. Is there a more elegant alternative to creating the AppGlobal singleton properties?
I can't see why you need to access userModel or someManager through a global state (and yes — Singletons are just that).
Why not just set it where you need it?
"Dependency Injection" is a 25-dollar term for a 5-cent concept.
That's not to say that it's a bad term…
[…]
Dependency injection means
giving an object its instance variables. Really. That's it.
– James Shore: Dependency Injection Demystified
Either do it during constructing
class C {
let currentUser: UserModel
let someManager: SomeManager
init(currentUser:UserModel, someManger:SomeManager) {
self.currentUser = currentUser
self.someManager = someManager
}
}
or through properties. If you need to make sure that all properties are set, do something like this:
class MyController: UIViewController {
var currentUser: UserModel? {
didSet{
self.configureIfPossible()
}
}
var someManager: SomeManager?{
didSet{
self.configureIfPossible()
}
}
func configureIfPossible(){
if let currentUser = self.currentUser, someManager = self.someManager {
// configure
}
}
}
In my current project we have the policy that every dependency must be visible and configurable from outside the class.
An example:
class LibrarySegmentViewController: BaseContentViewController {
var userDefaults: NSUserDefaults?
var previousSorting : LibrarySortingOrder = .AZ
var sorting : LibrarySortingOrder {
set{
self.previousSorting = sorting
if let filterMode = self.filterMode {
self.userDefaults?.setInteger(newValue.rawValue, forKey: "\(filterMode)_LibrarySorting")
}
self.setupIfReady()
}
get{
if let filterMode = self.filterMode {
if let s = LibrarySortingOrder(rawValue: self.userDefaults!.integerForKey("\(filterMode)_LibrarySorting")) {
return s
}
}
return .Date
}
}
}
So as you can see, we even use properties to reference NSUserDefaults.standardUserDefaults(). We do this as we can pass in fresh instances during testing, without bigger mocking hassle.
And this is the most importing reason why not to use singletons directly: The dependencies are hidden and might bite you during testing and refactoring. Another example would be an API client singleton that is hidden in the code and performs unwanted networking requests during testing. If it is set from outside of the tested class you can just pass in a mocked networking client that does not perform any requests but returns test data.
So even if you use singletons, you should pass it in as a dependencies.
If this question is about global or not, you should see this thread :
What is so bad about singletons?
But if you want a better design for your implementation of a singleton you can try something like this :
class SingletonExample: NSObject {
static let sharedInstance: SingletonExample()
}
class OtherSingletonExample: NSObject {
static let sharedInstance: OtherSingletonExample()
}
Then you can use SingletonExample.sharedInstance and OtherSingletonExample.sharedInstance anywhere in your code.
The idea is to isolate one singleton from another and access it as a class attribute instead of creating a big global struct for anything.
Please help me with Swift,
I need singleton with can inheritance.
I can do like this
class A {
var defaultPort: Int
required init() {
self.defaultPort = 404
}
class var defaultClient: A {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: A? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = self.init()
}
return Static.instance!
}
}
but in swift 2.0 we can do like this
static let defaultClient = A() //self.init()
but it creates an instance of the class A any way.
How i can use like this self.init()
static let defaultClient = self.init()
in order to be able to inherit
UPD
best way for now
class A {
class func defaultClient() -> Self {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: A? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = self.init()
}
return instance(Static.instance, asType: self)
}
}
here we need helper as
func instance<T>(instance: Any, asType type: T.Type) -> T {
let reurnValue = instance as! T
return reurnValue
}
because another way cast A to Self not exist, for now.
p.s. crazy swift way!
why i can not do instance as! Self
Your question isn't very clear. You're looking for something like the class constant solution posted in this answer, but which automatically uses "my own class" instead of explicitly creating an instance of a specific class... right?
That is, you want to turn this:
class Singleton {
static let sharedInstance = Singleton()
}
into this:
class Singleton {
static let sharedInstance = SomeMagicThing()
}
class SingletonSubclass {}
where SomeMagicThing automatically creates a Singleton instance when you call Singleton.sharedInstance, and a SingletonSubclass instance when you call SingletonSubclass.sharedInstance. Correct?
Sorry, that can't be done (as of Swift 2.1).
Part of your issue is that static and class mean two different things. The static modifier means that the declaration it modifies is associated only with a specific type declaration. So, the Singleton type owns a pointer to a specific object -- its subclasses don't inherit that pointer. (And if they did, would it point to the same object or a subclass-specific one?)
If you could create a class var or class let, that'd (in theory) give you the kind of dispatch/inheritance you want. But trying that gives you an error (emphasis mine):
class stored properties not yet supported in classes; did you mean static?
So it sounds like this sort of thing might show up someday.
Of course, the other side of the problem is finding a way to dynamically refer to the "current" type responsible for executing some statement. In the context of an instance method, you have self.dynamicType for such things... but there's no equivalent for classes. (Self is a type constraint, not an actual type.) This is a side effect of the type system in Swift being much more strict and static than that of Objective-C (for example, metatypes aren't just a special flavor of otherwise normal objects). File a bug if you'd like to see a change to that effect?
I'm trying to implement a cache for my entities with using generics in Swift. Here is my code:
class BaseCache<T>: NSObject {
var allEntities = [T]()
// MARK: - Append
func appendEntities(newEntities: [T]) {
for entity in newEntities {
// Check if allEntities array already contains an entity
var contains = false
for item in allEntities {
// EXC_BAD_ACCESS in isEqual method (see below)
if isEqual(entity, rightEntity: item) {
contains = true
break
}
}
if !contains {
allEntities.append(entity)
}
}
}
func isEqual(leftEntity: T, rightEntity: T) -> Bool {
return false
}
}
Here is a concrete implementation of BaseCache:
class CourierCache<T: AftershipCourier>: BaseCache<T> {
override func isEqual(leftEntity: T, rightEntity: T) -> Bool {
println("\(leftEntity)") // EXC_BAD_ACCESS here
println("\(rightEntity)")
return rightEntity.slug == leftEntity.slug
}
}
Any ideas how to fix that? Thanks!
PS: Note that this question is not relevant to my question
Looks to me like you’ve found a Swift bug. Here’s as simple as I could get it:
class C { }
class Base<T> {
func callCrash(t: T) {
crash(t)
}
func crash(t: T) { }
}
class Sub<T: C>: Base<T> {
override func crash(t: T) {
println(t) // EXC_BAD_ACCESS here
}
}
let sub = Sub<C>()
sub.callCrash(C())
However, you would probably be better served by putting the ability to detect equality into a protocol, and then requiring the objects, rather than the cache, to check for equality.
#rakeshbs’s answer shows how to do this with Equatable, but I would add a couple of caveats that means you may not want to use this approach:
You are checking a property, slug, to test for equality. Equality in Swift implies substitutability – i.e. if two elements are equal via ==, they should be completely equivalent and you should be able to substitute one for the other without anyone noticing. If your ships have properties that can vary even while their slug property is the same, this will not be the case. This can lead to some nasty bugs if you use library functions like contains or sort that rely on this substitutability property. If you are using classes, then you might find the identity operator (===) is a good thing to use to implement the equality operator.
Using equatable and == operators and generics means your comparison function will be statically bound, because operators are not member functions. That means if you hold in your cache different objects in the hierarchy, you won't get dynamic dispatch on your == operator. That is, if you have an AftershipCourier cache and you put FastAftershipCourier classes in it, you could find that the == for AftershipCourier be run between them, instead of a custom == that compares FastAftershipCourier. So if you need dynamic behaviour, make sure to have == call a method on the passed-in argument, that can be overridden by subclasses, rather than just comparing properties directly.
To resolve both these issues, use a protocol of your own devising with a comparison function, have the courier classes implement it, and then call it within your cache code.
P.S. your for loop checking the entity against allEntities can be written as let alreadyContained = contains(allEntities) { entity.comparingFuncYouDecideOn($0) }
You can modify your code like this to achieve what you need. Make use of the Equatable protocol to compare the AfterCourier instances. And use type alias to fix the type inside CourierCache.
class BaseCache<T:Equatable> {
var allEntities :Array<T> = []
func appendEntities(newEntities: [T])
{
for entity in newEntities {
if !contains(allEntities,entity)
{
allEntities.append(entity)
}
}
}
func print()
{
println("Entities : \(allEntities)")
}
}
class CourierCache<S>: BaseCache<AftershipCourier>
{
func testCourier()
{
for courier in allEntities
{
println("Courier Slug: \(courier.slug)")
}
}
}
class AftershipCourier : Equatable,Printable
{
var description: String {
return "Courier Slug: \(slug)"
}
var slug : Int = 0
}
func == (lhs: AftershipCourier, rhs: AftershipCourier) -> Bool
{
return lhs.slug == rhs.slug
}
typealias AfterCourierCache = CourierCache<AftershipCourier>
You can use it like this.
var cache = CourierCache<AftershipCourier>()
var t1 = AftershipCourier()
t1.slug = 1
var t2 = AftershipCourier()
t2.slug = 2
cache.appendEntities([t1])
cache.appendEntities([t2])
cache.print()
cache.testCourier();