I know that in swift we can use Extensions to add new methods to existing classes.
But what about if i want to add a variable?
extension UIViewController {
var myVar = "xyz"
}
It gives like :
Extensions must not contain stored properties
We can't add the stored properties to extensions directly but we can have the computed variables.
extension UIViewController {
var myVar: String {
return "xyz"
}
}
Extensions in Swift can:
Add computed instance properties and computed type properties
...
For more please visit
https://docs.swift.org/swift-book/LanguageGuide/Extensions.html
You can only add computed properties to extensions as follows...
extension UIViewController {
var someProperty = "xyz" : String {
return "xyz"
}
}
If you wish to use it the way you are defining it, you might need to subclass your UIViewController
class YourCustomViewController: UIViewController {
var someProperty: String = "xyz"
}
you can only use computed variables:
for example we have the type Int in swift, and we want it extend in a way that swift generates a random number from 0 to our number :
extension Int
{
var arc4random : Int{
if self > 0
{return Int(arc4random_uniform(UInt32(UInt(self))))}
else if self < 0
{return -Int(arc4random_uniform(UInt32(UInt(abs(self)))))}
else
{return 0}
}
}
and usage :
myArray.count.arc4random
here my array.count is an Int , and arc4random is the computed variable we have defined in our extension, u cant store a value in it
You can try ( This is a readOnly computed property )
extension UIViewController {
var someProperty : String {
return "xyz"
}
}
Related
Am stuck in a situation where I have a let variable declared & initialized in base class. I would need to pass a different enum in one of my other classes extending this base class.
So, I tried creating a class function in base class so that I can override and return a different enum type. But is there any way that I can access the extended class from base class ?
Created a sample code below to help explain:
class A {
var string: String {
get {
// Is it possible to refer to the class type dynamically here ?
// So that it would call B's printMessage
return A.printMessage("Hello")
}
}
class func printMessage(message: String) -> String {
return "You shall not pass !"
}
}
class B: A {
override class func printMessage(message:String) -> String {
return message + "World !"
}
}
let obj = B()
print(obj.string)
make it like this:
var string: String {
get {
// Is it possible to refer to the class type dynamically here ?
// So that it would call B's printMessage
return self.dynamicType.printMessage("Hello")
}
}
This question already has answers here:
Overriding superclass property with different type in Swift
(15 answers)
Closed 6 years ago.
I have A class. And its subclass B. I need to override type of its property. Also that will be ok to to change a protocol. How can I do that?
class A {
var property: String (or SomeProtocolA)
}
class B: A {
var property: Int (or SomeProtocolB)
}
Maybe its possible to add support second protocol for property in subclass?
You can't, and this is indicative of poor design.
Suppose Class A had a function:
class A {
var property: String (or SomeProtocolA)
func getMyString() -> String {
return property
}
}
and now class B inherits it, whilst "overwriting" property:
class B : A {
var property: Int(or SomeProtocolB)
// func getMyString() -> String { //inherited from superclass
// return property //type error, expected String, returning Int
//}
}
You can do this, but in VERY limited situations. The only ways that this is allowed is under the following circumstances:
The property must be get only.
The overriding type must be a subclass of the original type (so no struct, protocol or enum).
Here is an example overriding with strings:
class A {
var property: NSString {
return ""
}
}
class B: A {
override var property: NSMutableString {
return NSMutableString(string: "")
}
}
Why declare readonly property in protocol if we can set value trough class or struct? I can not understand usage of this.
In "The Swift Programming Book" version 2.0
“If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it is valid for the property to be also settable if this is useful for your own code.”
So that it's not settable from outside the class/struct. Imagine your API returned some instance of a protocol that has a get and set property (in your protocol), then anyone getting this instance would be able to set the value!
Also get and set properties can't be constants:
protocol RWProt {
var value : Int { get set }
}
// Error: Type 'Value' does not conform to protocol 'RWProt'
struct Value : RWProt {
let value = 0
}
This however works:
protocol Read {
var value : Int { get }
}
struct Value : Read {
var value = 0
mutating func change() {
value++
}
}
The protocol only needs the value to be gettable, so get protocols properties are not get only but rather get or set
Okay, here is another example:
import Foundation
public protocol ExternalInterface {
var value : Int { get }
}
private struct PrivateStuff : ExternalInterface {
var value = 0
mutating func doSomePrivateChangingStuff() {
value = Int(arc4random())
}
}
public func getInterfaceToPrivateStuff() -> ExternalInterface {
var stuff = PrivateStuff()
stuff.doSomePrivateChangingStuff()
return stuff
}
// In another file:
let interfaceToSomethingICantChange = getInterfaceToPrivateStuff()
// error: cannot assign to property: 'value' is a get-only property
interfaceToSomethingICantChange.value = 0
I have been trying to declare a static dictionary within a "struct". However, I could not achieve this. It gives me "Type 'BagItem' does not conform to protocol 'Hashable'" .
And my code is here:
struct StaticBag {
static var bag: Dictionary<BagItem, Array<BagItem>> = Dictionary<BagItem, Array<BagItem>>()
// static func AddMainItem(item: BagItem)
// {
// self.bag[item] = Array<BagItem>()
// }
}
'BagItem' in the code is my another global class.
What is the right and best way to declare this variable ?
Thank you for your answers
Best regards
As it says, the issue is that your custom BagItem type doesn't conform to the Hashable protocol. Dictionary keys need to be hashable, since dictionaries use the hash values to look up entries quickly.
What does BagItem look like? Is there a unique property that is already hashable? If so, you can add Hashable conformance by adding a hashValue property and implementing the == operator:
class BagItem : Hashable {
var uniqueID: Int = 0
var hashValue: Int { return uniqueID.hashValue }
}
func ==(lhs: BagItem, rhs: BagItem) -> Bool {
return lhs.uniqueID == rhs.uniqueID
}
How do you instantiate a type dynamically based upon a lookup value in a dictionary in Swift?
Hopefully this is useful to others. It took some research to figure this out. The goal is to avoid the anti-pattern of giant if or switch statements to create each object type from a value.
class NamedItem : CustomStringConvertible {
let name : String
required init() {
self.name = "Base"
}
init(name : String) {
self.name = name
}
var description : String { // implement Printable
return name
}
}
class File : NamedItem {
required init() {
super.init(name: "File")
}
}
class Folder : NamedItem {
required init() {
super.init(name: "Folder")
}
}
// using self to instantiate.
let y = Folder.self
"\(y.init())"
let z = File.self
"\(z.init())"
// now put it in a dictionary.
enum NamedItemType {
case folder
case file
}
var typeMap : [NamedItemType : NamedItem.Type] = [.folder : Folder.self,
.file : File.self]
let p = typeMap[.folder]
"\(p!.init())"
let q = typeMap[.file]
"\(q!.init())"
Interesting aspects:
use of "required" for initializers
use of .Type to get the type for the dictionary value.
use of .self to get the "class" that can be instantiated
use of () to instantiate the dynamic object.
use of Printable protocol to get implicit string values.
how to init using a non parameterized init and get the values from subclass initialization.
Updated to Swift 3.0 syntax