The Importance of Learning
I am learning SwiftUI for fun - I’ve never built an iOS app before, so I thought it was about time.
On Monday, I spent the entire day figuring out how to create a QR Code and display it on screen. My brain hurt and I felt demoralised by my slow progress.
On Tuesday, I decided to go back to iPhone school and spent a few hours continuing my learning journey with the excellent Building iOS User Interfaces with SwiftUI by Andrew Bancroft on Pluralsight and then cycled to the pub for the afternoon.
On Wednesday, while running, I realised, based on my new knowledge, that there was a better way to achieve the same result as Monday and a couple of hours later I was proven correct.
Monday’s brute force solution took approximately 8 hours to write and Wednesday’s version took less than 2 hours and demonstrated that Monday’s QR code was in fact upside down!
Other stats, Monday’s version is 3,159 characters and Wednesday’s is 1,343 characters.? Monday’s solution is a function which returns an Image and Wednesday’s is native SwiftUI QRCodeView.
I’ll share the code below which I transferred into a Swift Playground which is an awesome learning tool.? I’d be very keen to hear any further suggested improvements.
And my moral of this story is this … how many of us are brute forcing our way through our daily lives or forcing our teams to brute force their way through their work when a little bit of education is all that’s required to become 4x more efficient, significantly less stressed and produce better results?
What do you think? Can the source code be improved further?
Swift Playground
Try the code for yourself.
Source Code
// Two different approaches to generating a QR Code with a logo in the middle.
// Written by [email protected]
import SwiftUI
import PlaygroundSupport
import CoreImage.CIFilterBuiltins
let url = "https://greensted.com/"
let icon = "heart.fill"
PlaygroundPage.current.setLiveView(ContentView())
struct ContentView: View {
??var body: some View {
?????HStack(){
?????// MARK: Brute force QR Code generation
??????VStack(){
????????var qrCodeImage = generateQRCode(from: url)
????? ??if let qrCode = qrCodeImage {
??????????Image(uiImage: qrCode)
????????} else {
????????}
????????Text("Monday").bold()
??????}
??????Spacer()
??????// MARK: Educated QR Code generation
??????VStack(){
????????QRCodeView(data: url, icon: icon)
????????Text("Wednesday").bold()
??????}
????}
????.padding()
??}
}
struct QRCodeView: View {
??var data: String
??var icon: String
??var body: some View {
????// Generate the QR Code using Core Image
????let context = CIContext()
????let filter = CIFilter(name: "CIQRCodeGenerator") ?? CIFilter()
????let _: Void = filter.setValue(data.data(using: .utf8), forKey: "inputMessage")
?????
????if let outputImage = filter.outputImage {
??????if let cgimg = context.createCGImage(outputImage, from: outputImage.extent) {
?????????
????????// Finally create the Image struct using the cgImage
????????Image(uiImage: UIImage(cgImage: cgimg))
??????????.interpolation(.none)
??????????.resizable()
??????????.overlay(content:
????????????{
????????????Image(systemName: icon)
??????????????.resizable()
??????????????.foregroundColor(.white)
??????????????.scaledToFit()
??????????????.frame(width:60, height: 60)
????????????Image(systemName: icon)
??????????????.resizable()
??????????????.foregroundColor(.pink)
??????????????.scaledToFit()
??????????????.frame(width:54, height: 54)
??????????})
??????????.frame(width:200, height: 200)
??????}
????}
领英推荐
????else {}
??}
}
func generateQRCode(from string: String, size: CGSize = CGSize(width: 200, height: 200)) -> UIImage? {
???
??guard let data = string.data(using: .ascii),
?????let filter = CIFilter(name: "CIQRCodeGenerator")
??else { return nil}
???
??filter.setValue(data, forKey: "inputMessage")
??let context = CIContext(options: nil)
??guard let output = filter.outputImage,
?????let buskIconTemp = UIImage(systemName: "heart.fill"),
?????let buskIconBlack = flipImageVertically(buskIconTemp),
?????let buskIcon = recolorIcon(buskIconBlack, color: .systemPink),
?????let ciBuskIcon = CIImage(image: buskIcon),
?????let cgBusksIcon = context.createCGImage(ciBuskIcon, from: ciBuskIcon.extent) else {
????return nil
??}
?
??if let cgImage = context.createCGImage(output, from: output.extent) {
????UIGraphicsBeginImageContextWithOptions(size, false, 0)
????if let context = UIGraphicsGetCurrentContext() {
??????context.interpolationQuality = .none
??????context.draw(cgImage, in: CGRect(origin: .zero, size: size))
???????
??????let iconSize: CGFloat = 55
??????let iconOrigin = CGPoint(x: (size.width - iconSize) / 2, y: (size.height - iconSize) / 2)
??????let colour: UIColor = UIColor.white
??????context.setFillColor(colour.cgColor)
??????context.fill(CGRect(origin: iconOrigin, size: CGSize(width: iconSize, height: iconSize)))
??????context.draw(cgBusksIcon, in: CGRect(origin: iconOrigin, size: CGSize(width: iconSize, height: iconSize)))
???????
??????let qrCodeImage = UIGraphicsGetImageFromCurrentImageContext()
??????UIGraphicsEndImageContext()
??????return qrCodeImage
????}
??}
??return nil
}
func flipImageVertically(_ image: UIImage) -> UIImage? {
??UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
??guard let context = UIGraphicsGetCurrentContext() else {
????return nil
??}
??// Flip the context vertically
??context.scaleBy(x: 1, y: -1)
??context.translateBy(x: 0, y: -image.size.height)
??// Draw the original image into the flipped context
??image.draw(in: CGRect(origin: .zero, size: image.size))
??// Create a new image from the context
??let flippedImage = UIGraphicsGetImageFromCurrentImageContext()
??// Clean up the context
??UIGraphicsEndImageContext()
??return flippedImage
}
func recolorIcon(_ image: UIImage, color: UIColor) -> UIImage? {
??UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
??guard let context = UIGraphicsGetCurrentContext() else {
????return nil
??}
??// Draw the image first to create a mask
??image.draw(in: CGRect(origin: .zero, size: image.size))
??// Apply the color using a blending mode
??context.setBlendMode(.sourceIn)
??color.setFill()
??context.fill(CGRect(origin: .zero, size: image.size))
??// Get the new image with the applied color
??let recoloredImage = UIGraphicsGetImageFromCurrentImageContext()
??// Clean up the context
??UIGraphicsEndImageContext()
??return recoloredImage
}
CTO/VP Engineering/Advisor focussed on transformation
1 年The biggest problem I find in many of the companies I have worked with is teams (engineers, prod mgrs, et al) who have 'brute forced' it (guessed) and built poor quality systems that don't do the job properly. The 2nd biggest problem is that they don't realise that is what they have done. In our industry many people have ceased to be inquisitive in favour of JFDI which is leading to poor productivity and poor product.
CEO at Trade Classics.
1 年Well written and poignant narrative. I'm sure we can all think of times when we've brute forced something, when a little more upfront thought and self education would have paid dividends. Sadly I can't help with the code improvement as time=none, but I can say: { ??// Give Feedback return?feedbackJGpositive ?}