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.
Related
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"]
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.
I have an abstract class in my mind and I can't implement its several features in swift, so I use C++ to deliver my thoughts:
template <class T>
class Swapping {
public:
void swap() { _foregroundIndex = backgroundIndex() }
virtual void cleanup() = 0;
T* foreground() { return _buffer[foregroundIndex()]; }
T* background() { return _buffer[backgroundIndex()]; }
void setForeground(T* foreground) { _buffer[foregroundIndex()] = foreground; }
void setBackground(T* background) { _buffer[backgroundIndex()] = background; }
private:
short foregroundIndex() { return _foregroundIndex; }
short backgroundIndex() { return _foregroundIndex ^ 1; }
short _foregroundIndex = 0;
T* _buffer[2] = {NULL, NULL};
}
The main contradiction is that
The pure virtual method cleanup() requires all subclasses to implement it explicitly (can achieve in swift with protocol)
The instance variable _foregroundIndex has an initial value (cannot achieve using protocol)
The instance variable _foregroundIndex is restricted to be private ( cannot achieve using protocol)
On the other hand, if I use a class instead of protocol, then I can't guarantee cleanup() method is overriden.
One may suggest that put the virtual method in a protocol and the instance variable in a class. That may work but is not a obsession-satisfying one.
P.S. Objective-C is not Swift. Any objc_runtime related workaround is not preferred.
There’s an obvious solution, which I have seen often but will certainly not satisfy you is:
func cleanup() {
fatalError("You must override cleanup()")
}
Then you could try using extensions to extend the protocol with default implementations, but extensions don’t allow stored properties and so you would most likely need some external objects or other magic you certainly also dislike.
As I noted above in the comments, you might need to rethink your design. I don’t know what you really intend to do, but maybe something like this would work out for you:
class Swapper<T> {
private var foregroundIndex = 0
private var backgroundIndex: Int {
return foregroundIndex ^ 1
}
private var buffer: [T?] = [nil, nil]
private let cleanupHandler: () -> ()
init(cleanupHandler: #escaping () -> ()) {
self.cleanupHandler = cleanupHandler
}
func cleanup() {
cleanupHandler()
}
var foreground: T? {
get {
return buffer[foregroundIndex]
}
set {
buffer[foregroundIndex] = newValue
}
}
var background: T? {
get {
return buffer[backgroundIndex]
}
set {
buffer[backgroundIndex] = newValue
}
}
func swap() {
foregroundIndex = backgroundIndex
}
}
This makes more sense to me as this allows any types to be swapped with any clean up handler, without having to subclass the class every time.
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."
I'm playing with the swift language and i have a question on get/set properties. I think that it makes no sense to let the inner variable be public when the value is managed by a computed property. So I think that making this private to the class is a good practise. As I'm still learning maybe some of you could give me other ideas to leave it public.
class aGetSetClass{
private var uppercaseString : String
var upperString : String {
get {
return uppercaseString
}
set (value) {
self.uppercaseString = value.uppercaseString
}
}
init(){
uppercaseString = "initialized".uppercaseString
}
}
var instance3 = aGetSetClass()
println(instance3.upperString) // INITIALIZED
instance3.upperString = "new"
// println(instance3.uppercaseString) // private no access
println(instance3.upperString) // NEW
instance3.upperString = "new123new"
println(instance3.upperString) // NEW123NEW
The only way I could think of public access is either to make it as private set and then use a public set function instead:
public private(set) uppercaseString: String
public func setUpperString(string: String) {
uppercaseString = string.uppercaseString
}
Or make it public and use a didSet which sets itself under a certain condition (very inefficient for long strings):
public uppercaseString: String {
didSet {
if uppercaseString != uppercaseString.uppercaseString {
uppercaseString = uppercaseString.uppercaseString
}
}
}
These implementations use direct public access but your version is in my perspective the better / "swifter" way.