diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index d489677c..13535e03 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -6,7 +6,7 @@ { "id": "dd4a158ffe1a15b2", "type": "tabs", - "dimension": 60.15144344533838, + "dimension": 60.6484893146647, "children": [ { "id": "6a25767ea83a46c5", @@ -37,109 +37,94 @@ }, "pinned": true } - } - ], - "currentTab": 1 - }, - { - "id": "50ad62547a03ea1f", - "type": "tabs", - "dimension": 39.84855655466162, - "children": [ - { - "id": "5c968719c026c29f", - "type": "leaf", - "pinned": true, - "state": { - "type": "markdown", - "state": { - "file": "ios/swiftUI/MVVM_example.md", - "mode": "source", - "backlinks": true, - "source": false - }, - "pinned": true - } }, { - "id": "b6bf584108a82b1f", + "id": "1e67adc31c056023", "type": "leaf", - "pinned": true, "state": { "type": "markdown", "state": { - "file": "architecture/composable/input_output.md", + "file": "architecture/ReadMe_architecture.md", "mode": "source", "backlinks": true, "source": false - }, - "pinned": true + } } }, { - "id": "6a782c6ab1913ba1", + "id": "c0968db086fe71e1", "type": "leaf", - "pinned": true, "state": { "type": "markdown", "state": { - "file": "architecture/composable/viewStateViewModel.md", + "file": "ios/concurrency/actors.md", "mode": "source", "backlinks": true, "source": false - }, - "pinned": true + } } }, { - "id": "aa1f21e4ebfe1b65", + "id": "8c976337c384f5ec", "type": "leaf", "pinned": true, "state": { "type": "markdown", "state": { - "file": "architecture/composable/usage.md", + "file": "ios/concurrency/thread.md", "mode": "source", "backlinks": true, "source": false }, "pinned": true } - }, + } + ], + "currentTab": 3 + }, + { + "id": "648c3a2de83639d8", + "type": "tabs", + "dimension": 15.843773028739868, + "children": [ { - "id": "81681080152a7fcf", + "id": "98a986cea358123d", "type": "leaf", "state": { "type": "markdown", "state": { - "file": "ios/library/import.md", + "file": "architecture/concurrency.md", "mode": "source", "backlinks": true, "source": false } } - }, + } + ] + }, + { + "id": "50ad62547a03ea1f", + "type": "tabs", + "dimension": 23.50773765659543, + "children": [ { - "id": "e5e089229a91b293", + "id": "1b35c90d4293749d", "type": "leaf", + "pinned": true, "state": { - "type": "markdown", - "state": { - "file": "architecture/software_updates.md", - "mode": "source", - "backlinks": true, - "source": false - } + "type": "graph", + "state": {}, + "pinned": true } }, { - "id": "b09d7b071308fc9a", + "id": "d3abdcf2cf367df4", "type": "leaf", "pinned": true, "state": { "type": "markdown", "state": { - "file": "SUMMARY.md", + "file": "ios/concurrency/thread.md", "mode": "source", "backlinks": true, "source": false @@ -148,7 +133,7 @@ } } ], - "currentTab": 5 + "currentTab": 1 } ], "direction": "vertical" @@ -177,7 +162,7 @@ "state": { "type": "search", "state": { - "query": "dynamic", + "query": "nomenclature", "matchingCase": true, "explainSearch": false, "collapseAll": false, @@ -198,7 +183,7 @@ } ], "direction": "horizontal", - "width": 226.00556182861328 + "width": 258.0055618286133 }, "right": { "id": "13f2ec0339a31543", @@ -214,7 +199,7 @@ "state": { "type": "backlink", "state": { - "file": "architecture/software_updates.md", + "file": "ios/concurrency/actors.md", "collapseAll": false, "extraContext": false, "sortOrder": "alphabetical", @@ -231,7 +216,7 @@ "state": { "type": "outgoing-link", "state": { - "file": "architecture/software_updates.md", + "file": "ios/concurrency/actors.md", "linksCollapsed": true, "unlinkedCollapsed": true } @@ -254,7 +239,7 @@ "state": { "type": "outline", "state": { - "file": "architecture/software_updates.md" + "file": "ios/concurrency/actors.md" } } } @@ -275,34 +260,34 @@ "command-palette:Open command palette": false } }, - "active": "e5e089229a91b293", + "active": "c0968db086fe71e1", "lastOpenFiles": [ - "ios/library/framework.md", - "architecture/software_updates.md", - "ios/library/import.md", - "architecture/composable/viewStateViewModel.md", - "ios/library/avkit.md", - "architecture/orchestration.md", - "ios/README_iOS.md", - "architecture/navigationCoordinator.md", - "tools/browsers/developer_network.md", - "ios/config/README_config.md", - "os/mac/fresh_install.md", - "ios/lifecycle/README_lifecycle.md", - "ios/lifecycle/database.md", - "ios/config/secret_keys.md", - "ios/swiftUI/image.md", - "ios/lifecycle/cache.md", - "ios/config/cache.md", + "ios/concurrency/background_tasks.md", + "ios/concurrency/asyncLet.md", + "ios/concurrency/asyncAwait.md", + "ios/concurrency/actors.md", + "ios/concurrency/operations.md", + "ios/concurrency/GCD.md", + "ios/concurrency/dispatch_semaphore.md", + "ios/concurrency/dispatch_queue.md", + "ios/concurrency/dispatch_main.md", + "ios/concurrency/dispatch_group.md", + "ios/concurrency/dispatch_barrier.md", + "ios/concurrency/asyncTaskGroup.md", + "architecture/concurrency.md", + "architecture/coordinator_pattern.md", + "architecture/delegate_pattern.md", + "architecture/facade_pattern.md", + "architecture/mvc_pattern.md", "architecture/mvvm_c_pattern.md", - "architecture/mvvm_pattern.md", - "architecture/notification_pattern.md", "architecture/ReadMe_architecture.md", - "ios/config/analytics.md", - "ios/config/app_environment.md", - "ios/config/appConfiguration.md", - "ios/config/app_store _connect.md", - "ios/library/storage.md", + "architecture/singleton_pattern.md", + "architecture/software_updates.md", + "architecture/system_designs.md", + "ios/README_iOS.md", + "ios/concurrency/Readme_concurrency.md", + "ios/combine/ReadMe_combine.md", + "ios/ui/README_ui.md", "architecture/Untitled", "architecture/composable", "architecture", diff --git a/architecture/ReadMe_architecture.md b/architecture/ReadMe_architecture.md index e334f1f0..6252a253 100644 --- a/architecture/ReadMe_architecture.md +++ b/architecture/ReadMe_architecture.md @@ -20,6 +20,8 @@ Enjoy [[concurrency]] +[mvvm_pattern](mvvm_pattern.md) + [mvc_pattern](mvc_pattern.md) [singleton_pattern](singleton_pattern.md) @@ -28,8 +30,6 @@ Enjoy [coordinator_pattern](coordinator_pattern.md) -[mvvm_pattern](mvvm_pattern.md) - [mvvm_c_pattern](mvvm_c_pattern.md) [notification_pattern](notification_pattern.md) @@ -42,8 +42,6 @@ Enjoy ## Resources - - [Point Free](https://www.pointfree.co/collections/composable-architecture) [Point Series](https://www.pointfree.co) diff --git a/architecture/concurrency.md b/architecture/concurrency.md index ab43c357..10c749a4 100644 --- a/architecture/concurrency.md +++ b/architecture/concurrency.md @@ -2,6 +2,7 @@ Basic concepts from my understanding. +If you want to quickly jump into Swift Concurrency or iOS Xcode Swift concurrency examples. Please follow this [Readme_concurrency](Readme_concurrency.md) or folder `iOS/concurrency/readME_concurrency` ## Multi Threading | Multi Processing @@ -14,11 +15,11 @@ Side note: You can do multi threading on a single processor or do multi tasking When a piece of work, process, thread, code, executable (machine code) is meant to execute in a blocking or non blocking way. -### Async: +### Async For example your heart beats in an async fashion it isn't dependent retrospectively for someone's input in order to make the next heart beat to pump blood in your veins of the human body. -### Sync: +### Sync On the other hand eyes, brain coordinate with each other to send a neuron signal via synapses in order for the human motor functions to operate. So that is in a way synchronous activity. Hands or other body functions are dependent on some other functions when they give signals to do certain task synchronously and when they are doing certain task they do it in somewhat blocking way. Of course human brain is somewhat more capable of scheduling multiple instances of parallel activities such as your mental intuition is still in the works, your five sensory inputs are still working in the background and more. @@ -29,10 +30,14 @@ I should have went with a better example since human body mostly works asynchron A unit of work to be executed by a processor. Multiple threads can exist on a single process. +[thread](thread.md) + ## Process A collection of threads or units of work to be executed by the OS scheduler is called a process. It may also include shared resources in order to better communicate with other processes or access low level apis with kernel or I/O devices. +[tasks](tasks.md) + ## Scheduler diff --git a/architecture/coordinator_pattern.md b/architecture/coordinator_pattern.md index 96b4f6ce..4e64f9b5 100644 --- a/architecture/coordinator_pattern.md +++ b/architecture/coordinator_pattern.md @@ -1,4 +1,11 @@ -## Coordinator pattern +# Coordinator pattern + + +## Intro Navigation Coordinator pattern -> Passing around navigationContext to take care of presenting and dismissing logic from one point. + + +## Code + diff --git a/architecture/delegate_pattern.md b/architecture/delegate_pattern.md index abfbb5db..2bd50199 100644 --- a/architecture/delegate_pattern.md +++ b/architecture/delegate_pattern.md @@ -1,17 +1,18 @@ -## Delegate Pattern +# Delegate Pattern +## Intro 1 : 1 type - - https://medium.com/@nimjea/delegation-pattern-in-swift-4-2-f6aca61f4bf5 -Pros: +## Pros - No extra management of state. It is one to one. - Less side effects. -Cons: +## Cons - Need to be one to one -- +- Not easy to understand at first glance - isn't intuitive if coming from other languages. +- Lots of bigger name delegate functions - more verbiage. +- need to isolate for cleaner readability in extensions with conformance to `delegate / datasource` diff --git a/architecture/facade_pattern.md b/architecture/facade_pattern.md index c6f319e8..ee4613cb 100644 --- a/architecture/facade_pattern.md +++ b/architecture/facade_pattern.md @@ -1,4 +1,27 @@ -## Facade pattern +# Facade pattern +## Intro +When you have abstraction in place to make sure that certain thing could be carried out but you don't know the general specifics of its implementation under the hood. +So you place a facade in that callsite and just assume work or certain tasks / preparations have been taking place in the background which isn't oblivious to the front consumer or onlooker. Thus the facade pattern. It derives from actual civil architecture nomenclature. Houses having a great facade. + + + + + + + + + + + + + + + +### Tangent + +I usually use this to describe human beings, since they are nicer when things are good ( putting up a facade ) but internally they are who they are. +But that's psychology and I don't practice that legally. :P +My two bits `1 0` advice to everyone. diff --git a/architecture/mvc_pattern.md b/architecture/mvc_pattern.md index 6359cd2b..7b1c93f9 100644 --- a/architecture/mvc_pattern.md +++ b/architecture/mvc_pattern.md @@ -1,13 +1,13 @@ -## MVC +# MVC Model View Controller -Pros: +## Pros - Apple's default implementation in Objective C and Swift UIKit. - Easier for freshers. -Cons: +## Cons - Massive View controller - Not unit testable to higher degree. - ViewController does lot of things diff --git a/architecture/mvvm_c_pattern.md b/architecture/mvvm_c_pattern.md index a3461203..90e3bb9b 100644 --- a/architecture/mvvm_c_pattern.md +++ b/architecture/mvvm_c_pattern.md @@ -1,10 +1,10 @@ -## MVVM - C +# MVVM - C -Pros: +## Pros - Less presentation logic duplication - Good global state management -Cons: +## Cons - Upfront cost - Need to deal with multi level child VCs or View presenters - Traverse [UIViews] or Views diff --git a/architecture/singleton_pattern.md b/architecture/singleton_pattern.md index 183ff3f4..8fca8c80 100644 --- a/architecture/singleton_pattern.md +++ b/architecture/singleton_pattern.md @@ -1,6 +1,7 @@ -## Singleton +# Singleton + +## Pros -Pros: - Easy understanding - One source of truth - Object remains in the memory throughtout the app lifecycle. @@ -9,7 +10,8 @@ Pros: - iOS UIKit, CocoaTouch relies a lot on Singleton and MVC pattern. - App Delegate is important singleton instance. -Cons: +## Cons + - Data inconsistency - Not multi thread safe. (Not good for CRUD operations) - More dependencies - Highly coupled - Less testable @@ -19,8 +21,11 @@ Cons: - Could be time dependent with some callback. -```swift +## Code +Important to privatize the initi() in order to not let invocation rights to anyone else. + +```swift class SingletonClass { static let shared: SingletonClass = SingletonClass() @@ -28,4 +33,17 @@ class SingletonClass { func foo() { } } +``` + +Also defining the class `final` and having just `Singleton` pattern for invocation only once is kind of similar but there is definitely need for each in their own right. + + + +I know Java has few differences & I haven't taken my time to research these things in iOS Swift world. + +https://stackoverflow.com/questions/519520/difference-between-static-class-and-singleton-pattern?rq=1 + +https://stackoverflow.com/questions/51508613/is-final-necessary-for-a-singleton-class-in-swift + +https://javarevisited.blogspot.com/2013/03/difference-between-singleton-pattern-vs-static-class-java.html diff --git a/architecture/software_updates.md b/architecture/software_updates.md index aa224ed6..c9f9af8d 100644 --- a/architecture/software_updates.md +++ b/architecture/software_updates.md @@ -1,8 +1,24 @@ +# Software Updates +## Intro +This piece is quite opiniated from point of view. No way this is scientific or academic. So take it with a grain of salt or a glass of Whiskey talk speaking. +But none theless enjoy my thought process around Software updates in general. + +## Process Part of the reason Apple updates are huge, since they repackage it again for each release. Microsoft updates and other linux distros have a great pipeline saving the world thousands of network storage and throughput for every time there is an update. + Google even though they are fragmented with their android ecosystem , their app architecture for providing new updates is phenomenal with delivery smaller chunks of data being changed and quickly linking them appropriately. It is slower but cost effective for countries with lower bandwidth or lower storage options. Sometimes Android after updating the OS, triggers these kinds of processing of linking dynamic dependency chains in the background. `Preparing android system` message in your notifications. -Xbox on the other hand provides both options for game developers to push updates. Microsoft always was great back from the Windows 2000 ME, and XP editions with service packs v1, 2 and 3 for major OS updates as well keeping up security updates in a manageable fashion. Back when OTA (Over the Air) updates weren't the norm. Remember you had to use 3 - 5 Floppy disks to install an OS. Now even though you have installed the OS, there are still day one patches for new OS. Thus leading to SaaS (Software as a service) model. They can defer prioritization and just ship things when its important to beat the market. + +Xbox on the other hand provides both options for game developers to push updates. Microsoft always was great back from the Windows 2000 ME, and XP editions with service packs v1, 2 and 3 for major OS updates as well keeping up security updates in a manageable fashion. Back when OTA (Over the Air) updates weren't the norm. Remember you had to use 3 - 5 Floppy disks to install an OS. Now even though you have installed the OS, there are still day one patches for new OS. Thus leading to SaaS (Software as a service) model. + +They can defer prioritization and just ship things when its important to beat the market. + One could argue that this leads to poor software quality but others mention that software needs to be soft easily adaptable and following latest patterns or security mechanisms. So having SaaS is a boon for lot of less maintenance. -As a fellow engineer, the code I wrote yesterday is already obsolete and the code I'm writing is also in the same phase. So updates are good if done in a timely fashion and not too much force updates. Auto updates are also cool. \ No newline at end of file +As a fellow engineer, the code I wrote yesterday is already obsolete and the code I'm writing is also in the same phase. So updates are good if done in a timely fashion and not too much force updates. Auto updates are also cool. + + +## Other + +ABI - consideration \ No newline at end of file diff --git a/architecture/system_designs.md b/architecture/system_designs.md index 9dfdd558..0fcc0095 100644 --- a/architecture/system_designs.md +++ b/architecture/system_designs.md @@ -1,2 +1,4 @@ -System Designs +# System Designs + +WIP \ No newline at end of file diff --git a/ios/combine/ReadMe_combine.md b/ios/combine/ReadMe_combine.md index 36a2ee5d..d208558c 100644 --- a/ios/combine/ReadMe_combine.md +++ b/ios/combine/ReadMe_combine.md @@ -4,7 +4,6 @@ [problem_solving](problem_solving.md) - [assign](assign.md) [publisher](publisher.md) diff --git a/ios/concurrency/GCD.md b/ios/concurrency/GCD.md index e69de29b..ab3caaf6 100644 --- a/ios/concurrency/GCD.md +++ b/ios/concurrency/GCD.md @@ -0,0 +1,37 @@ + +# GCD + +## Intro + +Every queue is always First In First Out (FIFO) order. +The queue itself could be on main thread or background thread with varying Quality of services. + +Refer `Main thread` [dispatch_main](dispatch_main.md) +Refer Background threads [dispatch_global](dispatch_global.md) + +## low-level C-based API. +NSOperation and NSOperationQueue are Objective-C classes. +NSOperationQueue is objective C wrapper over GCD. If you are using NSOperation, then you are implicitly using Grand Central Dispatch. + +### Advantages + +GCD advantage over NSOperation: +- implementation +For GCD implementation is very light-weight +NSOperationQueue is complex and heavy-weight + +### Main thread +```swift +DispatchQueue.main.async { + self.tableView.reloadData() +} +``` +### Background Threads +```swift +DispatchQueue.global(qos: .background).async { + doSomething() +} +``` + + + diff --git a/ios/concurrency/Readme_concurrency.md b/ios/concurrency/Readme_concurrency.md index 9f0802eb..4e0aec37 100644 --- a/ios/concurrency/Readme_concurrency.md +++ b/ios/concurrency/Readme_concurrency.md @@ -1,25 +1,39 @@ - - +# Concurrency ## 10000 Ft level explaination -[concurrency](architecture/concurrency.md) +If you want to get a refresher of basic concurrency concepts please read through the [concurrency](architecture/concurrency.md) file. As this specifically discusses on Swift iOS / Apple SDK implementation code snippets. -## Note: WIP ## List [actors](actors.md) +[asyncAwait](asyncAwait.md) + +[asyncLet](asyncLet.md) + +[asyncTaskGroup](asyncTaskGroup.md) + [background_tasks](background_tasks.md) -[dispatch_main](dispatch_main.md) +[dispatch_barrier](dispatch_barrier.md) + +[dispatch_global](dispatch_global.md) [dispatch_group](dispatch_group.md) -[dispatch_global](dispatch_global.md) +[dispatch_main](dispatch_main.md) + +[dispatch_queue](dispatch_queue.md) + +[dispatch_semaphore](dispatch_semaphore.md) + +[dispatch_work_item](dispatch_work_item.md) [GCD](GCD.md) [operations](operations.md) -[thread_concurrency](thread_concurrency.md) +[tasks](tasks.md) + +[thread](thread.md) diff --git a/ios/concurrency/actors.md b/ios/concurrency/actors.md index 8ac7c946..cdcc3e89 100644 --- a/ios/concurrency/actors.md +++ b/ios/concurrency/actors.md @@ -1,8 +1,16 @@ +# Actors + +## Intro Reference type. Single threaded. Much better solution than relying on classes for concurrency. +## New Kid on the Block + +Reference type just like `Class` and `function` but it guarantees exclusive access to its execution environment with independent threads. Of course it does have to maintain references and the `reference` type checks and all that goody / baddy stuff for updating states across all the layers whenever something changes due to it inherently being of `reference` type but still great for Swift concurrency manifesto and not worrying about one more extra thing. + +SwiftUI `ObservableObject` conforming classes can be marked with `@MainActor` and it just works like magic. ## Swift UI diff --git a/ios/concurrency/asyncAwait.md b/ios/concurrency/asyncAwait.md new file mode 100644 index 00000000..ad2a2b7a --- /dev/null +++ b/ios/concurrency/asyncAwait.md @@ -0,0 +1,9 @@ + + +## Code + +Swift Concurrency Manifesto + +```swift +let (data, response) =  try await URLSession.shared.data(from: URL(string: "website.com")!) +``` diff --git a/ios/concurrency/asyncLet.md b/ios/concurrency/asyncLet.md new file mode 100644 index 00000000..6fce5fba --- /dev/null +++ b/ios/concurrency/asyncLet.md @@ -0,0 +1,34 @@ + + +# Async Let + +Important for kicking off new tasks and not waiting for async tasks to complete and then move to next line of code like a imperative programming paradigm. +You can utilize `async let` for kicking off request + +```swift +async let doSomethingAsync() +``` + +Not await for all those asynchronous tasks. +```swift +try await [do_some_tasks] +``` + +Full code for easier consumption of a task. + +Requires iOS 13 I believe since Swift concurrency manifesto is part of certain OS minimum version requirements. Of course Xcode is smart enough to let us know if we need to add those `@available` tags. +## Code + +```swift +var imagesAsync: [UIImage] = [] +func fetchDataAsync() { + async let (imageData0, _) = try URLSession.shared.data(from: URL(string: imagesArr[0])!) + async let (imageData1, _) = try URLSession.shared.data(from: URL(string: imagesArr[1])!) + async let (imageData2, _) = try URLSession.shared.data(from: URL(string: imagesArr[2])!) + async let (imageData3, _) = try URLSession.shared.data(from: URL(string: imagesArr[3])!) + async let (imageData4, _) = try URLSession.shared.data(from: URL(string: imagesArr[4])!) + + imagesAsync.append(contentsOf: try await [imageData0, imageData1,imageData2,imageData3]) +} + +``` \ No newline at end of file diff --git a/ios/concurrency/asyncTaskGroup.md b/ios/concurrency/asyncTaskGroup.md new file mode 100644 index 00000000..489a711d --- /dev/null +++ b/ios/concurrency/asyncTaskGroup.md @@ -0,0 +1,70 @@ + + +# Async TaskGroup + +Important for kicking off new tasks and not waiting for async tasks to complete and then move to next line of code like a imperative programming paradigm. +You can utilize `async let` for kicking off request + +For TaskGroup with throwing tasks. +```swift +withThrowingTaskGroup(of: Type.self) +``` + +Add these async tasks to the execution scheduler `group: TaskGroup`. +```swift +group.addTask { + try await doSomeAsyncTask() +} +``` +Usually good idea to iterate over the array of data to pull concurrent tasks which are not dependent on each other and are mutually exclusive. + +## Code + +Full code for easier consumption of a task. + +```swift +func fetchImagesTaskGroup() async { + if let images = try? await fetchImagesAsyncTaskGroup() { + self.imagesAsyncGroup.append(contentsOf: images) + } +} + +func fetchImagesAsyncTaskGroup() async throws -> [UIImage] { + return try await withThrowingTaskGroup(of: UIImage?.self) { [weak self] group in + guard let self = self else { throw error } + var images: [UIImage] = [] + images.reserveCapacity(imagesArr.count) + for imageURL in imagesArr { + group.addTask { + try await self.fetchSingleImage(url: imageURL) + } + } + + for try await image in group { + if let image = image { images.append(image) } + } + return images + } +} + +func fetchSingleImage(url: String) async throws -> UIImage { + guard let url = URL(string: url) else { throw URLError(.badURL) } + let (data, _) = try await URLSession.shared.data(from: url) + guard let image = UIImage(data: data) else { throw error } + return image +} + +``` + + + +## Failing task in multiple tasks + +You can also utilize optionals for your `Type` when we want to still proceed with running asynchronous tasks results. + +Like `Type?.self` to denote that out of `n` network request one can fail and you don't want that failure to interrupt or infinitely wait out for getting results or fire more chain events dependent on a result. Swift strictly typed language gives us a way to properly harness that with defining optionality. Adhering internally to `ExpressibleByNil` protocol. + +```swift +withThrowingTaskGroup(of: CustomModel?.self) +``` + diff --git a/ios/concurrency/background_tasks.md b/ios/concurrency/background_tasks.md index 402fe0b6..881b33f7 100644 --- a/ios/concurrency/background_tasks.md +++ b/ios/concurrency/background_tasks.md @@ -6,7 +6,7 @@ [Adding iOS 13 background task features](https://www.spaceotechnologies.com/ios-background-task-framework-app-update/) - +## Resources [Perform background fetch](https://delphiworlds.com/2016/06/performing-background-fetches-ios/) [Apple WWDC](https://developer.apple.com/videos/play/wwdc2019/707/) \ No newline at end of file diff --git a/ios/concurrency/dispatch_barrier.md b/ios/concurrency/dispatch_barrier.md new file mode 100644 index 00000000..1d0d9dd8 --- /dev/null +++ b/ios/concurrency/dispatch_barrier.md @@ -0,0 +1,14 @@ + +## Code + +```swift +// Normal Concurrent Queue +let customQueue = DispatchQueue(label: "com.sensehack.kautilya", attributes: .concurrent) + +customQueue.async(flags: .barrier) { + doSomething() +} + +``` + +Flag: `barrier` is being set to signal the executioner that this part of async block of code is critical and you need have a barrier in place in order to not make unexpected behavior and only execute it if it has exclusive access. diff --git a/ios/concurrency/dispatch_global.md b/ios/concurrency/dispatch_global.md index 13cfb591..ba88b25c 100644 --- a/ios/concurrency/dispatch_global.md +++ b/ios/concurrency/dispatch_global.md @@ -4,3 +4,10 @@ Only `Main` is the main thread which is kept for UI and `DispatchQueue.main` QOS parameter. +5 different Quality of Service options + +```swift +DispatchQueue.global().async { + doSomething() +} +``` \ No newline at end of file diff --git a/ios/concurrency/dispatch_group.md b/ios/concurrency/dispatch_group.md index 90a756a1..32e62d8b 100644 --- a/ios/concurrency/dispatch_group.md +++ b/ios/concurrency/dispatch_group.md @@ -1,8 +1,22 @@ + +# Dispatch Group + +## Creation + ```swift let group = DispatchGroup() +``` + + +## Usage + +Enter and Leave group for every tasks. +Different tasks can `enter` and after their completion can `leave`. + +```swift // 1 -group.enter() // Different tasks can enter +group.enter() group.leave() // 2 group.enter() @@ -10,9 +24,16 @@ group.leave() // 3 group.enter() group.leave() +``` -// This will only get called when all the 3 groups have leave. -group.notify(queue: .main, execute: { +## Completion of Group tasks + +This will only get called when all the 3 or `n` groups have left. +Queue to listen is also important, to receive notification on `main thread` and then execute is block operation doing tasks in that closure chunk. +```swift +group.notify(queue: .main, execute: { + doSomethingAfterCompletingChildGroupTasks() }) -``` \ No newline at end of file +``` + diff --git a/ios/concurrency/dispatch_main.md b/ios/concurrency/dispatch_main.md index f93c4d75..f32367c3 100644 --- a/ios/concurrency/dispatch_main.md +++ b/ios/concurrency/dispatch_main.md @@ -1,9 +1,45 @@ +# Dispatch Main +## Info -Serial Queue but async execution +Serial Queue but async execution if `async` is being used. Usually the prefered option. +Usually needed for the system to switch threads +eg. Network call -> Background thread +-> Jump/Transit to Main thread for UI updation tasks. +## UIKit ```swift -DispatchQueue.main.async { - self.tableView.reloadData() +DispatchQueue.main.async { + self.tableView.reloadData() +} +``` + + +## Combine +```swift +.receive(on: Runloop.main) + +.receive(on: Main.asyncInstance) +``` + +## RxSwift + +```swift +.subscribeOn(MainScheduler.instance) +``` + +## SwiftUI + +```swift +@MainActor +class CustomClass: ObservableObject { + @Published var data: [Data] = [] + + init() { fetchData() } + + func fetchData() { + + data = await URLSession.shared.data(url: "https://sensehack.github.io/") + } } ``` diff --git a/ios/concurrency/dispatch_queue.md b/ios/concurrency/dispatch_queue.md new file mode 100644 index 00000000..0e8cd4a0 --- /dev/null +++ b/ios/concurrency/dispatch_queue.md @@ -0,0 +1,17 @@ +# Dispatch Queue + +## Intro + +Default is always Serial Queue, unless you pass an attribute `.concurrent` in its initializer. +Then you have a concurrent queue. + +## Code + +```swift +// Normal Concurrent Queue +let customQueue = DispatchQueue(label: "com.sensehack.kautilya", attributes: .concurrent) + +customQueue.async { + doSomething() +} +``` \ No newline at end of file diff --git a/ios/concurrency/dispatch_semaphore.md b/ios/concurrency/dispatch_semaphore.md new file mode 100644 index 00000000..ba8ce1f2 --- /dev/null +++ b/ios/concurrency/dispatch_semaphore.md @@ -0,0 +1,34 @@ + +# Dispatch Semaphore + +## Intro + +Semaphores are a way to place safeguards and fine control to make sure certain part of a code is manually flagged for getting exclusive access at a given time. +Dispatch_Barrier can achieve this but Semaphore gives you finer control on specifying where this conditions could be added and gives the OS or engineer more low level access for directing guard conditions at certain scenarios. + +Need: Sometimes only few lines of code are needed to be guarded or have exclusive access so in those times `Dispatch_barrier` would be an overkill specifically when the function is smaller. These kind of shortcomings could be solved using `functional programming` and having every independent unit of task defined as a task / function. And only limiting certain aspects for `semaphore.wait` and `sempahore.signal`. + +## Code + +### Initialization +```swift +// Init +let semaphore: DispatchSemaphore = DispatchSemaphore(value: 1) +``` + +## Toggle States + +Engaging +1 and disengaging -1 for the OS scheduler to take control of exclusion and make the right decision. +```swift +// Engage +semaphore.wait() + +// DisEngage +semaphore.signal() +``` + +## Quirks + +### Priority Inversion + +Where there are three tasks of different priorities `low, medium & high`. But when the execution happens the `high` priority is always waiting for the execution to happen for other 2 tasks. Thus the priority of a task not being honored. diff --git a/ios/concurrency/dispatch_work_item.md b/ios/concurrency/dispatch_work_item.md new file mode 100644 index 00000000..c5793e22 --- /dev/null +++ b/ios/concurrency/dispatch_work_item.md @@ -0,0 +1,3 @@ +# Dispatch Work Item + +WIP diff --git a/ios/concurrency/operations.md b/ios/concurrency/operations.md index 8e4a8068..5edb0b31 100644 --- a/ios/concurrency/operations.md +++ b/ios/concurrency/operations.md @@ -1,3 +1,4 @@ +# Operations ## Intro @@ -12,4 +13,39 @@ let mainQueue = OperationQueue.main let customQueue = OperationQueue() customQueue.maxConcurrentOperationCount = 30 -``` \ No newline at end of file +``` + +## Advantages + +NSOperation advantages over GCD: + +- Control On Operation +you can Pause, Cancel, Resume an NSOperation + +- Dependencies +you can set up a dependency between two NSOperations +operation will not started until all of its dependencies return true for finished. + +- State of Operation +can monitor the state of an operation or operation queue. ready ,executing or finished + +- Max Number of Operation +you can specify the maximum number of queued operations that can run simultaneously + + +## NSOperation + +Operation Queue + +When to Go for GCD or NSOperation +when you want more control over queue (all above mentioned) use NSOperation and for simple cases where you want less overhead (you just want to do some work "into the background" with very little additional work) use GCD + +### References +https://cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch/ http://iosinfopot.blogspot.in/2015/08/nsthread-vs-gcd-vs-nsoperationqueue.html +http://nshipster.com/nsoperation/ + + +[SO](https://stackoverflow.com/questions/10373331/nsoperation-vs-grand-central-dispatch) + +[Detailed code](http://www.knowstack.com/swift-3-1-concurrency-operation-queue-grand-central-dispatch/) + diff --git a/ios/concurrency/tasks.md b/ios/concurrency/tasks.md new file mode 100644 index 00000000..2d78bca8 --- /dev/null +++ b/ios/concurrency/tasks.md @@ -0,0 +1,35 @@ + +# Tasks + +## Intro + +Could be described as a single unit of work needed to be completed could be described as a task. +Don't confuse this with process, threads, CPU Core. + +Those are more of combination of multiple tasks -> Thread + +Multiple threads + resources -> Process + +Multiple threads could run on single core. + +Multiple processes could run on single core. + +## Context Switching + +CPU context switching happens using different time sharing / slicing algorithms and OS handles the priority of things to queue up to make sure efficient usage of limited resources at its disposal. + +Now the strategy for handling resources would differ by lot of factors. +Architecture CPU - arm, arm64, intelx86, amd64, RISC-V. +I/O - DDR2, 3, 4, LPDDR, SSD, Nand, eMMC, UFS, M.2 NVME, Hard Drives SATA 2, 3. +CPU Cache - L1, L2, L3 +ECC Memory +Hardware accelerators +Security Modules - TPM, Apple T1, T2 chips, Enterprise Encryption +OS security - Encryption, Hardware encryption. + +My point is Architecture isn't easy and there are lots of trade offs for every decision we make. + +One could prefer Windows, macOS (unix subsystem), Debian flavored Linux, LinuxSE, Ubuntu. +UI - KDE plasma, Gnome, Windows Start, MacOS Springboard / launchpad / dock. + +Btw I use `Arch` Linux. **r/linuxMasterRace** meme diff --git a/ios/concurrency/thread.md b/ios/concurrency/thread.md new file mode 100644 index 00000000..a33f3c80 --- /dev/null +++ b/ios/concurrency/thread.md @@ -0,0 +1,66 @@ +# Concurrency + +## Threads + + +## Dispatch Group + +[dispatch_global](dispatch_global.md) + +[Concurrency in iOS ](https://metova.com/concurrency-in-ios/) + + +## Dispatch Queue + +Concurrent or Singular Synchronous +[dispatch_queue](dispatch_queue.md) + +Main thread +[dispatch_main](dispatch_main.md) + +## Dispatch Work Item + +[dispatch_work_item](dispatch_work_item.md) + + +## Race Condition + + +[SO](https://stackoverflow.com/questions/34510/what-is-a-race-condition?rq=1) + +## Critical Section + +## Semaphores + +DispatchSemaphore +[dispatch_semaphore](dispatch_semaphore.md) + +## RxSwift + +Thread safety with Subjects + +https://swiftsimplified.medium.com/thread-safety-with-subjects-in-rxswift-2543495aa35e + +https://www.thedroidsonroids.com/blog/rxswift-examples-4-multithreading + + +## Learn + +More about race conditions and avoiding critical reads / writes sections in the memory at once. +Multithreading - checks for whether certain things needed to be checked for thread safety overall. +The interview basically asked me all the multithreaded questions which I didn't know an answer for. + + + + +## Good sources + +[Free code camp Concurrency](https://www.freecodecamp.org/news/ios-concurrency/) + +https://www.avanderlee.com/swift/async-await/ + +https://www.advancedswift.com/async-await/ + +https://medium.com/swlh/an-in-depth-guide-to-operation-and-operationqueue-45658a22ee37 + +https://www.appsloveworld.com/swift/100/174/using-dispatch-async-to-load-images-in-background \ No newline at end of file diff --git a/ios/concurrency/thread_concurrency.md b/ios/concurrency/thread_concurrency.md deleted file mode 100644 index 9079bcb7..00000000 --- a/ios/concurrency/thread_concurrency.md +++ /dev/null @@ -1,108 +0,0 @@ -# Concurrency - -If you want to get a refresher of basic concurrency concepts please read through the `os\architecture\concurrency.md` file. As this specifically discusses on Swift iOS / Apple SDK implementation code snippets. - -## Threads Concurrency - -## GCD is a low-level C-based API. -NSOperation and NSOperationQueue are Objective-C classes. -NSOperationQueue is objective C wrapper over GCD. If you are using NSOperation, then you are implicitly using Grand Central Dispatch. - -GCD advantage over NSOperation: -i. implementation -For GCD implementation is very light-weight -NSOperationQueue is complex and heavy-weight - -Main thread -```swift -DispatchQueue.main.async { - self.tableView.reloadData() -} - -DispatchQueue.global(qos: .background).async { - -} - -``` - -## NSOperation Operation Queue - -NSOperation advantages over GCD: - -i. Control On Operation -you can Pause, Cancel, Resume an NSOperation - -ii. Dependencies -you can set up a dependency between two NSOperations -operation will not started until all of its dependencies return true for finished. - -iii. State of Operation -can monitor the state of an operation or operation queue. ready ,executing or finished - -iv. Max Number of Operation -you can specify the maximum number of queued operations that can run simultaneously - -When to Go for GCD or NSOperation -when you want more control over queue (all above mentioned) use NSOperation and for simple cases where you want less overhead (you just want to do some work "into the background" with very little additional work) use GCD - -ref: -https://cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch/ http://iosinfopot.blogspot.in/2015/08/nsthread-vs-gcd-vs-nsoperationqueue.html -http://nshipster.com/nsoperation/ - - -[SO](https://stackoverflow.com/questions/10373331/nsoperation-vs-grand-central-dispatch) - -[Detailed code](http://www.knowstack.com/swift-3-1-concurrency-operation-queue-grand-central-dispatch/) - -## Operation Queue -Under the hood, it is implemented under GCD. - -Heavy lifting -Abstraction on top of Dispatch Queue - -```swift -let mainQueue = OperationQueue.main - -let customQueue = OperationQueue() -customQueue.maxConcurrentOperationCount = 30 -``` - - -## Dispatch Group - -[dispatch_global](dispatch_global.md) - - -[Concurrency in iOS ](https://metova.com/concurrency-in-ios/) - - - -## Race Condition - - -[SO](https://stackoverflow.com/questions/34510/what-is-a-race-condition?rq=1) - -## Semaphores - -DispatchSemaphore - -## Learn - -More about race conditions and avoiding critical reads / writes sections in the memory at once. -Multithreading - checks for whether certain things needed to be checked for thread safety overall. -The interview basically asked me all the multithreaded questions which I didn't know an answer for. - - - - -## Good sources - -[Free code camp Concurrency](https://www.freecodecamp.org/news/ios-concurrency/) - -https://www.avanderlee.com/swift/async-await/ - -https://www.advancedswift.com/async-await/ - -https://medium.com/swlh/an-in-depth-guide-to-operation-and-operationqueue-45658a22ee37 - -https://www.appsloveworld.com/swift/100/174/using-dispatch-async-to-load-images-in-background \ No newline at end of file diff --git a/ios/lifecycle/README_lifecycle.md b/ios/lifecycle/README_lifecycle.md index 545b3222..13d9f5c0 100644 --- a/ios/lifecycle/README_lifecycle.md +++ b/ios/lifecycle/README_lifecycle.md @@ -38,7 +38,7 @@ [[swift_types]] -[[thread_concurrency]] +[[thread]] [[lifecycle/timer]] diff --git a/ios/swiftUI/MVVM_example.md b/ios/swiftUI/MVVM_example.md index eff525a6..4976031a 100644 --- a/ios/swiftUI/MVVM_example.md +++ b/ios/swiftUI/MVVM_example.md @@ -59,4 +59,35 @@ public func fetchData(url: String, id: Int? = nil, type: T.Type) a         }         return decodedData     } -``` \ No newline at end of file +``` + + +## Passing StateObject to Extracted View + +Utilize @ObservedObject for passing ViewModel ref in extracted views. + +```swift +struct ContentView: View { +    @StateObject var vm = ViewModel() + var body { + ExtractedView(vm: vm) + } +} + +struct ExtractedView: View { + @ObservedObject var vm: ImageNetwork + + // do something + VStack { + Text(vm.fetchText()) + } +} +``` + +Passing Data between Views in SwiftUI +https://www.createwithswift.com/tutorial-passing-data-between-views-in-swiftui-using-state-and-binding/ + +https://www.swiftdevjournal.com/passing-data-to-swiftui-views/ + +Pass `@StateObject` data in views. +https://www.hackingwithswift.com/books/ios-swiftui/sharing-swiftui-state-with-stateobject \ No newline at end of file diff --git a/ios/swiftUI/Readme_swiftUI.md b/ios/swiftUI/Readme_swiftUI.md index 0bb28a05..e45d29c3 100644 --- a/ios/swiftUI/Readme_swiftUI.md +++ b/ios/swiftUI/Readme_swiftUI.md @@ -12,6 +12,8 @@ [list](list.md) +[MVVM_example](MVVM_example.md) + [scrollView](scrollView.md) [stack](stack.md) diff --git a/ios/swiftUI/list.md b/ios/swiftUI/list.md index b28b04f6..31766bb9 100644 --- a/ios/swiftUI/list.md +++ b/ios/swiftUI/list.md @@ -1,3 +1,21 @@ +Table equivalent of UIKit in swiftUI + + + + +## Grids + +Recently introduced in iOS 16. +More robust and available easily. + + +Sources: +https://swiftui-lab.com/impossible-grids/ + +https://sarunw.com/posts/swiftui-grid/ + + + diff --git a/ios/test/README_test.md b/ios/test/README_test.md index cd7c070a..9969dc2e 100644 --- a/ios/test/README_test.md +++ b/ios/test/README_test.md @@ -10,16 +10,14 @@ [[mocks]] +[names](names.md) + [[parametrized_unit_tests]] [[stubs]] -[[XCTest]] - -[names](names.md) - [test](test.md) [rx_tests](rx_tests.md) -[mock](mock.md) \ No newline at end of file +[[XCTest]] \ No newline at end of file diff --git a/ios/ui/README_ui.md b/ios/ui/README_ui.md index 3f470435..eedd46e2 100644 --- a/ios/ui/README_ui.md +++ b/ios/ui/README_ui.md @@ -5,6 +5,7 @@ [[auto_layout]] + [[checkbox]] [[constraints]] @@ -23,7 +24,7 @@ [[transitions]] -[[uiImagePicker]] +[uiAppearance](uiAppearance.md) [[uibutton]] @@ -35,6 +36,8 @@ [[uilabel]] +[uiPageController](uiPageController.md) + [[uiscrollview]] [[uistackview]] @@ -45,8 +48,5 @@ [[uiview]] -[[uiAppearance]] - [uiViewController](uiViewController.md) -[uiPageController](uiPageController.md) \ No newline at end of file