Tuesday, June 20, 2023

Wednesday, January 25, 2023

How to align a vstack to the bottom of a scrollview in SwiftUI

 GeometryReader { reader in

    ScrollView {
        VStack {
            /// Spacer() or Color.red will now behave as expected
        }
        .frame(minHeight: reader.size.height)
    }
}

Friday, September 9, 2022

How to get a list of paired bluetooth devices (Mac OS)

 https://gist.github.com/jamesmartin/9847466aba513de9a77507b56e712296

import IOBluetooth
// See https://developer.apple.com/reference/iobluetooth/iobluetoothdevice
// for API details.
class BluetoothDevices {
func pairedDevices() {
print("Bluetooth devices:")
guard let devices = IOBluetoothDevice.pairedDevices() else {
print("No devices")
return
}
for item in devices {
if let device = item as? IOBluetoothDevice {
print("Name: \(device.name)")
print("Paired?: \(device.isPaired())")
print("Connected?: \(device.isConnected())")
}
}
}
}
var bt = BluetoothDevices()
bt.pairedDevices()

How to get access to Bluetooth on Mac OS

 using RFICOMM and iAP2

https://developer.apple.com/documentation/iobluetooth/iobluetoothdevice


Wednesday, September 7, 2022

How to register and use MFi

Apple MFi FAQ:

https://mfi.apple.com/en/faqs.html


View who does not need to join the MFi Program.
  • Developers and manufacturers of non-electronic accessories, including non-MagSafe cases and Apple Watch bands. Get guidelines and resources for designing accessories that do not incorporate MFi licensed technologies.
  • Distributors and resellers that want to source or sell MFi accessories as finished goods. MFi finished goods must be sourced from an authorized MFi manufacturer. The MFi Licensee will be authorized to develop/manufacture goods sold under your company's brand and will take responsibility for all program requirements on your company's behalf. The Licensee will also be authorized to include the correct MFi badge on the product packaging and user guide of your accessory, once it has completed the necessary program requirements.
  • Developers and manufacturers of accessories that connect to an Apple device using only Bluetooth Low Energy, Core Bluetooth, or standard Bluetooth profiles supported by iOS. Learn more about Bluetooth. (Note: BLE-enabled HomeKit accessories and BLE-enabled MFi Hearing Aids are part of the MFi Program).
  • Educational organizations that want to use the MFi technical specifications for teaching purposes. The information shared under the MFi Program is Apple Confidential and is not intended to be used in an academic setting.
  • Hobbyists and makers creating smart home accessories can use the non-commercial version of the HomeKit Accessory Protocol Specification.
  • Individuals creating accessories for personal use. We recommend using a third-party hobbyist solution to connect iOS devices to serial devices, and to write apps that communicate with these serial devices.
  • App developers creating apps that communicate with MFi accessories. App developers should join the Apple Developer Program. However, it is up to the accessory developer or manufacturer to determine whether they wish to authorize specific third-party apps to communicate with their MFi accessories through the External Accessory Framework. App developers should consult with the accessory developer to determine whether to proceed with development of an app that communicates with an MFi accessory using the EA framework.

Steps to follow for App developer and Device developer:
https://usermanual.wiki/Pdf/Guide20to20Submitting20Apps20that20Work20with20Accessories20R2.781218596/help


Some Apple forum discussion:

https://developer.apple.com/forums/thread/4905



Tuesday, September 6, 2022

Tuesday, March 15, 2022

NSPredicate example and how to use them

 https://academy.realm.io/posts/nspredicate-cheatsheet/

Format string summary

@"attributeName == %@"

object’s attributeName value is equal to value passed in

@"%K == %@"

pass a string variable to %K, it will be represented as a keypath, then check if it’s value is equal to value passed in

@"%name IN $NAME_LIST"

templated for predicate, checks if the value of key name is in $NAME_LIST. Uses predicateWithSubstitutionVariables

@"'name' IN $NAME_LIST"

checks if the constant value ‘name’ is in $NAME_LIST. Uses predicateWithSubstitutionVariables

[NSPredicate predicateWithFormat: @"title == %@", @"minecraft"]


Tuesday, February 22, 2022

Explain how runloops work

 https://khorbushko.github.io/article/2020/11/29/runloop-in-depth.html


RunLoop is the implementation of well-known EventLoop pattern - * programming construct or design pattern that waits for and dispatches events or messages in a program*.

while (!end) { } 

This pattern has been implemented on many platforms. Thus, the main problems that it should resolve are:

  • receive events/messages
  • work when works exist and sleep when no work available (correct resource management).

Hight level description of Thread:

thread life

Hight level description of EventLoop:

thread life

iOS/macOS RunLoop

Talking about iOS/macOS we always refer to RunLoop. To be more correct - 2 classes implement this behavior:

  • CFRunLoopRef (open source)
  • NSRunLoop (based on CFRunLoopRef)

As you already see, RunLoop is connected to the thread. You can’t create RunLoop directly, instead, it’s can be created at the very start of Thread creating and destroyed at the very end of theThread lifecycle. There are 2 function that provide access to RunLoop - CFRunLoopGetMain()and CFRunLoopGetCurrent()

debug backtrace

Run loops are part of the fundamental infrastructure associated with threads. A run loop is an event processing loop that you use to schedule work and coordinate the receipt of incoming events. The purpose of a run loop is to keep your thread busy when there is work to do and put your thread to sleep when there is none. - Apple.


Tuesday, November 2, 2021

How to handle unhandled exceptions like SIGTRAP

https://www.cocoawithlove.com/2010/05/handling-unhandled-exceptions-and.html


void InstallUncaughtExceptionHandler()

{

    NSSetUncaughtExceptionHandler(&HandleException);

    signal(SIGABRT, SignalHandler);

    signal(SIGILL, SignalHandler);

    signal(SIGSEGV, SignalHandler);

    signal(SIGFPE, SignalHandler);

    signal(SIGBUS, SignalHandler);

    signal(SIGPIPE, SignalHandler);

}

Tuesday, June 15, 2021

toString print all the fields

 public func toString() -> String {

    var ret = "Test Status: "

    for case let (label?, value) in Mirror(reflecting: self)

      .children.map({ ($0.label, $0.value) }) {

      ret.append(" \(label): \(value)")

    }

    return ret

  }


Wednesday, May 5, 2021

View files generated in documents folder in the Files app

 <key>UIFileSharingEnabled</key>

    <true/>

<key>LSSupportsOpeningDocumentsInPlace</key>

    <true/>

How to generate a file in documents folder

 public func createAndWriteFile() {

     let fileName = "sample"

     let documentDirectoryUrl = try! FileManager.default.url(

        for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true

     )

     let fileUrl = documentDirectoryUrl.appendingPathComponent(fileName).appendingPathExtension("txt")

     // prints the file path

     print("File path \(fileUrl.path)")

     //data to write in file.

     let stringData = "Hello Tutorials Point"

     do {

        try stringData.write(to: fileUrl, atomically: true, encoding: String.Encoding.utf8)

     } catch let error as NSError {

        print (error)

     }

  }

Thursday, April 29, 2021

Thursday, January 14, 2021

How to disable a modal from swiping down to close

let vc = DetailViewController() vc.isModalInPresentation = true present(vc, animated: true)

Wednesday, January 13, 2021

adding borders

 extension UIView {

    func addTopBorderWithColor(color: UIColor, width: CGFloat) {

        let border = CALayer()

        border.backgroundColor = color.cgColor

        border.frame = CGRect(x:0,y: 0, width:self.frame.size.width, height:width)

        self.layer.addSublayer(border)

    }


    func addRightBorderWithColor(color: UIColor, width: CGFloat) {

        let border = CALayer()

        border.backgroundColor = color.cgColor

        border.frame = CGRect(x: self.frame.size.width - width,y: 0, width:width, height:self.frame.size.height)

        self.layer.addSublayer(border)

    }


    func addBottomBorderWithColor(color: UIColor, width: CGFloat) {

        let border = CALayer()

        border.backgroundColor = color.cgColor

        border.frame = CGRect(x:0, y:self.frame.size.height - width, width:self.frame.size.width, height:width)

        self.layer.addSublayer(border)

    }


    func addLeftBorderWithColor(color: UIColor, width: CGFloat) {

        let border = CALayer()

        border.backgroundColor = color.cgColor

        border.frame = CGRect(x:0, y:0, width:width, height:self.frame.size.height)

        self.layer.addSublayer(border)

    }


    func addMiddleBorderWithColor(color: UIColor, width: CGFloat) {

        let border = CALayer()

        border.backgroundColor = color.cgColor

        border.frame = CGRect(x:self.frame.size.width/2, y:0, width:width, height:self.frame.size.height)

        self.layer.addSublayer(border)

    }

}


Thursday, January 7, 2021

How to generate a app size report

xcodebuild -exportArchive -archivePath iOSApp.xcarchive -exportPath Release/MyApp -exportOptionsPlist OptionsPlist.plist

Friday, December 18, 2020

Explain how bitcode works

https://jonasdevlieghere.com/embedded-bitcode/ Bitcode is the intermediate representation used by the LLVM compiler and contains all the information required to recompile an application. Having the bitcode present, in addition to machine code, Apple can further optimize applications by compiling and linking specifically for the user's target device. This is one approach to app thinning, which aims to achieve smaller binaries and therefore more free space on your iDevice. It will most likely replace Apple's current approach, where a developer uploads a fat binary to the App Store, which contains machine code for each target architecture.

Wednesday, December 2, 2020

How to create abstract functions in Swift

 class BaseClass {

    func abstractFunction() {
        preconditionFailure("This method must be overridden") 
    } 
}

class SubClass : BaseClass {
     override func abstractFunction() {
         // Override
     } 
}
https://stackoverflow.com/questions/24110362/abstract-functions-in-swift-language

Wednesday, November 18, 2020

Get Value For Selector

func getValueForSelector(cls: AnyClass, selector: Selector) -> AnyObject {

  let method = class_getInstanceMethod((cls), selector)!

  let methodIMP : IMP! = method_getImplementation(method)

  let newAmountObj = unsafeBitCast(methodIMP,to:(@convention(c)(AnyClass?,Selector,Any?)->Any).self)(cls,selector, nil) as AnyObject

  return newAmountObj

}

Accessor Search Patterns

Search Pattern for the Basic Setter

The default implementation of setValue:forKey:, given key and value parameters as input, attempts to set a property named key to value (or, for non-object properties, the unwrapped version of  value, as described in Representing Non-Object Values) inside the object receiving the call, using the following procedure:

  1. Look for the first accessor named set<Key>: or _set<Key>, in that order. If found, invoke it with the input value (or unwrapped value, as needed) and finish.

  2. If no simple accessor is found, and if the class method accessInstanceVariablesDirectly returns YES, look for an instance variable with a name like _<key>, _is<Key>, <key>, or is<Key>, in that order. If found, set the variable directly with the input value (or unwrapped value) and finish.

  3. Upon finding no accessor or instance variable, invoke setValue:forUndefinedKey:. This raises an exception by default, but a subclass of NSObject may provide key-specific behavior.


Tuesday, November 17, 2020

3 ways to call ObjC methods from swift

 There are three ways to dynamically call the method in this class:

1. Using performSelector()

let selector = NSSelectorFromString("titleForItem:withTag:")
let unmanaged = toolbar.perform(selector, with: "foo", with: "bar")
let result = unmanaged?.takeRetainedValue() as? String

2. Using methodForSelector() with @convention(c)

typealias titleForItemMethod = @convention(c)
    (NSObject, Selector, NSString, NSString) -> NSString
  
let selector = NSSelectorFromString("titleForItem:withTag:")
let methodIMP = toolbar.method(for: selector)
let method = unsafeBitCast(methodIMP, to: titleForItemMethod.self)
let result = method(toolbar, selector, "foo", "bar")

3. Using NSInvocation

It's only available in Objective-C.
SEL selector = @selector(titleForItem:withTag:);
NSMethodSignature *signature = [toolbar methodSignatureForSelector:selector];

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = toolbar;
invocation.selector = selector;

NSString *argument1 = @"foo";
NSString *argument2 = @"bar";
[invocation setArgument:&argument1 atIndex:2];
[invocation setArgument:&argument2 atIndex:3];

[invocation invoke];

NSString *result;
[invocation getReturnValue:&result];

Or, we can use Dynamic ðŸŽ‰

let result = Dynamic(toolbar)            // Wrap the object with Dynamic
    .titleForItem("foo", withTag: "bar") // Call the method directly!

More details on how the library is designed and how it works here.