Why we should use struct and class function in singleton pattern? - swift

I'm just reading a code from Udacity learning stuff. The teacher makes an instance variable sharedInstance with a struct that wrapped in a class function
Why can we not simply make a static var?
class BugFactory() {
class func sharedInstance() -> BugFactory {
struct Singleton {
static var sharedInstance = BugFactory()
}
return Singleton.sharedInstance
}
}
Why It's not recommended:
class BugFactory() {
static var sharedInstance = BugFactory()
}

Actually it is recommended to use your second code because of the improvements in the versions of swift.One more thing that you should consider is to declare your singleton object using static let and also make the initializer private
class Bar{
private init(){
// initialization
}
static let shared = Bar()
}

You should actually use static let to create sharedInstance/singleton.
Also make sure to have private init() method, so that any other class does not unintentionally creates another instance of the class which is supposed to singleton.
The tutorial you are referencing might be using some older Swift version. If you have comment options there on video make a comment.

Related

What's the difference between a struct with only type functionality, and a class with only type functionality?

For example, consider this class:
class Foo {
private init() {
// Private init, so no instances can be created.
// All methods and properties will by owned by the type.
// So no instances will need to be created,
// as there is no instance functionality.
}
static var count = 0
static func increment() {
Foo.count += 1
}
}
Perhaps it makes no difference whether it's a class or a struct? (assuming inheritance isn't needed).

Singleton closed for modification open to extend

I would like to know how to achieve this:
Assume I have a singleton class as
class Global{
static let shared = Global()
private init(){}
}
I want this class as closed to modification. But open to extend.
I want to achieve result as
Global.shared.var1
When var1 is coming from another class somehow extending Global.
It's a wish. Is it even possible? What is the right way to achieve this.
Found a hack that served my purpose for the time being (suggest me a better way/alternate):
class Students{
static let shared = Students()
private init(){}
var name: [String] = ["Farhan","Hasan","Saba","Fatima"]
}
class Teachers{
static let shared = Teachers()
private init(){}
var name: [String] = ["Mr. Riaz","Ms. Ayesha"]
}
//Base for Singleton, sort of proxy
class Global{
private init(){}
}
//Somewhere else in your project
extension Global{
static let students = Students.shared
}
//Somewhere else in your project
extension Global{
static let teachers = Teachers.shared
}
//Apparently it served the purpose
print(Global.students.name) //prints: ["Farhan", "Hasan", "Saba", "Fatima"]
print(Global.teachers.name) //prints: ["Mr. Riaz", "Ms. Ayesha"]

Singleton? Or is there a better way?

I'm about to build a singleton but I'm not sure if it's the right solution.
I have this problem I have a class that creates a URLSessionTaskDelegate. I would like to use that delegate in another class to get some information from the file upload.
So I was thinking If I could put this plus some other information in to an object like this:
public class UploadQueueCellData
{
let _FileName:String
let _UploadTaskDelegate:URLSessionTaskDelegate
let _ImageData:Data
init(fileName:String,imageData:Data,uploadTaskDelegate:URLSessionTaskDelegate)
{
_FileName = fileName
_ImageData = imageData
_UploadTaskDelegate = uploadTaskDelegate
}
.... etc
}
And then store it in a singleton with a array inside it:
public class ImageUploadQueue
{
private var _queue = [UploadQueueCellData]()
private let imageUploadQueue:ImageUploadQueue? = nil
public func GetImageUploadQueueInstance() -> ImageUploadQueue
{
if imageUploadQueue == nil
{
imageUploadQueue = ImageUploadQueue()
return imageUploadQueue
}
else
{
return imageUploadQueue!
}
}
private init()
{
}
.... etc
}
and then just use that to update information as change happens in another class.
But is there a better way without a singleton ? and am I even doing the singleton correct from a Swift 3 point of view ?
Edit:
so I I see that I'm doing the singleton wrong:
public class ImageUploadQueue
{
private var _queue = [UploadQueueCellData]()
//private let imageUploadQueue:ImageUploadQueue? = nil
static let shared = ImageUploadQueue()
private init()
{
}
Would that be better then? But the question remains is there not a better approach than using the singleton pattern for this? I say better simply because I regard the singleton pattern as a last resort.
I found that my problem arose from the fact that I couldn't get a class I created in one view to display information in another view. my solution to this was the singleton solution above it worked but I felt dirty for using that solution.
I finally found a different way to do this. instead of the singleton I've just created a class containing the Array just like the singleton did above like this:
public class ImageUploadQueue
{
private var _queue = [UploadQueueCellData]()
....//Class specific code
}
and then just use that class as a reference to the Data just like the singleton with the exception that my class above it
had this function that enabled the view to use the information in the queue
public func GetUploadQueue()->ImageUploadQueue
{
return _networkRequester.uploadQueue
}
However that class is created by viewA and I needed the information in ViewB.
so I did this in viewB
var uploader:ImageUpload
{
get
{
return ((self.tabBarController!.viewControllers![0] as? UINavigationController)?.viewControllers[0] as! ViewController).uploader
}
set
{
(self.tabBarController!.viewControllers![0] as! ViewController).uploader = newValue
}
}
And it solved my initial problem with not being able to get information from viewA to ViewB at the same time avoided the use of a singleton.

How to execute once when module loads?

I need to create objects from string names that I am reading from a script. I don't want to use the Objective-C runtime.
In my C++ implementation, each class registered itself with an object factory singleton through a global static variable. When the dll loads, the globals were initialized, and all available classes were registered.
I don't want the object factory to have hard coded pre-knowledge of all possible types.
In Swift, all globals are lazily initialized so my C++ registration strategy doesn't work.
Is there some init API that swift calls once per module load?
If not, does anyone have a good idea for class registration?
public enum DynamicTypeFactoryError : ErrorType {
case ClassNotRegistered
}
public protocol DynamicType {
static var dynamicClassName: String { get }
init()
}
public struct DynamicTypeRegistraion<T: DynamicType> {
public init() {
DynamicTypeFactory.inst.register(T.dynamicClassName, factory: { T() })
}
}
//===========================================================================
// singleton
public class DynamicTypeFactory {
// properties
public static let inst = DynamicTypeFactory()
typealias ClassFactoryType = (Void) -> DynamicType
var registry = [String : ClassFactoryType]()
// methods
public func create(className: String) throws -> DynamicType {
// make sure the class exists
guard let factory = registry[className] else {
throw DynamicTypeFactoryError.ClassNotRegistered
}
return factory()
}
/// This is used to register an object so it can be dynamically created
/// from a string.
public func register(className: String, factory: (Void) -> DynamicType) {
if (registry[className]) != nil {
// TODO - this should be logged
assertionFailure("Class: \(className) is already registered")
} else {
registry[className] = factory
}
}
}
//===========================================================================
// MyObject
public struct MyObject : DynamicType {
// properties
static let registration = DynamicTypeRegistraion<MyObject>()
public static var dynamicClassName = "MyObject"
public init() {
}
}
// Usage
let myObj = try? DynamicTypeFactory.inst.create("MyObject")
Since MyObject's static registration is not initialized, calling create fails because it hasn't been registered yet.
After reviewing the links posted by Martin R, it appears there is no "non-lazy" initialization of statics, and this is by design. So a different approach will be needed for Swift applications. Thanks Martin!
There are two methods in Objective C which are used to load and initialize a class.
+load and +initialize
1. In swift you can use "public override class func initialize()" to put your initialization code, please note that it will be called lazily.
Support for overriding load was removed in Swift 1.2
Here is what docs say about initialize method
"The runtime sends initialize to each class in a program just before the class, or any class that inherits from it, is sent its first message from within the program. The runtime sends the initialize message to classes in a thread-safe manner. Superclasses receive this message before their subclasses."

is it possible to put Class in a variable and access the class's static variables and functions in actionscript3?

Say I had the following class
public class Scene{
public static var title="new scene";
public function Scene(){}
public static function start() { trace("scene started"); }
}
How can you access the Scene class's static variables and functions like this?
var i:Class = Scene;
trace(i.title);
i.start();
I'm trying to figure out how variables assigned with Class work in actionscript.
Any tips would be welcome. Thanks.
Static methods are called from the class:
trace(Scene.title);
Scene.start();
Singleton patterns enable constructor, local reference, and potentially abstraction through interface classes.
Example of Scene as a singleton:
package
{
public class Scene
{
private static var instance:Scene = new Scene();
public static function getInstance():Scene
{
return instance;
}
public var title:String = "new scene";
public function Scene()
{
if (instance)
throw new Error("Scene is a singleton and can only be accessed through Scene.getInstance()");
}
public function start():void
{
trace("scene started.");
}
}
}
Your example implementation would now be:
var i:Scene = Scene.getInstance();
trace(i.title);
i.start();
This is how you can access the dynamic class (Scene) & it's properties / methods :
var myDynamicClasses:Array = [Scene]; // Required
var i:Class = Class(getDefinitionByName("Scene"));
trace(i.title);
i.start.call();
This could throw an error, if the first line is not included. Because, when the compiler notices the class Scene (not the one from adobe's package) is not being used it ignores it. Thus it would be not available for dynamic initialization.
We could force the compiler to include these classes by putting these class names in variables or declare an array as above as a quick hack.
If you have many dynamic classes, you could add a reference to them in this array & each class will be included by the compiler for dynamic initialization.
var i:Class = Scene;
trace(i.title);
Should throw an error because the compiler can no longer assume that i is a scene when it gets to line 2. If you were to coerce the Class object, it should work.
var i:Class = Scene;
trace((Scene(Class).title);