Today we'll continue looking at initialization in Swift with Designated Initializers. Let's get started.
Swift's initialization system is made up of what are essentially a set of rules. We'll step through them here. Let's start with a class.
The first rule of Designated Initializers is that we need one. All classes must define (or inherit) at least one.
Ok, we've added one designated and one convenience initializer. Not too shabby. Now, let's use this base class.
Uh oh, what's going on here? Turns out it's the next rule. We're writing the designated initializer for Peakachew. Designated initializers must call a designated initializer from their immediate superclass, not a convenience one like we tried to do here.
Well, we've fixed our first problem but we've hit the next rule. Designated initializers have to initialize all stored properties on their class before calling super.
Lastly, designated initializers must call their parent class's initializer before assigning a value to any properties they've inherited from it.
With that, we're done. We're now following all the rules:
Way back in Bite #1 (zomg!) we talked about initializing View Controllers in Swift. Swift'sinitfunctions are still a source of confusion for many newcomers. Today we'll look at a couple cases where Swiftsynthesizesinits for us.
Structs
Swift offers free "memberwise"initializers for Structs. This means that if we define a Struct, and opt not to define any initializers, one will be synthesized for us, under the hood, using the properties we've given to the Struct. If we add our own though, we lose the synthesized init, and become responsible for defining 100% for the Struct'sinits.
Classes can synthesize a default initfunction for us. Only one that accepts 0 parameters, though. We'll get this if we define a class, while assigning default values to all its properties:
classSpaceship{vartopSpeed=1000varcurrentSpeed=0}
letship=Spaceship()
There's plenty to cover about init'ing things in Swift. We'll take a look in future Bites. Oh, and happy 200thBite !
It happenstothebest of us. We're going along, composing some UIViews in our app. We're styling them, configuring them, we can't wait to try them out. That's when we see it. A big, empty, unescapable void of nothingness right where our views should be! π±
Today we'll look at some tips to solve a case of missingUIViews.
First, we should arm ourselves with tools to help inspect what's going on. Xcode's own View Debugger is a great place to start, and Reveal.app is a fantastic third-party solution.
Whether it's one of these tools, or simply writing some in-depth logging functions, our first step should be to look at both our view hierarchy and its layout for anything funky.
We can use private functions like recursiveDescription to print out a handy tree-view of our views to Xcode'sConsole.
Most of these debugging sessions stop here, as the problem often involves a view not being in the correct place in the hierarchy, or Auto Layout has gone and done something wacky with our views' locations.
If we're still stuck though, here are some sanity checks we can perform:
Are any viewshidden?
How about transparent? (0 alpha)
Is it masked via a maskLayer?
Does it have a CGRectZeroframe?
Is the key UIWindow a weird size or in a weird place?
Try making each view a specificuglycolor (the static .XColor() functions on UIColor work wonders here).
Is another view covering it up?
Is .clipsToBounds enabled and a strange frame/bounds is causing the view to be clipped?
If all else fails, comment out everything, and add it back one bit at a time until something fails.
Most Swift developers are familiar with how great Swift is at integrating with Objective-C, but what about C itself? Today we'll look at how we can interact with C variables and pointers in Swift. Let's dive in.
First we create a regular Int value in Swift. Nothing special. Then, we'll pass it in to the withUnsafePointerfunction, along with a closure. Inside, we'll be passed in an UnsafePointer version of our original Int. We'll use the unsafeBitCastfunction to convert it into to a void pointer. Finally, we'll pass it in the C function. Whew!
Swift's compiler is smart enough to take note of this nesting whenever ambiguity arises. This means we can use types nested inside multiple "container" types without any issues.
Even-lazier Lazy Definitions
We covered the lazy keyword in Bite #179. It turns out, we can be even lazier, and omit the extra closure altogether. (Still works the same).
lazyvarbackgroundView=SpecialBackgroundView()
Variadic Parameters
Objective-C supported these as well, but they were a bit of pain to work with there. In Swift, we simply add an ellipsis (...) to our function's definition, and we receive the arguments as a strongly-typed Swift** array**.
Today we'll continueourlookat interesting Swift features. Let's begin.
Type Matching with βisβ
Try as we might, sometimes still we end up with an AnyObject or Any reference in our Swift code. We can ask if it is a given type or subtype using Swift's powerful pattern matching:
This technique has a few different applications, but one good example is capturing a value from a switchstatement inline:
enumTheme{caseDay,Night,Dusk,Dawnfuncapply(){// ...letbackgroundColor:UIColor={switchself{caseDay:returnUIColor.whiteColor()caseNight:returnUIColor.darkGrayColor()}}()// ... set backgroundColor on all UI elements}}
Today we'll look at acouplemore tips for working in Swift. This time, we'll focus on Swift properties. Let's dive in.
Property Observers
In Objective-C, we'd likely use Key-Value Observing to "know" when the value of a property on one of our objects changes.
KVO still works great in Swift. In many cases, we might be able to get away with Swift's (much cleaner) property observers:
structSpaceship{letname:StringvarcurrentSpeed:Int=0{willSet{print("About to change speed to \(newValue)")}didSet{ifcurrentSpeed>oldValue{print("Increased speed to \(currentSpeed)")}elseifcurrentSpeed<oldValue{print("Decreased speed to \(currentSpeed)")}}}}
Lazy Properties
"Lazy" initialization is a great way to put off expensive work until some later time in our code. Back in Objective-C, if we wanted to "lazily" initialize a property, we might go override it's getter, and check if a private instance variable is nil or not, then populate it if it's not, then return it. Whew!
In Swift, we can forget all of this and accomplish the exact same with a simple new keyword:
lazyvarcouchPotatoes=[String]()
We can also use this technique to lazily init our UI elements, neat!
Today we'll continue our look at interesting Swift features. Let's begin.
Multiple/Chained Optional Unwrapping
This is great when we've got multiple optionals to unwrap. We can even use unwrapped references from earlier in the statement in later parts of the statement. Neat!
ifletURL=NSURL(string:someURL),letdata=NSData(contentsOfURL:URL),letship=Spaceship(data:data){// use 'ship'}
Multiple Initialization
We can initialize multiple references in one statement (and one line). This works for when using both let and var:
We can simplify Array (and Dictionary) initstatements like this:
letspaceships:[Spaceship]=[]
To this:
letspaceships=[Spaceship]()
Semicolons: Gone but not forgotten!
Removing the need for trailing semicolons was one of Swift's most welcome features. However, they actually are present in Swift, and can serve a useful purpose. They'll let us write multiple statements on one line. This works great (for example) in guardstatements:
Today we'll look at a fewmore interesting Swift tips and tricks. Let's get started.
Multiple Switch Cases
We'll start with a simple one. We can simplify messy switch statements by combining the similar cases. This is similar to how we can use multiple case statements in other languages, but a bit less wordy:
In Bite #159, we started looking at some syntactic shortcuts in Swift. Today we'll continue by looking at a few (perhaps) lesser-known Swift tricks, and their effects. Let's get started.
@autoclosure
This attribute can help save space when writing simple closures:
Now, the compiler will infer the curly braces {} around our statement:
cache("spaceships",cacheIf:ships.count>0)
private(set)
structSpaceship{private(set)varname="Untitled"}
With the private(set) declaration, we're telling the compiler this property has the default access-level of internal for reads, but writes can only happen in the source file where it's declared.
For frameworks, we can configure both the getter/setter explicitly:
When optimizing performance-critical code, dynamic dispatch can be our enemy.
If our class's properties and functions can be overridden by subclasses, we're going to pay the performance cost of an indirect call or access every time we use one of those functions or properties.
We can easily prevent this by declaring a property or functionfinal.
This way, any attempts to override it will result in a compile-time error. We can also declare a classfinal, which applies the final keyword to all the class's functions and properties.