Embed a UIViewController in a UINavigationController Programmatically

We know how to embed a ViewController in a NavigationController in Storyboard. However, I came across a scenario where I had to initiate it programmatically. The code:

let viewController = MyViewController()
let nav = UINavigationController(rootViewController: viewController)
self.navigationController?.present(nav, animated: true, completion: nil)

Create a script using Mac terminal

Scripts save us a lot of time. While scripts are running and doing the work we would have had to do manually, we can drink coffee or talk or just chill! 😃 Here is how you can create a simple script in mac terminal.

Run the following in the terminal:

Paste the following or your own private script:

echo "Hello, world!"

Hit

Ctrl + wq

Run the following:

sudo chmod 700 myScript.sh

Run the script by:

./myScript.sh

My personal scripts run a bunch of git commands all in one script or build an app with different configurations etc. I also have scripts that compile and build an application or more 😉

Happy scripting guys and girls!

Unique ID on iOS Devices

Problem!

We all know now that identifierForVendor doesn’t remain unique on iOS Devices. It changes when the user deletes all of the apps from the same vendor.

According to Apple:

The value in this property remains the same while the app (or another app from the same vendor) is installed on the iOS device. The value changes when the user deletes all of that vendor’s apps from the device and subsequently reinstalls one or more of them. The value can also change when installing test builds using Xcode or when installing an app on a device using ad-hoc distribution. Therefore, if your app stores the value of this property anywhere, you should gracefully handle situations where the identifier changes.

Please see Apple Documentation for more information.

Solution

To get the unique Id we need to generate it first through CFUUID and save it on the device using KeyChain, in this case our SwiftKeychainWrapper will do the job. This way, even when the user deletes the app the UUID can be fetched using the UNIQUE_KEY that was originally used to save the UUID.

import UIKit
import SwiftKeychainWrapper

class ViewController: UIViewController {

    @IBOutlet weak var uuidValue: UILabel!
    private let UNIQUE_KEY = "mySuperDuperUniqueId"
    override func viewDidLoad() {
        super.viewDidLoad()
        let uniqueDeviceId: String? = KeychainWrapper.standard.string(forKey: UNIQUE_KEY)
        
        guard uniqueDeviceId != nil else {
            let uuid = generateUuid()
            let saveSuccessful: Bool = KeychainWrapper.standard.set(uuid, forKey: UNIQUE_KEY)
            if saveSuccessful {
                uuidValue.text = uuid
            } else {
                fatalError("Unable to save uuid")
            }
            return
        }
        uuidValue.text = uniqueDeviceId!
    }
    
    private func generateUuid() -> String {
        let uuidRef: CFUUID = CFUUIDCreate(nil)
        let uuidStringRef: CFString = CFUUIDCreateString(nil, uuidRef)
        return uuidStringRef as String
    }
}

 

Android Threads and updates on Main Thread

While working on the android app, I discovered the following error:
Skipped 55 frames!  The application may be doing too much work on its main thread.
I realized I was running heavy processing and UI updates on the same thread. A time consuming task (such as fetching data, filtering arrays) should run in its own thread and when the result is received/achieved the app should run UI update in the main thread.
For instance, in iOS we do:

DispatchQueue.main.async {
	self.tableView.reloadData()
}
Once the data has been received from backend then we run self.tableView.reloadData() in the main thread to present this new data in the view.
Likewise in Android we should run heaving processing tasks in separate threads. We first define the update that we want to happen when we have received the result from a task. We create an instance of the Runnable class which will execute the UI update, in this case show the checkMark icon:

final Runnable checkMarkIsVisible = new Runnable(){
	@Override
	public void run() { 
		checkMark.setVisibility(View.VISIBLE);
	} 
};
Then we create a separate thread for performing the task that can decide whether or not the checkmark will be displayed. Once the result is achieved, we run call the Runnable checkMarkIsVisible on the main thread.
final Handler mainHandler = new Handler(mContext.getApplicationContext().getMainLooper());

new Thread(new Runnable() {
	@Override
	public void run(){
		 //Perform som task
		 if( isItemInList(myItem, myList) ){
		      mainHandler.post(checkMarkIsVisible);
		   }
	}
}).start();

You will not receive the error message anymore.


Edited:

A friend tipped me off after reading this post that instead of having to grab the main thread, you can also run on main thread using runOnUiThread:

new Thread(new Runnable() {
	@Override
	public void run() {
		final String result = performBlockingTask();

		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				mTextView.setText(result);
			}
		});
	}
});