Class initializer in Swift? - ios

In Java I can create a static initializer like:
static { ... }
In Swift I can have:
class MyClass {
class var myVar:Int?
}
Is it possible to create some kind of class/static var initializer in Swift?

If you need a computed property accessible from the class type and you want it to be like a constant value, the best option is static keyword.
Type Property Syntax
“For computed type properties for class types, you can use the class keyword instead to allow subclasses to override the superclass’s implementation.” Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/pt/jEUH0.l
With class keyword a subclass can override the computed value.
Best solution:
class MyClass {
static var myVar: Int {
return 0
}
}

Related

How can I define a variable can will hold the type of a generic protocol in swift?

I want to create a method that takes a type of a class that implements a generic protocol and then hold that value in a variable, so that later I can create instances.
Example with non-generic protocol
protocol Initializable { init() }
class Impl: Initializable { required init(){} }
//Here we will hold the type of a class that implements Initializable
var initializableType: Initializable.Type? = nil
//This method will get the type of a class that implements Initializable and store it to initializableType.
func register<T>(implementation: T.Type) where T : Initializable {
initializableType = implementation.self
}
//Register the type
register(implementation: Impl.self)
//Then create instance
initializableType?.init()
Now how I can to do the same for the following protocol?
protocol GenericInitializable {
associatedtype InitDataType
init(_ with: InitDataType)
}
It seems I can not define a type that will hold the meta type of a generic protocol. The type erasure technique works for instances, and as the name suggest it erases the type information that I need.

How to use a generic class without the type argument in Swift?

I want to encapsulate a generic object in another class without setting the generic type argument. I created a base Animal<T> class and defined other subclasses from it. Example:
public class Animal<T: YummyObject> {
// Code
}
public class Dog: Animal<Bark> {
// Code
}
public class Cat: Animal<Meow> {
// Code
}
and defined an Animal property, without the type argument, in the UITableView extension bellow:
extension UITableView {
private static var animal: Animal!
func addAnimal(animal: Animal) {
UITableView.animal = animal
}
}
but I get the following compile error when doing so:
Reference to generic type Animal requires arguments in <...>.
This seems to work fine in Java. How can I accomplish the same thing in Swift as well?
Swift doesn’t yet support wildcard-style generics like Java does (i.e., Animal<?>). As such, a common pattern is to define a type-erased superclass, protocol (or wrapper) to enable such usage instead. For instance:
public class AnyAnimal {
/* non-generic methods */
}
and then use it as your superclass:
public class Animal<T: YummyObject>: AnyAnimal {
...
}
Finally, use AnyAnimal in your non-generic code instead:
private static var animal: AnyAnimal!
Examples in the Swift Standard Library. For a practical example, see the KeyPath, PartialKeyPath, and AnyKeyPath classes hierarchy. They follow the same pattern I outlined above. The Collections framework provides even further type-erasing examples, but using wrappers instead.

Can subclass inherit type property from its super class? And if yes, how to override it?

code running in xcode
“For computed type properties for class types, you can use the class keyword instead to allow subclasses to override the superclass’s implementation.”
“You can override an inherited instance or type property to provide your own custom getter and setter for that property”
----Apple Swift3
//override static
class A{
var myValue = 0614
static var storedTypeProperty = "Some value"
class var overrideableComputedTypeProperty: Int {
return 1
}
}
class B: A {
storedTypeProperty = "New String"
}
It seems like that B doesn't inherit any type property from A.
So how to override the "inherited type property" as described above in Swift3 book.
The problem you are facing is because you are using a static variable. static variables can not be overwritten, full stop. No point to argue here.
First sentence says, if you have a class (not a struct),like class A {} , you can use the class keyword instead of the static keyword, and override class types. This means, that you can use two keyword for the same purpose, with a major difference, that static can not be overwritten.
class A {
// overridable computed property
class var overridableClassPropery: String {
return "This is class A's overwritten property"
}
// Not overridable `static` computed property
// Error will be shown if you try to override this property in class `B`
static var notOverridableStaticPropery: String {
return "Can not override this property in a subclass"
}
}
The second one says, that you can override a superclasses class property, and provide your own get implementation in a subclass, like the following:
class B: A {
// Class type computed property can be overwritten
override class var overridableClassPropery: String {
return "This is class B's overwritten property"
}
}
EDIT:
notOverridableStaticPropery of class A is being inherited by class B, what means, you can access / call it through class B. BUT you can not override it, it will have the value set in class A always.
print(A.notOverridableStaticPropery) // prints "This is class A's not overridable static property"
print(B.notOverridableStaticPropery) // prints "This is class A's not overridable static property"

Static properties in Swift

I'm trying to convert the following Objective-C code to Swift. In my Objective-C code, there's a static variable and its accessed from a class method.
#implementation SomeClass
static NSMutableArray *_items;
+ (void)someMethod {
[_items removeAll];
}
#end
Since you can't access types declared like this private var items = [AnyObject]() from class functions in Swift, I created a stored property for it like this.
class var items: [AnyObject] {
return [AnyObject]()
}
And I'm trying to call a method on it from a class function like so.
class func someFunction() {
items.removeAll(keepCapacity: false)
}
But I get this error Immutable value of type '[AnyObject]' only has mutating members named 'removeAll'.
Can anyone please tell me what's the cause of this error and how to correct it?
Thank you.
With this code:
class var items: [AnyObject] {
return [AnyObject]()
}
you are not creating a stored property - instead it's a computed property, and the worst part is that every time you access to it, a new instance of [AnyObject] is created, so whatever you add to it, it's lost as soon as its reference goes out of scope.
As for the error, the static computed property returns an immutable copy of the array that you create in its body, so you cannot use any of the array method declared as mutating - and removeAll is one of them. The reason why it is immutable is because you have defined a getter, but not a setter.
Currently Swift classes don't support static properties, but structs do - the workaround I often use is to define an inner struct:
class SomeClass {
struct Static {
static var items = [AnyObject]()
}
}
SomeClass.Static.items.append("test")
If you want to get rid of the Static struct every time you refer to the items property, just define a wrapper computed property:
class var items: [AnyObject] {
get { return Static.items }
set { Static.items = newValue }
}
so that the property can be accessed more simply as:
SomeClass.items.append("test")
Updated to Swift1.2
In Swift1.2[Xcode6.3], you can declare static properties using keyword static, also you can declare static methods using keyword class or static.
class SomeClass {
// use static modifier to declare static properties.
static var items: [AnyObject]!
// use class modifier to declare static methods.
class func classMethod() {
items.removeAll(keepCapacity: false)
}
// use static modifier to declare static methods.
static func staticMethod() {
items.removeAll(keepCapacity: false)
}
}
EDIT:
The difference between static and class modifier is that static is just an alias for "class final",so methods modified with static can not be overridden in subclasses.
Thanks #Maiaux's
Yet the manual for Swift 2 still claims just enumeration ond structures may use static store properities.

"initialize" class method for classes in Swift?

I'm looking for behavior similar to Objective-C's +(void)initialize class method, in that the method is called once when the class is initialized, and never again thereafter.
A simple class init () {} in a class closure would be really sleek! And obviously when we get to use "class vars" instead of "static vars in a struct closure", this will all match really well!
If you have an Objective-C class, it's easiest to just override +initialize. However, make sure subclasses of your class also override +initialize or else your class's +initialize may get called more than once! If you want, you can use dispatch_once() (mentioned below) to safeguard against multiple calls.
class MyView : UIView {
override class func initialize () {
// Do stuff
}
}
If you have a Swift class, the best you can get is dispatch_once() inside the init() statement.
private var once = dispatch_once_t()
class MyObject {
init () {
dispatch_once(&once) {
// Do stuff
}
}
}
This solution differs from +initialize (which is called the first time an Objective-C class is messaged) and thus isn't a true answer to the question. But it works good enough, IMO.
There is no type initializer in Swift.
“Unlike stored instance properties, you must always give stored type properties a default value. This is because the type itself does not have an initializer that can assign a value to a stored type property at initialization time.”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
You could use a type property which default value is a closure. So the code in the closure would be executed when the type property (or class variable) is set.
class FirstClass {
class var someProperty = {
// you can init the class member with anything you like or perform any code
return SomeType
}()
}
But class stored properties not yet supported (tested in Xcode 8).
One answer is to use static, it is the same as class final.
Good link for that is
Setting a Default Property Value with a Closure or Function
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
Code example:
class FirstClass {
static let someProperty = {
() -> [Bool] in
var temporaryBoard = [Bool]()
var isBlack = false
for i in 1...8 {
for j in 1...8 {
temporaryBoard.append(isBlack)
isBlack = !isBlack
}
isBlack = !isBlack
}
print("setting default property value with a closure")
return temporaryBoard
}()
}
print("start")
FirstClass.someProperty
Prints
start
setting default property value with a closure
So it is lazy evaluated.
For #objc classes, class func initialize() definitely works, since +initialize is implemented by the Objective-C runtime. But for "native" Swift classes, you'll have to see the other answers.
You can use stored type properties instead of initialize method.
class SomeClass: {
private static let initializer: Void = {
//some initialization
}()
}
But since stored types properties are actually lazily initialized on their first access, you will need refer them somewhere. You can do this with ordinary stored property:
class SomeClass: {
private static let initializer: Void = {
//some initialization
}()
private let initializer: Void = SomeClass.initializer
}
#aleclarson nailed it, but as of recent Swift 4 you cannot directly override initialize. You still can achieve it with Objective-C and categories for classes inheriting from NSObject with a class / static swiftyInitialize method, which gets invoked from Objective-C in MyClass.m, which you include in compile sources alongside MyClass.swift:
# MyView.swift
import Foundation
public class MyView: UIView
{
#objc public static func swiftyInitialize() {
Swift.print("Rock 'n' roll!")
}
}
# MyView.m
#import "MyProject-Swift.h"
#implementation MyView (private)
+ (void)initialize { [self swiftyInitialize]; }
#end
If your class cannot inherit from NSObject and using +load instead of +initialize is a suitable fit, you can do something like this:
# MyClass.swift
import Foundation
public class MyClass
{
public static func load() {
Swift.print("Rock 'n' roll!")
}
}
public class MyClassObjC: NSObject
{
#objc public static func swiftyLoad() {
MyClass.load()
}
}
# MyClass.m
#import "MyProject-Swift.h"
#implementation MyClassObjC (private)
+ (void)load { [self swiftyLoad]; }
#end
There are couple of gotchas, especially when using this approach in static libraries, check out the complete post on Medium for details! ✌️
I can't find any valid use case to have something like +[initialize] in Swift. Maybe this explains way it does not exist
Why do we need +[initialize] in ObjC?
To initialize some global variable
static NSArray *array;
+ (void)initialize {
array = #[1,2,3];
}
which in Swift
struct Foo {
static let array = [1,2,3]
}
To do some hack
+ (void)initialize {
swizzle_methodImplementation()
}
which is not supported by Swift (I can't figure out how to do it for pure Swift class/struct/enum)

Resources