This question already has answers here:
How to initialize properties that depend on each other
(4 answers)
Closed 8 years ago.
I created a class in Swift like below, but it gives error:
'ApiUrls.Type' does not have a member named 'webUrl'
Here is my code:
import UIKit
class ApiUrls {
let webUrl:NSString = "192.168.0.106:8888"
var getKey:NSString = webUrl + NSString("dev/sys/getkey") // here comes the error ApiUrls.Type' does not have a member named 'webUrl
}
What's wrong in it?
You cannot initialize an instance property with the value of another property, because self is not available until all instance properties have been initialized.
Even moving the properties initialization in an initializer doesn't work, because getKey relies on webUrl, so getKey cannot be initialized until itself is initialized.
I see that webUrl is a constant, so maybe it's a good idea to make it a static property - classes don't support statics as of yet, so the best way is to use a private struct:
class ApiUrls {
private struct Static {
static let webUrl: String = "192.168.0.106:8888"
}
var getKey: String = Static.webUrl + "dev/sys/getkey"
}
Also, unless you have a good reason, it's better to use swift strings and not NSString.
As far as I know, you cannot initialise variables like that in the class definition.
Try declaring your variables as
let webUrl:NSString = "192.168.0.106:8888"
var getKey:NSString = ""
and add this in viewDidLoad
getKey = webUrl + NSString("dev/sys/getkey")
Related
This question already has answers here:
How to initialize properties that depend on each other
(4 answers)
Closed 7 months ago.
Part of my Code which is inside the class fetchData()
#Published var deviceNmae : String = ""
#Published var deviceID : String = ""
init(){
self.deviceID = "t1199"
}
let urlString = "https://io.adafruit.com/\(deviceID)/"
error i am getting is
Cannot use instance member 'deviceID' within property initializer; property initializers run before 'self' is available
How can i solve this ? i looked into similar questions in stackOverflow but nothing seems to be working can someOne guide me with this
Two options:
Use a lazy var:
lazy var urlString = "https://io.adafruit.com/\(deviceID)/"
Use a computed property
var urlString: String { "https://io.adafruit.com/\(deviceID)/" }
There are some posts for how to write code for static constant and static variable in Swift. But it is not clear when to use static constant and static variable rather than constant and variable. Can someone explain?
When you define a static var/let into a class (or struct), that information will be shared among all the instances (or values).
Sharing information
class Animal {
static var nums = 0
init() {
Animal.nums += 1
}
}
let dog = Animal()
Animal.nums // 1
let cat = Animal()
Animal.nums // 2
As you can see here, I created 2 separate instances of Animal but both do share the same static variable nums.
Singleton
Often a static constant is used to adopt the Singleton pattern. In this case we want no more than 1 instance of a class to be allocated.
To do that we save the reference to the shared instance inside a constant and we do hide the initializer.
class Singleton {
static let sharedInstance = Singleton()
private init() { }
func doSomething() { }
}
Now when we need the Singleton instance we write
Singleton.sharedInstance.doSomething()
Singleton.sharedInstance.doSomething()
Singleton.sharedInstance.doSomething()
This approach does allow us to use always the same instance, even in different points of the app.
There are some posts for how to write code for static constant and static variable in Swift. But it is not clear when to use static constant and static variable rather than constant and variable. Can someone explain?
When you define a static var/let into a class (or struct), that value will be shared among all the instances (or values).
static variables/class are variables can be accessed without need of creation of any instance/object.
class Human {
static let numberOfEyes = 2 //human have only 2 eyes
static var eyeDefect = false //whether human have side-effect or not. he can have defect later so its variable
//other variables and functions
}
//you can access numberOfEyes like below no object of Human is created
print(Human.numberOfEyes)
print(Human.eyeDefect)
//Object of Human
let john = Human()
I think you know difference between constant and variable. In short, constant is that whose value never changes; numberOfEyes in above example and variable is that whose value changes; eyeDefect in above example.
static constant or variables are placed in memory(RAM) separate then the Objects. i.e. numberOfEyes have different memory space allocated than John object, its not inside John.
now, when to use static constants/variables:
When you use singleton design pattern: static let sharedInstance = APIManager()
class APIManager(){
static let sharedInstance = APIManager()
//Your other variables/functions here below
}
//Use it as to get singleton instance of APIManager from anywhere in your application
let instanceOfAPIManager = APIManager.sharedInstance
When you need value of anything that is globally the same without need to make instance of the class under which it is defined like numberOfEyes in human class.
Use of static variables/constants are not much recommended because of memory issues because once it's instantiated/assigned, it remains in memory until your application gets removed from the memory. I have found till now the best place to use static variables/constants is only while making singleton pattern and sometimes pointers for other normal variables and constants don't use static because: memory issue, it will be difficult to run unit testing in your code with static variables/constants. Not recommended to use as like in Human class also. instead use them as just constant or variables and access them by making instance.
class Human {
let numberOfEyes = 2 //human have only 2 eyes
var eyeDefect = false //whether human have side-effect or not. he can have defect later so its variable
//other variables and functions
}
//you can access numberOfEyes like below if you need just those values.
print(Human().numberOfEyes)
print(Human().eyeDefect)
Static constants and variables do belong to the class itself, not to a particular instance. A class can also have static methods that can be called without creating an instance of a class.
So when you have a class MyClass with a static var x, you can also access it through MyClass.x directly. x will be shared among all instances of a class
This is more of an important comment:
class Person {
static var name = "Static John" // a property of Person 'type'
var name = "Alex" // a property of Person 'instance'
var nonStaticName = "Peter"
static var staticName = "Sara"
static func statFunc() {
let x = Person.name // Static John
let y = name // Static John or Alex?! Static John!!!!
let r = staticName // Sara
let k = nonStaticName // ERROR: instance member 'nonStaticName' cannot be used on type 'Person'
// The compiler is like: I'm referring to the `nonStaticName` property of which instance?! There is no instance! Sorry can't do!
}
func nonStaticFunc() {
let x = Person.name // Static John
let y = name // Static John or Alex?! Alex!!! Because we're in a instance scope...
let k = nonStaticName // Obviously works
let r = staticName // ERROR: static member 'staticName' cannot be used on instance of type 'Person'. Person.staticName will work
}
}
Interesting observations:
First:
static var name = "Static John" // a property of Person 'type'
var name = "Alex" // a property of Person 'instance'
creates no conflicts.
Second:
You can't ever use instance variables inside static variables. You can use static variables inside instance functions if you refer to it by prefixing it with the type ie do Person.name, whereas
static variables can be accessed inside static functions with or without prefixing the type ie Person.staticName or staticName both work.
I had this error several times now and I resorted to different workarounds, but I'm really curious why it happens. Basic scenario is following:
class SomeClass {
var coreDataStuff = CoreDataStuff!
lazy var somethingElse = SomethingElse(coreDataStuff: coreDataStuff)
}
So I understand I can not use self before class is fully initialised, but in this case I'm using self property coreDataStuff to initialise a lazy var which will not happen until my instance is ready.
Anybody could explain me why I'm getting
Instance member can not be used on type error?
Try that :
class SomeClass {
var coreDataStuff = CoreDataStuff!
lazy var somethingElse: SomethingElse = SomethingElse(coreDataStuff: self.coreDataStuff)
}
It is important to precise the type of your lazy var and to add self. to the argument you pass
There are two requirements that are easily overlooked with lazy variables in Swift, and, unfortunately, the warnings are cryptic and don't explain how to fix it.
Lazy Variable Requirements
Use self.: When referring to instance members, you must use self.. (E.g. self.radius.)
If you forget to use self., you'll get this error:
Instance member 'myVariable' cannot be used on type 'MyType'
Specify the type: The type cannot be inferred, it must be explicitly written. (E.g. : Float.)
If you forget to specify the type, you'll get this error:
Use of unresolved identifier 'self'
Example
struct Circle {
let radius: Float
lazy var diameter: Float = self.radius * 2 // Good
//lazy var diameter = radius * 2 // Bad (Compile error)
}
I am currently reading The Swift Programming Language, and when it reaches to Type Properties, it says “You define type properties for value types with the static keyword, and type properties for class types with the class keyword. ” But what static means and what id does? I just can't get a clue.
Type properties are properties that are associated with the type, meaning you don't need an actual instance of the class or struct to access them. static is used to define such a property in structs. For example:
struct Constants {
static let pi = 3.1416
static let e = 2.71828
let phi = 1.618
}
println(Constants.pi) // prints "3.1416"
println(Constants.e) // prints "2.71828"
println(Constants.phi) // Error: 'Constants.Type' does not have a member named 'phi'
println(Constants().phi) // prints "1.618" when we create an instance
The following code prints nil, despite ListCell is a valid class.
var lCellClass : AnyClass! = NSClassFromString("ListCell");
println(lCellClass);
The docs are saying that method returns
The class object named by aClassName, or nil if no class by that name is currently loaded. If aClassName is nil, returns nil.
I also tried to get NSClassFromString() of current viewcontroller which is LOADED but still get nil
What can be the problem ?
Update:
Even trying to do this NSClassFromString("Array") I still get nil
The NSClassFromString function does work for (pure and Objective-C-derived) swift classes, but only if you use the fully qualified name.
For example, in a module called MyApp with a pure swift class called Person:
let personClass: AnyClass? = NSClassFromString("MyApp.Person")
The module name is defined by the "Product Module Name" (PRODUCT_MODULE_NAME) build setting, typically the same name as your target (with some normalization applied to e.g. remove spaces).
This is atypical, but if the class you're loading is in the current module and you don't know the module name at compile-time e.g. because the code is compiled as part of multiple targets, you can look up the bundle name dynamically, which usually corresponds to the module name:
let moduleName = Bundle.main.infoDictionary!["CFBundleName"] as! String
let personClass: AnyClass? = NSClassFromString(moduleName + "." + "Person")
I don't recommend this however unless you really don't know at compile-time.
See Using Swift Class Names with Objective-C APIs in Using Swift With Cocoa and Objective-C for more information.
It's also possible to specify a name for the symbol in Objective-C which omits the namespace in objective C by using the #objc annotation. If you prefer to use the name without the module, just use the same class name:
#objc(Foobar)
class Foobar{
}
NSClassFromString("Foobar") will return the class Foobar.
This may be problem that your class have not extend from NSObject. As by default swift does not have superclass.
For example:
Just using UIViewController as an example,
func getVc(from stringName: String) -> UIViewController? {
let appName = Bundle.main.infoDictionary!["CFBundleName"] as! String
guard let vc = NSClassFromString(appName + "." + stringName) as? UIViewController.Type else {
return nil
}
return vc.init()
}
If your App name contains "-" or number, just replace them with "_"