Difference between lazy var and let - swift

The following code works, but when I change lazy var to let, it cannot work. I don't know why
lazy var collectionView : UICollectionView = {
let layout = UICollectionViewLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.translatesAutoresizingMaskIntoConstraints = false
cv.backgroundColor = .red
cv.dataSource = self
cv.delegate = self
return cv
}()
the above code works but the following code has errors:

The reason is you use lazy initialization is when the initial value for a property is not known until after the object is initialized.
Also you do need to declare your lazy property using the var keyword, not the let keyword, because constants must always have a value before initialization completes.
Your data is not yet available, that's why is not working
see more here

From documentation:
“You must always declare a lazy property as a variable (with the var keyword), because its initial value might not be retrieved until after instance initialization completes. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.”
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 3.0.1).”
Check out this book on the iBooks Store: https://itun.es/us/jEUH0.l

Related

How to make changes to cocoapods file?

Im using this library for my project - https://github.com/filletofish/CardsLayout
and I tried to change the size of the items in CardsCollectionViewLayout.swift but it does not work.. it still stays the same.
I've also tried to make the changes by forking the library (as desribed by Technerd here: Editing locked files from a CocoaPods framework)
but this does not work either.
Is there any other way of being able to make changes to Pods? Or am I simply doing something wrong in these two previous ways
Edit:
#IBOutlet var collectionView: UICollectionView!
let cardLayout = CardsCollectionViewLayout()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.collectionViewLayout = CardsCollectionViewLayout()
collectionView.dataSource = self
collectionView.delegate = self
collectionView.isPagingEnabled = true
collectionView.showsHorizontalScrollIndicator = false
collectionView.isHidden = true
// cardLayout.itemSize = CGSize(width: 50, height: 50)
collectionView.collectionViewLayout = cardLayout
searchInput.delegate = self
}
You should show the code you wrote to setup your layout. This would make it easier to help you.
Put the code related to collectionView in the didSet block of your collectionView property.
The following code snippet should work for you:
#IBOutlet weak var collectionView: UICollectionView! {
didSet {
let cardLayout = CardsCollectionViewLayout()
cardLayout.itemSize = CGSize(width: 50, height: 50)
collectionView.collectionViewLayout = cardLayout
collectionView.dataSource = self
collectionView.delegate = self
collectionView.isPagingEnabled = true
collectionView.showsHorizontalScrollIndicator = false
collectionView.isHidden = true
}
}
Do never change a file in a pod! Your changes would be lost when updating the pod!
If you ever need to change the behavior of a pod, you have options:
write an extension, if that suits your needs
use subclassing
if you need to make bigger changes, use a fork as you already tried
or you may add the pods source files to your projects code base. But I wouldn't recommend this, because that would make it difficult to profit from updates published to the pods source.

More about the weird behavior of ReferenceWritableKeyPath with an Optional property

(I say "more" in my title because this question is an appendix to my How does Swift ReferenceWritableKeyPath work with an Optional property?.)
In my code, self.iv is an outlet property:
#IBOutlet weak var iv: UIImageView!
Now, will this compile?
let im = UIImage()
let kp = \UIImageView.image
self.iv[keyPath:kp] = im // error
No! We are told that something here must be unwrapped, although it is not entirely obvious what it is:
Value of optional type 'UIImage?' must be unwrapped to a value of type 'UIImage'
But now watch this. Instead of an outlet, I'll just make an image view:
let im = UIImage()
let kp = \UIImageView.image
let iv = UIImageView()
iv[keyPath:kp] = im
That compiles! Why? What semantic / syntactic difference is there between a UIImageView property and a UIImageView local? Is it that the property is an implicitly unwrapped Optional?
To test that idea, let's "propagate" the unwrapping of self.iv explicitly through a local:
let im = UIImage()
let kp = \UIImageView.image
let iv = self.iv!
iv[keyPath:kp] = im
That compiles too! But we must use a separate local; merely unwrapping self.iv directly is not sufficient:
let im = UIImage()
let kp = \UIImageView.image
self.iv![keyPath:kp] = im // error
I am not understanding this at all. It goes against my standard beliefs about what an implicitly unwrapped Optional is, and about how a non-Optional may always be assigned to an Optional wrapping the same type. Something about ReferenceWritableKeyPath seems to work oddly with Optional properties but I can't put my finger on it.
So my question is (sorry, maybe a bit vague): can someone justify all these results and make them seem rational and predictable? What are the rules here?
NOTE: Could be the same as https://bugs.swift.org/browse/SR-11184

Swift 3 - What does this mean?

I converted my project to Swift 3, I am having trouble with the following piece of code, it seems that this ( >>>-) is no longer used in Swift 3. What does >>>- actually mean? and how to use it in Swift 3?
fileprivate func addImageToView(_ view: UIView, image: UIImage?) -> UIImageView? {
guard let image = image else { return nil }
let imageView = Init(UIImageView(image: image)) {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.alpha = 0
}
view.addSubview(imageView)
// add constraints
[NSLayoutAttribute.left, .right, .top, .bottom].forEach { attribute in
(view, imageView) >>>- { $0.attribute = attribute }
}
imageView.layoutIfNeeded()
return imageView
}
The >>>- returns a value. Before Swift 3, the compiler did not warn you if you did not assign the return value of a function or method to anything. Starting in Swift 3, you will get an error if the return value of a function or method (including operators) is unused. A library author can fix this by adding the #discardableResult annotation, but in the meantime you will have to change that line of code to:
let _ = (view, imageView) >>>- { $0.attribute = attribute }
Despite the fact this answer can solve the issue in your side, there still a need to the author of the library to make some changes on his side.
The problem is because swift removed completely the var from function parameters and somehow that change is affecting the param you're receiving in the closure. (It seem a bug to me). You need to figure it out what is the type of the inout param the library is passing to the operator closure, and declare it as inout in your call. let's say that type is Constraint (this might not be the same as the library), then on you:
(view, imageView) >>>- { (i : inout Constraint) in
i.attribute = attribute
}
But again, the author might still need to make some changes in the operator implementation as well.

Swift: how to order instructions in init method of a subclass

I need to implement this class:
class PinImageView: UIImageView {
var lastLocation:CGPoint
var panRecognizer:UIPanGestureRecognizer
init(imageIcon: UIImage?, location:CGPoint) {
self.lastLocation = location
super.init(image: imageIcon)
self.center = location
self.panRecognizer = UIPanGestureRecognizer(target:self, action:"detectPan:")
self.gestureRecognizers = [panRecognizer]
}
}
I think there is a kind of "cyclic" problem because the compiler wants me to initialize panRecognizer before calling super.init(image: imageIcon) but panRecognizer has self as target and we can use self only after calling the super init method.
How can I solve this?
This is a non-optional instance variable
var panRecognizer:UIPanGestureRecognizer
so you have to set a value for it before completing init, and specifically as you see, before calling super.
It doesn't quite need to be like that. Instead, it can be a lazy loading instance variable, so it's created the first time you request it.
Now, when you init you can setup the instance, call super, and then add the gesture recogniser (which will create the gesture in the process).
lazy var panRecognizer : UIPanGestureRecognizer = {
return UIPanGestureRecognizer(target:self, action:"detectPan:")
}()

Property with '= {return}()' or '{return}'?

There are two ways in Swift to declare complicated property:
option1:
var label: UILabel {
var label = UILabel()
label.font = UIFont(name: "ArialRoundedMTBold", size: 18.0)
return label
}
option2:
var label: UILabel = {
var label = UILabel()
label.font = UIFont(name: "ArialRoundedMTBold", size: 18.0)
return label
}()
What's the difference?
option1 declares a computed property, every time you invoke the property, the result would be re-computed. Computed property is often used to replace computing function. And computed property cannot be declared by let
option2 declares a label and customizes it. It is not a computed property which means it can also be declared as a constant. It can be used as a normal property.
The asnwer provided by #Carrl is good, but I would clarify some things with option2:
What you assign to label in option2, it is actually a closure, and the () means at the and of the curly brackets, that you execute the closure right away.
So imagine:
let labelClosure: () -> UILabel = {
var label = UILabel()
label.font = UIFont(name: "ArialRoundedMTBold", size: 18.0)
println("here2")
return label
}
This is the closure that you assign to label in option2, but this is just a function, without executed (see, there are no () at the end of the curly brackets). So if you want to create a label from that, you should write:
labelClosure()
So wrap things up: in option2 you assign the closures return value to label, in opposition to option1, which is a computed property. And what does a computed property mean? Actually, that doesn't store any value, it just computes and returns its value every time you call it.