How to execute once when module loads? - swift

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."

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

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

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.

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.

What is a factory class method in Swift?

I'm trying to build an App which required me to install the Couchbase-lite pod. When I tried to initialize a class, it said it was NS_UNAVAILABLE and it told me to use the factory class methods instead. How do I go about this in a general way in using the 'Factory class methods'?
Say for example I did this:
class Polyline: CBLModel {
init() { // the error starts here that says init is unavailable
/* code here */
}
Factory method is a class function that creates an instance of your class.
Couchbase documentation says that you should follow a pattern that bypasses init altogether:
Remember that every model has a one-to-one association with a document in the database. CBLModel has no public initializer methods, and you should not implement any yourself in subclasses.
Creating new polylines should be done as follows:
let poly = Polyline(forNewDocumentInDatabase: database)
If you need custom initialization, it needs to go into a factory method as well:
class Polyline : CBLModel {
#NSManaged var x : Int
#NSManaged var y : Int
class func newPolylineInDatabase(database: CBLDatabase, withX x: Int andY y:Int)
-> Polyline {
let res = Polyline(forNewDocumentInDatabase: database)
res.x = x
res.y = y
return res
}
}

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