Challenges
- CGAffineTransform is a transform type used by Core Graphics and used to scale, rotate graphical elements. You can obtain an inverse transform by calling the inverted() method.
Just like dividing by zero fails, inverting a singular transform can fail. (When this happens CGAffineTransform does nothing to warn you except print a message to the console. You can do better.
The following code that checks whether a transform can be inverted or will fail.
extension CGAffineTransform { var isInvertable: Bool {
return abs(ad - bc) > CGFloat.ulpOfOne
}
}
CGAffineTransform().isInvertable // false CGAffineTransform.identity.isInvertable // true
Use the following code make viewing transforms easy:
extension CGAffineTransform: CustomStringConvertible { public var description: String {
return [a,b,c,d,tx,ty].reduce("") { $0 + " ($1)" }
}
}
Write a method on CGAffineTransform called safeInverted() that returns an optional type. If the transform can be inverted it returns the new transform. Otherwise it returns nil.
Test your method with let scaleByTwo = CGAffineTransform.identity.scaledBy(x: 2, y: 2) and observe the values you get back.
- Use optional chaning to safely invert the transform and then invert it again. (Much like taking the recipricol of the same number, you should wind up with
the same number.)
- Change your above design to throw MathError.singular error if the transform can't be inverted. Call this new method checkedInverted() so it can co-exist nicely with your safeInverted() method. Test it out.
- Notice the return types of safeInverted() and checkedInverted(). How do they differ?
You’ve learned the basics of memory management in Chapter 15, “Advanced Classes”, where you explored the class lifecycle and automatic reference counting or ARC. In most cases, memory management works out of the box in Swift and you don’t have to worry about it.
However, there are certain cases when ARC can’t handle everything on its own, so it’s your responsibility to use it wisely. In this chapter, you’ll revisit the concept of reference cycles and learn how to resolve them for classes and closures. You will also learn to manage asynchronous code with Grand Central Dispatch and use capture lists in closures to capture values from the enclosing scope.
Before you break reference cycles, it’s very important to understand how they are created.