So … the day has come, I feel ready to try and take the exam!
I am beginning today, Sunday June 23rd at 10.40am.
Questions, answers and comments
We begin with a series of “Which of these statements are true?” … goodness, I’m trembling for the emotion!
@unknown defaultcase is there to catch cases that get added to an enum after we wrote our code. This stops our app ending up in an unknown state if something changes in the future.
- Visual Formatting Language metrics let us share sizes across views more easily. Metrics let us define shared values that many views can use.
- We can add a simple shadow to a
UIViewby using the shadow properties of its layer. While these shadows are easy to create, it’s helpful to also provide a shadow path to avoid performance problems.
- We must ask permission to read the user’s location. Location data is highly sensitive, so ask for it only if you need it.
inoutparameters must be variables.
- Auto Layout constraints must always be complete and non-conflicting. These are Auto Layouts two rules, and you must always obey them if you want your layouts to work.
- If we make a class and don’t give all its properties default values, we need to create a custom initialiser. Structs benefit from a default memberwise initialiser. Here I made my first mistake, a bit too early for my expectations, as I confused the MapView with the code needed to use it…
- Any part of the mask of an
SKCropNodethat has color is not cropped.It doesn’t matter what the color is, so make it nice and clear. Second mistake in a row, but the question really was not clear at all and I’m starting to get nervous:
The .replace blend mode replaces all the pixel colours in an SKSpriteNode, but leaves transparency intact. This blend mode ignores transparency, which is what makes it so fast.
There is no mention on transparency on the Documentation… “Enumeration Case SKBlendMode.replace The source color replaces the destination color.” … where the hell is mention on transparency? Ok … I kind of hate SpriteKit but these kind of unclear questions are what drives me nuts (and drove me nuts for all this course)… One thing is not knowing the answer, one thing is being screwed by the question not being laid out clearly…
- You can share images, text, and more using activity view controllers. Activity view controllers are capable of handling a variety of data types.
- Activity view controllers can send our data using AirDrop. AirDrop is one of several services that connect to activity view controllers.
Codableis preferred when you have an app that’s written only in Swift.
Codabletakes much less work than
NSCoding, and is safer too.
- The keyboard frame can change many times while our app is running. The user can hide and show the QuickType bar as often as they want.
- We can render a
UIImagedirectly to a Core Graphics canvas. They have a
draw()method that makes this easy.
- Variadic parameters can potentially receive zero values. The array we’re given might be empty.
- Scroll indicator insets control how large the scroll bar is relative to its container. These insets let the user see how much content there is in the scroll view, as well as how far through it they are.
The alternative option was quite interesting and worth mentioning here for the sake of knowledge:
To use Touch ID we must provide a user-facing reason string in our property list. For reasons only known to Apple, the Touch ID reason is provided in code, and the Face ID property is provided in the property list.
SKCropNodeonly crops nodes that are placed inside it. If you want something to be cropped, it must be made a child of a crop node. Every time I see a question on SpriteKit I get a stress shiver in my back… that’s not nice…
SKTexturelets us change the image of an
SKSpriteNodewithout having to delete and recreate it. This makes it helpful for changing how something looks in place – we can just change the property. What did I just say?! The Documentation for this was a bit murky as no mention was given to the deletion and recreation of the
SKSpriteNode. Fortunately, the alternative was quite clearly wrong and helped me in the choice.
- We can make an
SKTexturedirectly from a
UIImage. This allows us to generate textures dynamically. This is done via the
- Lazy properties are a performance optimisation. They are created only when needed, and so might never be created.
sizeToFit()on a view makes it take up the correct amount of space for its content.
UIKitwill measure the contents of the view, then adjust its size so that all the content is visible.
- Nil coalescing lets us provide a default value to use if an optional is nil. As much as I love optionals, I’d much rather have real types to work with, and nil coalescing helps provide just that.
Once more, it is nice to learn from the wrong option:
We need to make custom types conform to NSKeyedUnarchiver if we want to load them from UserDefaults. NSKeyedUnarchiver is a class, not a protocol; it’s used to convert a Data instance into some other sort of data type.
- When creating a scaling
CGAffineTransformwe can provide different X and Y values. This lets us squash our views if needed.
UserDefaultslets us store program settings and user settings in one place. All apps have access to their own
- Multitasking refers to a computer running many pieces of code at the same time. The codes runs in parallel, so any of the tasks can complete at any time.
- Enum raw values are underlying values that sit behind each case. These can be strings, integers, or something else.
loadView()is called before
loadView()is called first, and it’s where you create your view;
viewDidLoad()is called second, and it’s where you configure the view that was loaded.
- Core Graphics can render to PDFs or to screens. This is what’s meant by being “device-independent”.
- We can create custom subclasses of
SKNode. It’s lets us store additional properties and methods.
- Pin annotation titles are automatically shown by MapKit. This is the default behaviour of MapKit.
- You can add many items to an array by using
+=operator adds one array to another, so you can use it to add items quickly.
- A lazy property can be an instance of a different struct.
shuffle()method shuffles an array in place rather than returning a new array. If you want the shuffled array return, use
Objective-Cwrapper that can hold a
CGPoint, or something else.
NSValuewas needed because
Objective-Cwas not able to store
CGRectand other structs in arrays and dictionaries.
- Bitmasks can be combined using
|. This operator is called “bitwise or” and it combines two numbers together.
The alternative option was quite interesting once more:
All SpriteKit physics bodies must be attached to a node. The
nodeproperty is optional because the node might have been destroyed after a collision started.
- Variadic parameters are converted into arrays inside your function. Third mistake of the day, and this time I was absolutely sure I was going to be correct… but again… questions laid out as traps are just that, nasty traps… my answer was: “You can pass an array in place of a variadic parameter.” To which the explanation was: “You must always pass values individually, separated by commas”. Let’s not express my rage in words, better for the reader …
isEmptyon a string is faster than
count == 0.
trueas soon as it knows at least one item exists, where
count == 0has to count all the letters in a string.
- All modern iPhones and iPads support iBeacons. iBeacons were first introduced way back with the iPhone 4S. …fine, my brain is starting to burn when it stretches the memory…
- Multiple buttons can call the same method when tapped. You can connect as many actions as you like to a single method.
print()is a variadic function. You can pass in as many values as you want, separated by commas.
NSMutableAttributedStringboth hold strings with formatting. The only difference is that mutable attributed strings can be modified after we create them.
The alternative was most interesting!
dropFirst()method on a string always removes the first character. FALSE: if the array is empty,
dropFirst()does nothing. Also,
dropFirst()can be called with a parameter to make it drop several letters.
- Multipeer networking can take advantage of Bluetooth and Wi-Fi. We don’t actually care what networking system is used – that’s an implementation detail that iOS takes care of for us.
- We can track changes in the value of a
valueChangedevent. This gets reported back to us every time the slider is moved.
- The default GCD background queue has a lower priority than
.userInitiatedbut higher than
.utility. It has a higher priority than
.utilityand lower than
.userInitiated. Ouff… finding this in my memory was almost as hard as finding it later in the Documentation…
UIGraphicsImageRendererautomatically adjusts its sizes for the pixel density of the current screen. There are options to change this, but the default works best most of the time.
First hour is over, bathroom break 🙂
Back… let’s move on
- To use a
SKAction.follow()action we must pass in its
SpriteKitis a cross-platform framework, and
UIBezierPatharen’t available on macOS. This was the fourth mistake as I rushed it… damn me… of course I could create timers with the repeating option set to false … idiot!
resignFirstResponder()method stops a selected text control from being active, which in turn makes the keyboard go away. You should call this method when you want the user to stop editing a text field or text view.
- The target of an action refers to where that method will be run. The target refers to where the code will be run, and the action refers to what code will be run.
inoutparameters inside a function changes them outside too.
- You can combine
if let. Phew… halfway through… 46/50 by now… not bad but not as good as I hoped it to be. I have only one more mistake for the Distinction pass…
- We can create custom classes for our collection view cells. Custom classes let us create outlets for the cells’ subviews.
- We can change the delegate of the default
UNUserNotificationCenter. This lets us control who gets told when notifications are triggered. This question was just plain scary…
- We can use
#selectorto point to a specific method in a different object. You can use
#selectorto point to a method in any object, as long as that method is marked
- SpriteKit scenes have a default gravity vector. The default value is
Y:-9.8, which matches the gravity on Earth.
- Colouring a sprite means setting its
colorBlendFactorproperties. This lets us control the degree of coloration precisely. Please Paul, for my health’s sake… write “colouring a sprite NODE”… not just a sprite… my heart has limited amount of shocks per day available…
- Creating a new
SKEmitterNodefrom a filename returns an optional. You can unwrap it safely or unsafely depending on how confident you are.
- Interface Builder creates outlets as implicitly unwrapped optionals. This is required because the view won’t exist when the view controller is first created, but it will exist shortly afterwards and then continue to exist for the life of the view controller.
- Every map annotation needs a latitude and longitude coordinate. Without this information the annotation wouldn’t make sense – where would it go?
- Delegation allows one object to respond on behalf of another. Delegation is what allows us to customise the behaviour of built-in types without having to sub-class them.
The other option was:
App Transport Security means apps are installed safely from the App Store. FALSE: App Transport Security means that we can transfer data over the internet using secure connections only.
- We can adjust the stroke color and line width of an
SKShapeNode. This lets us draw lines and borders around shapes.
The other option was, quite trickily because of my friend SpriteKit:
When we call
removeAllActions()method on a
SpriteKitnode, it means any actions will be removed once they have completed. FALSE:
removeAllActions()removes the actions immediately rather than waiting for them to complete.
- Lazy properties can be used inside any kind of structs.
MKPinAnnotationViewis a built-in class that draws tappable pins on the map. As its name suggests, this draws a pin on the map.
- When the user selects a picture using
UIImagePickerControllerwe’ll be sent a dictionary of data. Apple prefers using dictionaries for this purpose because it allows them to expand it to add more things later on if needed.
SpriteKitphysics body with
isDynamicset to false will no longer be affected by gravity. Non-dynamic physics bodies take less CPU time to calculate in the physics simulator, and still respond to collisions.
The other one was very mean but … here it is:
All instances of SKSpriteNode have a texture. FALSE: It’s possible to create sprite nodes with just a color, which is why the texture property is optional.
- Table view cells with subtitles show two different text labels. The default table view cell has a single label, but the subtitle style has two.
- Local notifications can include alerts, sounds, and badges. There are extra settings, but these are the most common.
pcommand in LLDB is short for “print”. It’s an easy way to read the value of a particular variable.
- Visual Formatting Language can create horizontal or vertical constraints. VFL creates horizontal constraints using
H:and vertical constraints using
- We can loop over strings like arrays. Both arrays and strings can be treated like sequences, which means we can loop over them.
- Background tasks prioritise battery efficiency. Background priority is there for tasks that take a very long time to complete, so the system doesn’t allocate them much CPU resource.
- Each multipeer network needs a service type string that identifies it uniquely. Apple recommends you include your company and app name to make sure this string is unique.
String!does not need to be unwrapped before use. If you access an implicitly unwrapped optional while it contains
nil, your code will crash. So yes, it technically doesn’t need to be unwrapped but … it is warmly suggested!
- We can control the center of a view using its
centerproperty. This is often the easiest way to move a view around the screen.
- The safe area layout guide is the space available to our view, excluding rounded corners and notches. All important content should lie inside the safe area, or you risk it being obscured.
- Lazy properties are created using the
- Auto Layout lets us position one view relative to another. This makes it a great way to handle different languages, because your layouts will adapt when given longer or shorter text.
UIStoryboardcan load storyboards from our bundle and create view controllers from there. Just provide it the storyboard name as its first parameter and it will do the rest.
- It’s a good idea to make liberal use of assertions. These can help catch errors in your program state.
- We can create an
SKSpriteNodefrom a texture, from an image name, or from a color. All three initialisers are useful. So this was my fifth mistake but, wait, I can also create a sprite node from a file named… which means that this question is wrongly put… ok… I didn’t check the other option before but I was quite sure with this… if because of this I get to the 6th mistake I will complain with Paul because it really should not be put this way… The other option was :
An SKLabelNode always aligns its text to the center. FALSE: It has a horizontalAlignmentMode property that lets us control this.
Sure I could have checked this, but I guessed, this is the default… which it is …
#if targetEnvironment(simulator)is a compiler directive that lets us compile code only for the simulator. Any code inside this directive won’t be compiled for real devices – it’s as if it doesn’t exist.
- Drawing a sprite with the blend mode
.replaceis faster than the default blend mode. The
.replaceblend more ignores transparency, which makes it faster to draw.
- We must request the user’s permission to show notifications. We can only start showing notifications when permission is granted.
- SpriteKit texture atlases are more efficient than regular asset catalog images. They allow SpriteKit to load in a single image and share it across many nodes.
CLLocationManageris responsible for telling us when iBeacons are detected. We need to assign an object as its delegate, then wait for callbacks when something happens.
- Strong reference cycles can cause view controllers to never be destroyed. If view controllers are kept alive, their contents might be kept alive too – it’s very wasteful.
- Storyboard identifiers allow us to create storyboard view controllers in code. These work similarly to table view cell reuse identifiers.
At 12.40pm I took a pause to go for launch and then to visit a couple of exhibitions in my home town. Tomorrow will be the 220th anniversary of the birth of Silvio Pellico (I hope you know who he is) who was born in my town (Saluzzo). Also Bodoni (yeah, the guy who invented the font among other things) was from here!
But now, at 5.30pm, let’s see if I can resume and finish this with a bit of success.
- Reading a specific character from a string means starting at the start index and counting forwards until we find the letter we want. This is a slow operation, particularly if you want to read through a very large string.
- We can add a delay to animations so they start after a few seconds. This lets you time them as accurately as you need.
components(separatedBy:)method of strings sends back an array of strings. Some strings might be empty depending on what your source data was.
- You can use values higher than 1.0 for red, green, and blue in
UIColor. This uses an iOS feature called wide color, which enables extremely deep colours on modern devices.
- When using
tryyou must catch all errors that can be thrown.
- All user interface code should be run on the main thread. The main thread is the only place it can safely be run.
- If you use
try!and your call throws an error, your code crashes.
- If a function receives a closure parameter and doesn’t use it immediately, it must be marked
@escaping. Think about it like this: the closure escapes the method rather than being used inside there then thrown away.
pathproperty of a URL gives us the location as a string. It’s helpful for APIs that use a string for the filename rather than a URL.
- If you try to use an implicitly unwrapped optional when it is
nil, your code crashes.
- We can add a line break to a string by writing
\n. Alternatively we can use multi-line strings.
- We can simulate Touch ID and Face ID using the iOS Simulator. You can opt into biometric authentication, and provide both matching and unmatching faces/touches.
- Xcode will refuse to build if you haven’t used
@objcwhen it’s needed. When the
@objcattribute is required, it really is required.
- Multipeer networking can send any kind of
Datainstance. As long as you can encode it to
Data, iOS can send it to other peers.
OH MY GOODNESS!
I DID IT!
PASSED WITH DISTINCTION!
Can’t wait to resume learning!
I would like to have Paul here for a big hug and to thank him for all this! I have made so much progress thanks to him and, really, if I have to say, what he taught really stayed! I really feel able to take a blank canvas and DO something!
Oh … I am so excited!
So what is your opinion? How should I go on?
Let me know down in the comments!
Thank you to everyone, especially Rob Baldwin, Filip Nemecek and others on the Slack channel! I would have not gotten here if it was not for them!
I love you guys! Hope to see you soon!
If you like what I’m doing here please consider liking this article and sharing it with some of your peers. If you are feeling like being really awesome, please consider making a small donation to support my studies and my writing (please appreciate that I am not using advertisement on my articles).
If you are interested in my music engraving and my publications don’t forget visit my Facebook page and the pages where I publish my scores (Gumroad, SheetMusicPlus, ScoreExchange and on Apple Books).
You can also support me by buying Paul Hudson’s books from this Affiliate Link.
Anyways, thank you so much for reading!
Till the next one!