class MyManager {
private static var __once: () = {
Static.instance = MyManager()
}()
class var sharedInstance: MyManager {
struct Static {
static var onceToken: Int = 0
static var instance: MyManager? = nil
}
_ = MyManager.__once
return Static.instance!
}
fileprivate init() {
print("MyManager init");
}
....... etc
calling it
aManager = MyManager.sharedInstance
results in
MyManager init fatal error: unexpectedly found nil while unwrapping an Optional value
_ = MyManager.__once isn't calling your __once function, it's assigning it to nothing. You forgot the ():
MyManager.__once()
That's the whole purpose of requiring _ =, to make you realize you're dealing with the function itself, not a function call.
Regardless, this is an unnecessarily convoluted and messy implmentation of a singleton. All you need is:
class MyManager {
static let instance = MyManager()
}
It's lazy, thread-safe, and sane.
For me this is the best way, make init private.
// MARK: - Singleton
final class Singleton {
// Can't init is singleton
private init() { }
// MARK: Shared Instance
static let shared = Singleton()
// MARK: Local Variable
var emptyStringArray : [String] = []
}
Related
I'm working on UI testing code for iOS app recently,
my UI testing code is using swift, but the project itself has some objective-c code, and I create a singleton object for launch arguments settings, which also written by swift, so I adding the #objcMembers tag to the class.
but while running the UI testing code, it seems not capable to reach the variables and functions, the singleton itself also not exists?
something I missed?
import UIKit
#if DEBUG
#objcMembers
class EALaunchArugments: NSObject {
static let sharedInstance = EALaunchArugments()
// key for property
static private let UITestingKey = "-UITesting"
var isUITesting: Bool {
let value = self.getLaunchArgumentValue(key: EALaunchArugments.UITestingKey)
return Bool(value ?? "") ?? false
}
private func getLaunchArgumentValue(key: String) -> String? {
let arguments = ProcessInfo.processInfo.arguments
let indexOfKey = arguments.firstIndex(of: key)
guard let index = indexOfKey, index != NSNotFound else {
return nil
}
guard index + 1 >= arguments.count else {
return nil
}
return arguments[index + 1]
}
func setAllLaunchArgumentsSettingsForUITesting() {
// some work
}
}
#endif
I have a simple boolean variable in a function on which a set an observer to check when it changes:
var userValid: Bool{
didSet{
let valid=userValid ? "valid" : "not valid"
print("uservalid changed to \(valid)")
}
}
I set it to false in the init and then to true in the program: the initialiser is called twice once for the class and once for the subclass but I am alway checking the value in the class. So I am seeing the variable is set to true in the observer, but then when I check it in another function I find it at false without the observer to be ever called again.
As it comes out the problem seems to stem from the fact I initialise two times the class: once as a singleton and the other one with:
init?(coder aDecoder: NSCoder)
Of course I initialise the singleton with:
public class func sharedMapDelegate() -> MapDelegate {
struct Static {
static let instance : MapDelegate = MapDelegate()
}
return Static.instance
}
How may I return the value generated from the initWithCoder instead of creating a new one?
I think I have fixed it by changing the singleton to:
public class func sharedMapDelegate() -> MapDelegate {
struct Static {
static var instance : MapDelegate {
if let me = Factory.sharedFactory().mapHandler {
return me
} else {
Factory.sharedFactory().mapHandler=MapDelegate()
return Factory.sharedFactory().mapHandler
}
}
}
return Static.instance
}
In Apple's Using Swift with Cocoa and Objective-C document (updated for Swift 3) they give the following example of the Singleton pattern:
class Singleton {
static let sharedInstance: Singleton = {
let instance = Singleton()
// setup code
return instance
}()
}
Let's imagine that this singleton needs to manage a variable array of Strings. How/where would I declare that property and ensure it gets initialized properly to an empty [String] array?
For me this is the best way, make init private. Swift 3 \ 4 \ 5 syntax
// MARK: - Singleton
final class Singleton {
// Can't init is singleton
private init() { }
// MARK: Shared Instance
static let shared = Singleton()
// MARK: Local Variable
var emptyStringArray = [String]()
}
You can initialize an empty array like this.
class Singleton {
//MARK: Shared Instance
static let sharedInstance : Singleton = {
let instance = Singleton(array: [])
return instance
}()
//MARK: Local Variable
var emptyStringArray : [String]
//MARK: Init
init( array : [String]) {
emptyStringArray = array
}
}
Or if you prefer a different approach, this one will do fine.
class Singleton {
//MARK: Shared Instance
static let sharedInstance : Singleton = {
let instance = Singleton()
return instance
}()
//MARK: Local Variable
var emptyStringArray : [String]? = nil
//MARK: Init
convenience init() {
self.init(array : [])
}
//MARK: Init Array
init( array : [String]) {
emptyStringArray = array
}
}
As per the apple's documentation: In Swift, you can simply use a static type property, which is guaranteed to be lazily initialized only once, even when accessed across multiple threads simultaneously.
class Singleton {
// MARK: - Shared
static let shared = Singleton()
}
With initialization method:
class Singleton {
// MARK: - Shared
static let shared = Singleton()
// MARK: - Initializer
private init() {
}
}
Any initialisation would be done in an init method. No difference here between a singleton and a non-singleton.
From what I understand, the RACSubject equivalent of ReactiveCocoa 4 is the Observer class.
I want to have a signal and an observer linked together so that the signal sends events applying a map operation to the events sent to the observer.
In Obj-C it looks like this:
// ViewModel.h
#interface ViewModel
#property (readonly) RACSubject *someAction; //expects e.g. int values
#property (readonly) RACSignal *someSignal; //sends e.g. string values
#end
// ViewModel.m
//redeclaring the signal and action as readwrite
#implementation
- (id)init {
_someAction = [RACSubject subject];
_someSignal = [_someAction map:^id(NSNumber *index) {
return "Some string based on index passed in";
}];
}
#end
Now when someone pushes a value onto someAction, the someSignal will fire an event containing a derived value.
How do I achieve the same effect in Swift?
What I've been able to do so far is something like this:
public class ViewModel: NSObject {
public let (internalSignal, someAction) = Signal<Int, NoError>.pipe()
public var someSignal: Signal<String, NoError> {
get {
return self.internalSignal.map({ [unowned self](index: Int) -> String in
return "Some string value based on \(self.someArray[index])"
})
}
}
public let someArray = [1, 2, 3, 4, 5]
}
Which looks like a bad solution because
internalSignal should be private but needs to be declared public in order to match it to Signal's pipe
someSignal is computed every time it's needed therefore, even though the same signal could be reused over and over. Also can't be declared as a let constant.
You could initialize the members in init just like ObjC...
public class ViewModel: NSObject {
private let internalSignal: Signal<Int, NoError>
public let someAction: Observer<Int, NoError>
public let someSignal: Signal<String, NoError>
override init() {
(internalSignal, someAction) = Signal<Int, NoError>.pipe()
someSignal = internalSignal.map { index in
"Some string value based on \(index)"
}
super.init()
}
}
For someSignal you could also use lazy initialization, which allows the member to refer to self:
public class ViewModel: NSObject {
private let internalSignal: Signal<Int, NoError>
public let someAction: Observer<Int, NoError>
public private(set) lazy var someSignal: Signal<String, NoError> =
self.internalSignal.map { [unowned self] index in
"Some string value based on \(self.someArray[index])"
}
override init() {
(internalSignal, someAction) = Signal<Int, NoError>.pipe()
super.init()
}
}
Unlike the first piece of code, the lazy-var is initialized only before someSignal is used, not at the ViewModel's initialization.
Also, since it is a var, Swift allows you use mutate its value (there is no such thing as lazy let). We can restrict the permission using private(set), but this won't prevent you accidentally write self.someSignal = ... somewhere.
Alternatively, you could make someSignal an implicitly unwrapped optional and initialize manually:
public class ViewModel: NSObject {
private let internalSignal: Signal<Int, NoError>
public let someAction: Observer<Int, NoError>
public private(set) var someSignal: Signal<String, NoError>!
override init() {
(internalSignal, someAction) = Signal<Int, NoError>.pipe()
super.init()
someSignal = internalSignal.map { [unowned self] index in
"Some string value based on \(self.someArray[index])"
}
}
}
I'm looking for the equivalent of the following Obj-C code in Swift:
- newInstanceOf:(id)classRef {
return [classRef new];
}
and then to use it:
id instance = [whatever newInstanceOf:NSArray.class]
[instance isKindOfClass:NSArray.class] == YES
I have tried using a Swift template:
func newSomething<T>(classRef:T.Type) -> T {
return classRef()
}
I get the error: error: 'T' cannot be constructed because it has no accessible initializers
You could create a protocol to act as a type constraint for objects initializable by a void-argument initializer, and thereafter extend your types of choice to this protocol.
protocol SimplyInitializable {
init()
}
extension Int : SimplyInitializable { }
extension Double : SimplyInitializable { }
extension String : SimplyInitializable { }
struct MyStruct {
var myInt : Int
init() {
myInt = 0
}
}
extension MyStruct : SimplyInitializable { }
func newSomething<T: SimplyInitializable>(classRef: T.Type) -> T {
return classRef.init()
}
/* Examples */
var a = newSomething(Int)
var b = newSomething(Double)
var c = newSomething("".dynamicType)
var d = newSomething(MyStruct)
var e = newSomething(a.dynamicType)
print(a.dynamicType) // Int
print(b.dynamicType) // Double
print(c.dynamicType) // String
print(d.dynamicType) // MyStruct
print(e.dynamicType) // Int
Actually in Swift, not all classes are guaranteed to have an init() initializer. It can work with NSObject classes though because NSObject does have that requirement.
func newInstanceOf<T:NSObject>(aClass:T.Type) -> NSObject
{ return aClass.init() }
let string = newInstanceOf(NSString) // ""
let date = newInstanceOf(NSDate) // 2016-01-15 05:27:29 +0000