I am new to Swift and I'm facing a problem.
My problem is quite simple:
I have a simple class with some object in it (declared in their own file) :
class Outcome : NSObject {
var foo : SomeClass?
var doo : OtherClass?
var roo: AnotherClass?
}
What I want to do is when an object of the class is set, set all the other object to nil, so I used the didSet feature and add a resetData method that is supposed to set all the object to nil, except the one I just set.
The class looks like this :
class Outcome : NSObject {
var foo : SomeClass? {
didSet { self.resetData(exeption: foo!) }
var doo : OtherClass? {
didSet { self.resetData(exeption: doo!) }
}
var roo: AnotherClass? {
didSet { self.resetData(exeption: roo!) }
}
func resetData (exeption: AnyObject) {
var allObjects = NSArray(array: [self.foo ?? NSNull(), self.doo ?? NSNull(), self.roo ?? NSNull()])
for var anObject in (allObjects as NSArray as! [NSObject?]) {
if exeption.isEqual(anObject) == false {
anObject = nil
}
}
}
}
The idea of the resetData method is to set all the objects to nil except the exception (which is the object I just set in my view controller)
The code is working and the instruction anObject = nil is executed, but the problem is that when I set a set a beakpoint I can clearly see that the object is not nil, so this does not do what I want.
I think it is a question of reference, I do not really get it, is it possible to set an object to nil ? Is there a better way to do this ?
As mentioned in the comments, your loop does not modify the class
properties at all, only the anObject loop variable.
If the intention is to define a type which holds either an instance
of SomeClass or an instance of OtherClass or an instance
of AnotherClass then an enum would be a better choice:
enum Outcome {
case foo(SomeClass)
case doo(OtherClass)
case roo(AnotherClass)
}
Usage example:
var outCome = Outcome.foo(SomeClass())
print(outCome) // foo(<SomeClass: 0x1009000b0>)
// ...
outCome = .doo(OtherClass())
print(outCome) // doo(<OtherClass: 0x100d00540>)
Related
I ran into a problem when I was trying to "translate" some Objective-C code to Swift. I define Garage and Car in CoreData. Garage has a relationship to Car called cars. I have a masterviewcontroller to display "Garage" class and detailviewcontroller to display a NSArray of "car" class. Here is my code in Objective-C. I want to let cars = allobjects when it is nil; otherwise just return it.
#property (nonatomic, strong) NSArray* cars;
- (NSArray*) cars {
if (_cars == nil) {
_cars = self.garage.cars.allObjects;
}
return _cars;
}
However, in Swift, it does not have a underscore instance for property, and I cannot let cars == nil since "==" cannot be applied to operands of type [Car]. I tried to use the following code, but it gave me two errors: "attempting to access 'cars' within its own getter" and "cannot assign a value of type '[AnyObject]?' to a value of type '[Car]'"
var garage : Garage?
var cars : [Car] {
if let a = cars {
get {
cars = self.garage?.cars.allObjects
}
}
Any help is appreciated.
UPDATE/////////////////////////////////////////////
Here is the method I used to solve my problem.
private var _cars: [Car]?
var cars: [Car]?
{
get {
if _cars == nil {
_cars = self.garage?.cars.allObjects as? [Car]
}
return _cars
}
set {
_cars = cars
}
}
Thank you for all the help.
I might suggest just having a computed property:
var cars : [Car]? {
return garage?.cars.allObjects
}
And, remember to make cars variable and optional array.
Looks like you need a lazy property:
lazy var cars: [Car]? = self.garage?.cars.allObjects
Yes, you need a lazy var.
Your code will be (Swift 2.3):
lazy var cars: [Car]? = { [unowned self] in
return self.garage?.cars.allObjects
}()
The trick are the { and the [unowned self]
Lazy var in sintax instance the value just one time and keep it, maybe it's what you want.
Maybe you just need a wrapper to get each time the value of self.garage?.cars.allObjects in which case you need a computed var, not a lazy var with a static value
var cars: [Car]? {
get {
return self.garage?.cars.allObjects
}
}
In Swift, you would generally replace properties with variables (var); if a property can be set in you init method and stays unchanged after that, you would use (let).
In your case, you have your own "get" method. In Swift, when you have a getter or setter method, there is no backing variable. So what you do, you create one. Typically as a private variable with a leading underscore.
You should think about how you reset the variable to nil. Having a setter is not a good idea, because you only want to allow setting the variable to nil and nothing else. If it is only set to nil inside the class itself, you can set the variable with underscore to nil. Otherwise you might add a function like "resetCars".
And note that if you have a "get" method, but none of "set", "willSet" and "didSet", you can just write the set code without any getter. So a typical usage would be:
private var _cars: [Car]?
func resetCars () -> Void { _cars = nil } // To allow resetting outside the class
var cars: [Car] {
if _cars == nil {
_cars = cleverlyCalculatedNonNilValue()
}
return _cars
}
class ArcaneCardVC: UIViewController {
var currentCard: ArcaneCardView?
}
class PostVC: ArcaneCardVC {
override var currentCard: PostCard?
// <===== This is what I want to do but cant
}
class ArcaneCardView: UIView {
}
class PostCard: ArcaneCardView {
}
Here is the error I get:
Cannot override mutable property 'currentCard' of type 'ArcaneCardView?' with covariant type 'PostCard?'
The other solution is explicitly doing this in code everytime I use currentCard:
var card = currentCard as! PostCard
When you override a variable, you can't change it's type. Why not? Well, suppose that you are able to do that, then the following scenario would be possible:
var A: PostVC = PostVC() // some initialization
var B: ArcaneCardVC = A // this is a valid state since `PostVC` is a subclass of `ArcaneCardVC`
What should be the type of B.currentCard? Hmm, this is a complicated question. You can answer that its type should be PostCard. Ok, lets add other classes to the party:
class OtherCard: ArcaneCardView {
}
class OtherVC: ArcaneCardVC {
override var currentCard: OtherCard?
}
Considerer now the following code:
var A: ArcaneCardVC = PostVC()
var B: ArcaneCardVC = OtherVC()
A.currentCard = B.currentCard // something will crash here!!!
To avoid this kind of behavior, you can't change the type of a property when you are subclassing.
The correct way to do it is the way you're doing with currentCard as! PostCard.
Another option would be to use a property getter like
// inside PostVC
// Note the camel case on the 'C' makes it a different variable that the super class
var CurrentCard: PostCard {
get { return self.currentCard as! PostCard }
}
Then you'd use self.CurrentCard instead of self.currentCard as! PostCard
I am trying to learn Singleton Class in Playground but dont know how to get its only one instance.Why is this singleton class returning nil while accessing its property?It would be great if someone would explain me why do i need this Static class?
class SingletonC {
var a:String?
class var sharedInstance: SingletonC {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: SingletonC? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = SingletonC()
}
return Static.instance!
}
}
var ab = SingletonC()
ab.a = "fdsfds"
SingletonC.sharedInstance.a //prints nil
UPDATED:
After experimenting sometimes i got the value
SingletonC.sharedInstance.a = "Hello"
SingletonC.sharedInstance.a
But can i obtain this by creating a object of SingletonCfor the first time?What is the way to use Singleton class?
I think what you want is a static property. Instead of var a: String?, use static var a: String?.
With that, all instances have the same value of a.
Call a by SingletonC.a
What your code does is you create an instance of SingletonC and put it in ab. And you set ab's a property to "fdsfds" (Only ab instance has a of value "fdsfds").
The third line, SingletonC.sharedInstance.a creates a new SingletonC instance and put it in Static.instance (creates one time only by using the dispatch_once function). Thus, ab and sharedInstance are different instances of SingletonC.
Answer for your updated question:
dispatch_once(&Static.onceToken) {
let instance = SingletonC()
instance.a = "Your string"
Static.instance = instance
}
As about a singleton class it have only one instances as if you are reserving the value same the way you have to assign it the value
class Demo{
// assign value
SingletonC.sharedInstance.a = "Your value"
//get value
println(SingletonC.sharedInstance.a)
var b = SingletonC.shahredInstance.a
}
or further more if you want a simple code every time you can use it as
class Demo{
let obj = Singleton.sharedInstance
// assign value
obj.a = "Your value"
//get value
println(obj.a)
var b = obj.a
}
Both here works the same
I want a lazily-initialized property whose initializer I can invoke again if I set the property to nil.
If I define my property this way:
lazy var object = { /*init code*/ }()
...and later invoke the property, the initializer is triggered once. However, if I set object to nil later in my program, the initializer is not invoked again. How can I do that in Swift?
I looked into computed properties but they don't actually store values, so whenever I invoke the variable, the computation or initialization always occurs. I want to compute only whenever the property is nil.
The lazy property initializer is responsible of initializing the property the first time it is accessed in read mode. Setting to nil has no effect on the initialization status - it's just a valid value the property stores.
You can mimic a lazy initialization with 3 properties:
a private initializer, implemented as a computed property (or a closure if you prefer)
a private backing property, storing the actual value
a non private property, which is the one you actually use in your code
The code looks like this:
class MyClass {
private var _myPropInitializer: Int {
return 5
}
private var _myProp: Int?
var myProp: Int? {
get {
if self._myProp == nil {
self._myProp = self._myPropInitializer
}
return _myProp!
}
set {
_myProp = newValue
}
}
}
the initializer property returns a computed value for the variable when it needs to be initialized, which is the 5 integer in the above example
myProp is an optional integer (to be able to store a nil):
on set, it will store the new value in the _myProp property
on get, if _myProp is nil, it invokes the initializer, assigning it to _myProp, and it returns its value
If you want to reuse that pattern, it's better to put everything in a class:
class Lazy<T> {
private let _initializer: () -> T
private var _value: T?
var value: T? {
get {
if self._value == nil {
self._value = self._initializer()
}
return self._value
}
set {
self._value = newValue
}
}
required init(initializer: () -> T) {
self._initializer = initializer
}
}
Note: a struct is not usable because setting a property inside a property getter is not allowed, whereas in a class it is.
Then you can use it as follows:
class MyTestClass {
var lazyProp: Lazy<Int>
init() {
self.lazyProp = Lazy( { return 5 } )
}
}
Some tests in playground:
var x = MyTestClass()
x.lazyProp.value // Prints {Some 5}
x.lazyProp.value = nil
x.lazyProp._value // Prints nil
x.lazyProp.value // Prints {Some 5}
The downside is that you have to access to the actual property as x.lazyProp.value and not as x.lazyProp.
Here's a lazy pattern I use when your object can only ever be nil or a computed value. It requires only 2 properties:
var todayPredicate: NSPredicate! {
set {
guard newValue == nil else {return} // could throw here if required
self._todayPredicateLazyBacker = nil
}
get {
guard self._todayPredicateLazyBacker == nil else {return self. _todayPredicateLazyBacker}
// construct your today predicate
let predicate = ...
self._todayPredicateLazyBacker = predicate
return self._todayPredicateLazyBacker
}
}
private var _todayPredicateLazyBacker: NSPredicate?
todayPredicate is constructed only once when it is read for the first time (lazy).
So why would you ever want to set todayPredicate to nil? In this example you are probably observing for the day changing because todayPredicate must always represent today. In your observer code you would simply do this, for example...
self.todayPredicate = nil
self.loadEvents()
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