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.
Related
I have been trying to convert a singleton class to generic. Since swift doesn't support stored property in generic class Singleton could not be implemented. I tried all the possible solutions that I know but nothing works. Other Stackoverflow answers related to this topic doesn't help either. Can someone help me to get on the right path, please? Thanks in advance.
I have added the sample code below.
class SingleTonClass<T: Equatable & RawRepresentable>: NSObject where T.RawValue == String {
private var catlog: CatlogModelClass<T>?
private var catlogArray = [CatlogModelClass<T>]()
**// This stored property Now has to be changed to support Generic**
private static var shared : SingleTonClass = {
return SingleTonClass()
}()
// Accessor for Singleton
static func sharedInstance() -> SingleTonClass {
return shared
}
private override init () {}
}
If you want it to be non-singleton, you need to create a public constructor.
You should pass in the catalog and catalogArray into the constructor and initialize self.catalog and self.catalogArray. You then need to remove the static shared instance of the class, because your new setup would require you to create an instance of it.
Please help me with Swift,
I need singleton with can inheritance.
I can do like this
class A {
var defaultPort: Int
required init() {
self.defaultPort = 404
}
class var defaultClient: A {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: A? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = self.init()
}
return Static.instance!
}
}
but in swift 2.0 we can do like this
static let defaultClient = A() //self.init()
but it creates an instance of the class A any way.
How i can use like this self.init()
static let defaultClient = self.init()
in order to be able to inherit
UPD
best way for now
class A {
class func defaultClient() -> Self {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: A? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = self.init()
}
return instance(Static.instance, asType: self)
}
}
here we need helper as
func instance<T>(instance: Any, asType type: T.Type) -> T {
let reurnValue = instance as! T
return reurnValue
}
because another way cast A to Self not exist, for now.
p.s. crazy swift way!
why i can not do instance as! Self
Your question isn't very clear. You're looking for something like the class constant solution posted in this answer, but which automatically uses "my own class" instead of explicitly creating an instance of a specific class... right?
That is, you want to turn this:
class Singleton {
static let sharedInstance = Singleton()
}
into this:
class Singleton {
static let sharedInstance = SomeMagicThing()
}
class SingletonSubclass {}
where SomeMagicThing automatically creates a Singleton instance when you call Singleton.sharedInstance, and a SingletonSubclass instance when you call SingletonSubclass.sharedInstance. Correct?
Sorry, that can't be done (as of Swift 2.1).
Part of your issue is that static and class mean two different things. The static modifier means that the declaration it modifies is associated only with a specific type declaration. So, the Singleton type owns a pointer to a specific object -- its subclasses don't inherit that pointer. (And if they did, would it point to the same object or a subclass-specific one?)
If you could create a class var or class let, that'd (in theory) give you the kind of dispatch/inheritance you want. But trying that gives you an error (emphasis mine):
class stored properties not yet supported in classes; did you mean static?
So it sounds like this sort of thing might show up someday.
Of course, the other side of the problem is finding a way to dynamically refer to the "current" type responsible for executing some statement. In the context of an instance method, you have self.dynamicType for such things... but there's no equivalent for classes. (Self is a type constraint, not an actual type.) This is a side effect of the type system in Swift being much more strict and static than that of Objective-C (for example, metatypes aren't just a special flavor of otherwise normal objects). File a bug if you'd like to see a change to that effect?
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
}
}
I want to create a static class in swift, is this possible? If so how?
I tried:
static class MyClass
but get the error Declaration cannot be marked 'static'
There's no static class, but you can make one by just adding static methods only.
The problem is that (as of today) classes cannot have static properties, so you have 2 options:
use a struct instead of a class, defining all its methods and properties as static
use the singleton pattern
The second option is in my opinion a better solution, unless you have specific reason for not wanting it.
static means no instance, so I would make it a struct with no initializer:
struct MyStruct {
#available(*, unavailable) private init() {}
static var foo = "foo"
static func doSomething(a: String) -> String {
return a + foo
}
}
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)