I was reading Shannon's post about shape layers, and one of the resources he links to is this page about fill rules. It was interesting to see the inner workings of them. Go and bookmark calayer.com, as well!
I think that what I do here can't really be called writing; it's more like scribbling, my posts are rather small and rare. But I try to be consistent, even if what I'm going to write about seems to not be of a big deal, because I believe that any info, no matter how big or small, might turn out to be useful to someone.
On the other hand, despite all these facts, I have weeks when I have absolutely no idea what to write about; there's zero inspiration. I can't even imagine how hard it is to consistently write posts of 500, 1000 or more words. Hats off.
Postarea originală poate fi găsită [aici][130]. Unele cuvinte/exprimări traduse ori sună ciudat, ori își pierd din înțeles, așa că pentru acestea, am adăugat între paranteze termenul în varianta netradusă "(așa)". Am încercat pe cât posibil să păstrez tonul autorului.
Aceasta este prezentarea pe care am ținut-o la [App Builders din Elveția][1] pe 25 Aprilie 2016.
Slide-urile sunt disponibile pe [SpeakerDeck][127]. Înregistrarea video a sesiunii este disponibilă pe [YouTube][128]. Articolul a apărut în format fizic în ediția din [iunie 2016 a Hacker Bits][129].
We all hate explicitly typed strings, especially for creating UIImages, but we can surely improve on that. Let's start with an enum, that has a var, to transform its raw value into an UIImage:
enum Asset: String {
case back = "leftArrow"
case logo
case email
case briefcase
// Theoretically, a bang wouldn't be that bad here,
// as we should be 100% sure of what goes in this enum
var image: UIImage? {
return UIImage(named: rawValue)
}
}And why not improve UIImageView too, while we're at it?
extension UIImageView {
convenience init(asset: Asset) {
self.init(image: asset.image)
}
}The following snapping logic is for a collection with cells of the same size and one section, but the logic for more sections shouldn't be much different, or much more complex.
scrollViewWillEndDragging has an inout targetContentOffset parameter, meaning we can read and modify the end position of the scroll. Luckily, we don't need to take into consideration insets, line or item spacing (I've lost a lot of time by including them, then not being able to understand why the correct math produces wrong results):
let cellWidth = collectionView( // 1
collectionView,
layout: collectionView.collectionViewLayout,
sizeForItemAt: IndexPath(item: 0, section: 0)
).widthI personally find this a bit of a mouthful, especially if you have to type it a lot:
if someDate.compare(otherDate) == .OrderedAscending {
// Do stuff
}Update, Oct 10, 2017: These are now built-in for Date. Leaving these here like they are (Swift 2), since the whole post is just about them.
But we can have a few operators to make our lives a bit easier:
func <(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs) == .OrderedAscending
}
func <=(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs < rhs || lhs == rhs
}
func >(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs) == .OrderedDescending
}I think adding everywhere a deinit method, with a print statement inside, is a decent first barrier against retain cycles:
deinit {
print("Object X has been deinitialized.")
}This way, if you expect object x to deinit at some point but it doesn't, you at least know you need to start searching, and where.
Now, for the improved printing, to make this a bit cleaner and easier:
Usually an app has fonts with well defined purposes. So why not let enums make our lives easier, a little bit? First, a couple of them, to define our font families and weights:
struct Font {
private enum Family: String {
case avenirNext
case proximaNova
}
private enum Weight: String {
case regular
case medium
case demiBold
case bold
}
}Then a method to easily create fonts:
Let's say we have a custom UILabel, which in turn has several types; maybe a StatusLabel that can be of type sold out and expired. The label would have several common properties, but each type would have something specific. How can we go about this?
class StatusLabel: UILabel {
enum StatusType {
case soldOut
case expired
}
init(type: StatusType) {
super.init(frame: .zero)
font = UIFont.common
layer.cornerRadius = 4
textAlignment = .center
translatesAutoresizingMaskIntoConstraints = false
}
}We now covered the common parts, and we could go ahead and set the backgroundColor and textColor like this:
Instead of checking if size.width > size.height, we can have three handy CGSize extensions:
extension CGSize {
var isCompact: Bool { return height > width + delta }
var isWide: Bool { return width > height + delta }
var isSquare: Bool { return abs(width - height) < delta }
}For usage within viewWillTransition(to:with:) I don't think the delta will be really needed, but if we want to use these properties for our own custom views, it might come in handy. Modify its value to fit your own needs, of course.