{code}

Learning from Open Source

Contributing

This webpage cannot succeed without volunteer effort. Your help in improving existing or adding new articles is very welcome. Simply contact via  e-mail any article you think we should add.

Quake

Fast Inverse Square Root
A Quake III Algorithm

Dynamic Island

Detecting device for
dynamic island.

XOR

Flipping the bits, the
power of XOR.

Alpha Channel

Alpha blending the source and background RGBA colors.

Gradient in Sprite Kit

How to Create a Gradient in Sprite Kit

Quake


float Q_rsqrt( float number )
{
	long i;						// 32-bit number
	float x2, y;					// 32-bit decimal number
	const float threehalfs = 1.5F;			// 1.5 (also 32-Bit)
	
	x2 = number * 0.5F;
	y = number;
	i = * ( long * ) &y;				// evil floating point bit hack
	i = 0x5f3759df - ( i >> 1 );			// what the fuck?
	y = * ( float * ) &i;
	y = y * ( threehalfs - ( x2 * y * y ) );	// 1st iteration
//	y = y * ( threehalfs - ( x2 * y * y ) );	// 2st iteration, can be removed

	return y;
}
	

Dynamic Island

According to the live activity documentation, we can only detect whether the device supports Live activity, but we don't know if the device has dynamic island

But there is a workaround for you to check for dynamic island. Currently dynamic island only available on iPhone 14 Pro and iPhone 14 Pro Max. So just need to check this both device.

Thanks to this link for type model, the model type name of iPhone 14 Pro and iPhone 14 Pro Max is iPhone15,2 and iPhone15,3 so we just need to check for these.

Code will be like this

extension UIDevice {
    func checkIfHasDynamicIsland() -> Bool {
        if let simulatorModelIdentifier = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
            let nameSimulator = simulatorModelIdentifier
            return nameSimulator == "iPhone15,2" || nameSimulator == "iPhone15,3" ? true : false
        }
        
        var sysinfo = utsname()
        uname(&sysinfo) // ignore return value
        let name =  String(bytes: Data(bytes: &sysinfo.machine, count: Int(_SYS_NAMELEN)), encoding: .ascii)!.trimmingCharacters(in: .controlCharacters)
        return name == "iPhone15,2" || name == "iPhone15,3" ? true : false
    }
}

Usage

let value = UIDevice().checkIfHasDynamicIsland()
print("value: ", value)

Using safeAreaInsets

Another solution is to use the window safeAreaInsets value to detect dynamic island. when the device orientation is portrait, safeAreaInsets.top is equal to 59(Display Zoom Default), or 51(Display Zoom Large Text).

note:
This is likely to support the iPhone15 Pro/iPhone15 Pro Max and later models.
extension UIDevice {
    // Get this value after sceneDidBecomeActive
    static var hasDynamicIsland: Bool {
        // 1. dynamicIsland only support iPhone
        guard UIDevice.current.userInterfaceIdiom == .phone else {
            return false
        }
               
        // 2. Get key window, working after sceneDidBecomeActive
        guard let window = (UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }.flatMap { $0.windows }.first { $0.isKeyWindow}) else {
            print("Do not found key window")
            return false
        }
       
        // 3.It works properly when the device orientation is portrait
        return window.safeAreaInsets.top >= 51
    }
}

Usage

if UIDevice.current.hasDynamicIsland == true {
...
}

Flipping the Bits

Set Bit

void set_bit( unsigned char *byte, unsigned char n ) {
    *byte |= 1 << n;
}				

Get Bit

unsigned char get_bit( unsigned char byte, unsigned char n ) {
    return (byte >> n) & 1;
}

Swap with XOR

void swap_using_xor( unsigned int *x, unsigned int *y )
{
	*x = *x ^ *y;	// x = x ^ y
	*y = *x ^ *y;	// y = (x ^ y) ^ y wich means now y = original x
	*x = *x ^ *y;	// x = (x ^ y) ^ y but since y is now original x then
			// it is really x = (x ^ y) ^ x, so x = original y
}

Alpha Channel

Blending two RGBA 32-bit colors

RGBA stands for red green blue alpha. While it is sometimes described as a color space, ... On a little endian architecture this is equivalent to ABGR32.

uint32_t alpha_blend(uint32_t source, uint32_t background)
{
	// Alpha blending the source and background RGBA colors : ABGR32 (little endian)
	uint32_t alpha = (source >> 24);
	uint32_t bxrx = (((source & 0x00ff00ff) * alpha) + 
		 ((background & 0x00ff00ff) * (0xff - alpha))) & 
		 0xff00ff00;
	uint32_t axgx  = ((((source >> 8) & 0x00ff00ff) * alpha) + 
		 (((background >> 8) & 0x00ff00ff) * (0xff - alpha))) & 
		 0xff00ff00;
	
	return ((bxrx >> 8) | axgx);
}

How to Create a Gradient in Sprite Kit

The Idea

Render a UIImage with a gradient layer. Assign the gradient image to an SKTexture object. Assign the texture object to an SKSpriteNode and add the sprite as a child to the scene.

Extending UIImage Class to Render Gradient Images

To render gradient images, we need to extend the base class of UIImage.
Basically, this extended behavior does is that it lets us configure a gradient layer, and then render a UIImage using the gradient layer.

		extension UIImage {
    static func gradientImage(withBounds: CGRect, startPoint: CGPoint, endPoint: CGPoint , colors: [CGColor]) -> UIImage {
        
        // Configure the gradient layer based on input
        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = withBounds
        gradientLayer.colors = colors
        gradientLayer.startPoint = startPoint
        gradientLayer.endPoint = endPoint
        // Render the image using the gradient layer
        UIGraphicsBeginImageContext(gradientLayer.bounds.size)
        gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return image!
    }
}

Choosing the Colors

Feel free to use any colors (and remember to transform them into cgColor).

let color1: CGColor = UIColor(red: 0, green: 0, blue: 192/255, alpha: 1).cgColor
let color2: CGColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1).cgColor
let color3: CGColor = UIColor(red: 192/255, green: 0, blue: 0, alpha: 1).cgColor

Choosing the Gradient Direction

Gradient layer has properties startPoint and endPoint. These are defined in the gradient layer’s unit coordinate space, regardless of whether the gradient layer is drawn on a square or a rectangle. The direction of a linear gradient is from startPoint towards the endPoint. This might be confusing, but basically, the direction of the gradient is the direction in which the color changes most rapidly.

Start Point
(0, 0)


End Point
(1, 1)

End Point
(0, 0)


Start Point
(1, 1)

End Point
(1, 0)


Start Point
(0, 1)

Start Point
(1, 0)


End Point
(0, 1)

End Point
(0.5, 0 )


Start Point
(0.5, 1)

Start Point
(0.5, 0)


End Point
(0.5, 1)

End Point
(0, 0.5)


Start Point
(1, 0.5)

Start Point
(0, 0.5)


End Point
(1, 0.5)

Feel free to choose any direction you like. I’m going to use the top left gradient in this example:

let startPoint = CGPoint(x: 0, y: 0)
let endPoint = CGPoint(x: 1, y: 1)

Using the Gradient

Now inside e.g. didMove function, create a gradient image with the scene’s frame as the boundaries of it, and use the colors defined above + set the start and the end points of the gradient to define its direction.

let image: UIImage = UIImage.gradientImage(withBounds: self.frame, startPoint: startPoint, endPoint: endPoint, colors: [color1, color2, color3])

Then create a texture using the gradient image. Create a gradient node using the texture and finally add it as the child of the scene.

let gradientTexture = SKTexture(image: image)
let gradientNode = SKSpriteNode(texture: gradientTexture)
self.addChild(gradientNode)

Now if you run the app you should see a nice gradient in the view.

In the gradient hides all the other sprites in the scene, you need to adjust the gradient layer’s z-position by changing gradientNode.zPosition to have e.g. the smallest value among all the other nodes if you want the gradient to be in the background.

Swift

CGContext

Transforms the user coordinate system in a context such that the y-axis is flipped.

/*
Copyright © 2023 Insoft. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

extension CGContext {

    /// Transforms the user coordinate system in a context
    /// such that the y-axis is flipped.
    func flipYAxis() {
        concatenate(CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty:
            CGFloat(height)/abs(userSpaceToDeviceSpaceTransform.d)))
    }

}

CGFloat

A colection of extensions for CGFloat

/*
Copyright © 2023 Insoft. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

extension CGFloat {
    static let scale = UIScreen.main.scale
    static let nativeScale = UIScreen.main.nativeScale
    
    static var width: CGFloat {
        return UIScreen.main.bounds.size.width
    }
    static var nativeWidth: CGFloat {
        return UIScreen.main.nativeBounds.size.width
    }
    static var height: CGFloat {
        return UIScreen.main.bounds.size.height
    }
    static var nativeHight: CGFloat {
        return UIScreen.main.nativeBounds.size.height
    }
    
    static let margin: CGFloat = 18.0
    static let scaleFactor = UIDevice.current.userInterfaceIdiom == .pad ? 1.5 * UIScreen.main.scale : UIScreen.main.scale
    static func degrees(_ angle: CGFloat) -> CGFloat {
        return angle * .pi/180
    }
    
    static let earthGravity: CGFloat = 9.8;
}

CGImage

A colection of extensions for CGImage

/*
Copyright © 2023 Insoft. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

import CoreGraphics

#if canImport(UniformTypeIdentifiers)
import UniformTypeIdentifiers
#endif

#if canImport(MobileCoreServices)
import MobileCoreServices
#endif

extension CGImage {
    static func create(fromPixelData pixelData:UnsafePointer<UInt8>, ofSize size:CGSize) -> CGImage? {
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
        let provider = CGDataProvider(data: CFDataCreate(nil, pixelData, Int(size.width) * Int(size.height) * 4))
        CGImageSourceCreateWithDataProvider(provider!, nil)
        
        let cgimg = CGImage(
            width: Int(size.width),
            height: Int(size.height),
            bitsPerComponent: Int(8),
            bitsPerPixel: Int(32),
            bytesPerRow: Int(size.width) * Int(4),
            space: colorSpace,
            bitmapInfo: bitmapInfo,
            provider: provider!,
            decode: nil,
            shouldInterpolate: true,
            intent: CGColorRenderingIntent.defaultIntent
        )
        
        return cgimg
    }
    
    @discardableResult func write(to destinationURL: URL) -> Bool {
        if #available(iOS 14.0, *) {
            guard let destination = CGImageDestinationCreateWithURL(destinationURL as CFURL, UTType.png.identifier as CFString, 1, nil) else { return false }
            CGImageDestinationAddImage(destination, self, nil)
            return CGImageDestinationFinalize(destination)
        } else {
            // Fallback on earlier versions
            guard let destination = CGImageDestinationCreateWithURL(destinationURL as CFURL, kUTTypePNG, 1, nil) else { return false }
            CGImageDestinationAddImage(destination, self, nil)
            return CGImageDestinationFinalize(destination)
        }
    }
}

// MARK: - Objective-C

@objc class _CGImage: NSObject {
    @objc static func create(fromPixelData pixelData:UnsafePointer<UInt8>, ofSize size:CGSize) -> CGImage? {
        return CGImage.create(fromPixelData: pixelData, ofSize: size)
    }
    
    @objc func write(cgimage: CGImage, to destinationURL: URL) -> Bool {
        return cgimage.write(to: destinationURL)
    }
}

UIApplication

A colection of extensions for UIApplication

/*
Copyright © 2023 Insoft. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

import Foundation

extension UIApplication {
    @objc static var rootViewController: UIViewController? {
        if #available(iOS 15, *) {
            // WTF! Apple
            return (UIApplication.shared.connectedScenes.first as? UIWindowScene)?.windows.first?.rootViewController
            
        } else {
            return UIApplication.shared.windows.first?.rootViewController
        }
    }
}