Saturday, December 10, 2022

WWDC 2022 Video Sessions

Last June, Apple hosted WWDC 2022 at its headquarters. Video sessions, from June 7 to 10, are available at the Apple developer site. As usual, I watched those videos in the past few months. Now I've finished watching all of them.

The following are videos I watched.

Monday

  1. Apple Design Awards
  2. Keynote
  3. Platforms State of the Union
  4. WWDC22 Day 1 recap

Tuesday

  1. Add accessibility to your Unity games
  2. Adopt Variable Color in SF Symbols
  3. Adopt desktop-class editing interactions
  4. Bring Continuity Camera to your macOS app
  5. Bring your driver to iPad with DriverKit
  6. Bring your world into augmented reality
  7. Build your first app in Swift Playgrounds
  8. Capture machine-readable codes and text with VisionKit
  9. Complications and widgets: Reloaded
  10. Create a more responsive media app
  11. Create macOS or Linux virtual machines
  12. Create parametric 3D room scans with RoomPlan
  13. Deliver reliable streams with HLS Content Steering
  14. Discover Metal 3
  15. Dive into App Intents
  16. Enhance collaboration experiences with Messages
  17. Explore more content with MusicKit
  18. Get more mileage out of your app with CarPlay
  19. Get the most out of Xcode Cloud
  20. Get timely alerts from Bluetooth devices on watchOS
  21. Get to know Create ML Components
  22. Get to know Developer Mode
  23. Hello Swift Charts
  24. Implement App Shortcuts with App Intents
  25. Load resources faster with Metal 3
  26. Meet Apple Maps Server APIs
  27. Meet Focus filters
  28. Meet Swift Async Algorithms
  29. Meet Swift Regex
  30. Meet WeatherKit
  31. Meet Web Push for Safari
  32. Meet desktop-class iPad
  33. Meet passkeys
  34. Plug-in and play: Add Apple frameworks to your Unity game projects
  35. Program Metal in C++ with metal-cpp
  36. Qualities of great AR experiences
  37. The SwiftUI cookbook for navigation
  38. Visualize and optimize Swift concurrency
  39. Day 2 recap
  40. What's new in App Clips
  41. What's new in AppKit
  42. What's new in Create ML
  43. What's new in Nearby Interaction
  44. What's new in SF Symbols 4
  45. What's new in Safari and WebKit
  46. What's new in SharePlay
  47. What's new in Swift
  48. What's new in SwiftUI
  49. What's new in UIKit
  50. What's new in Xcode
  51. What's new in managing Apple devices
  52. What's new with in-app purchase
  53. What’s new in notarization for Mac apps

Wednesday

  1. Add Live Text interaction to your app
  2. Add Shared with You to your app
  3. Adopt declarative device management
  4. Boost performance with MetalFX Upscaling
  5. Bring your iOS app to the Mac
  6. Build a desktop-class iPad app
  7. Build a productivity app for Apple Watch
  8. Build global apps: Localization by example
  9. Compose advanced models with Create ML Components
  10. Compose custom layouts with SwiftUI
  11. Create engaging content for Swift Playgrounds
  12. Create your Privacy Nutrition Label
  13. Design App Shortcuts
  14. Design an effective chart
  15. Design app experiences with charts
  16. Discover advancements in iOS camera capture: Depth, focus, and multitasking
  17. Display ads and interstitials in SharePlay
  18. Eliminate data races using Swift Concurrency
  19. Embrace Swift generics
  20. Explore EDR on iOS
  21. Explore in-app purchase integration and migration
  22. Improve the discoverability of your Swift-DocC content
  23. Integrate your custom collaboration app with Messages
  24. Link fast: Improve build and launch times
  25. Meet Apple Music API and MusicKit
  26. Meet Background Assets
  27. Meet CKTool JS
  28. Meet ScreenCaptureKit
  29. Meet Transferable
  30. Meet distributed actors in Swift
  31. Meet the expanded San Francisco font family
  32. Optimize your Core ML usage
  33. Optimize your use of Core Data and CloudKit
  34. Replace CAPTCHAs with Private Access Tokens
  35. Streamline local authorization flows
  36. Support multiple users in tvOS apps
  37. Swift Regex: Beyond the basics
  38. Take ScreenCaptureKit to the next level
  39. Target and optimize GPU binaries with Metal 3
  40. Understand USD fundamentals
  41. Use Xcode to develop a multiplatform app
  42. WWDC22 Day 3 recap
  43. What's new in HealthKit
  44. What's new in Swift-DocC
  45. What's new with SKAdNetwork
  46. What’s new in AVQT
  47. What’s new in CloudKit Console
  48. What’s new in Endpoint Security
  49. What’s new in Safari Web Extensions
  50. What’s new in Wallet and Apple Pay
  51. What’s new in iPad app design
  52. What’s new in privacy

Thursday

  1. Create Safari Web Inspector Extensions
  2. Create Safari Web Inspector Extensions
  3. Create a great video playback experience
  4. Create camera extensions with Core Media IO
  5. Debug Swift debugging with LLDB
  6. Deep dive into Xcode Cloud for teams
  7. Demystify parallelization in Xcode builds
  8. Design for Arabic
  9. Design for Collaboration with Messages
  10. Design protocol interfaces in Swift
  11. Discover ARKit 6
  12. Discover PhotoKit change history
  13. Discover Sign in with Apple at Work & School
  14. Display EDR content with Core Image, Metal, and SwiftUI
  15. Display HDR video in EDR with AVFoundation and Metal
  16. Enhance your Sign in with Apple experience
  17. Evolve your Core Data schema
  18. Explore App Tracking Transparency
  19. Explore Apple Business Essentials
  20. Get it right(to left)
  21. Go bindless with Metal 3
  22. Go further with Complications in WidgetKit
  23. Improve app size and runtime performance
  24. Make a great SharePlay experience
  25. Maximize your Metal ray tracing performance
  26. Meet Swift Package plugins
  27. Reach new players with Game Center dashboard
  28. Reduce networking delays for a more responsive app
  29. Simplify C++ templates with concepts
  30. SwiftUI on iPad: Add toolbars, titles, and more
  31. SwiftUI on iPad: Organize your interface
  32. The craft of SwiftUI API design: Progressive disclosure
  33. Track down hangs with Xcode and on-device detection
  34. Transform your geometry with Metal mesh shaders
  35. Use SwiftUI with AppKit
  36. Use SwiftUI with UIKit
  37. WWDC22 Day 4 recap
  38. What's new in App Store Connect
  39. What's new in MapKit
  40. What's new in StoreKit testing
  41. What's new in TextKit and text views
  42. What's new in Vision
  43. What's new in the Photos picker
  44. What's new in web accessibility
  45. What’s new in HLS Interstitials
  46. Writing for interfaces

Friday

  1. Accelerate machine learning with Metal
  2. Author fast and reliable tests for Xcode Cloud
  3. Bring multiple windows to your SwiftUI app
  4. Build device-to-device interactions with Network Framework
  5. Create Swift Package plugins
  6. Create accessible Single App Mode experiences
  7. Create custom catalogs at scale with ShazamKit
  8. Discover Benchmarks in App Analytics
  9. Discover Managed Device Attestation
  10. Efficiency awaits: Background tasks in SwiftUI
  11. Explore SMS message filters
  12. Explore media metadata publishing and playback interactions
  13. Explore the machine learning development experience
  14. Implement proactive in-app purchase restore
  15. Improve DNS security for apps and servers
  16. Power down: Improve battery consumption
  17. Profile and optimize your game's memory
  18. Scale compute workloads across Apple GPUs
  19. Use Xcode for server-side development
  20. WWDC22 Day 5 recap
  21. What's new in PDFKit
  22. What's new in Screen Time API
  23. What's new in WKWebView

References

Read More...

Saturday, September 03, 2022

Unselect cell in tableview if the cell is visible

I have an iOS app. The main screen has a tabbar on the bottom with three tab bar items. Here I'll explain two related tabs. One of them, the “export” tab, is for displaying objects in a tableview. It allows the user to make multiple selections. Another one, the "edit" tab, is for editing objects. If a user makes any changes to objects, any previously selected object items in the export tab will be cleared if the user switches back to the export tab.

Multiple Selection in Export View

In order to keep selected objects consistant, I created a class called SelcHelper to catch selected objects' indexPath. In ExportViewController, there is a function selectRow which is used to select or deselect a row in the table view.

  1. class ExportViewController:
  2.  BaseTableViewController // this is my base class on UITableViewController
  3. {
  4.  private var selHelp[er = SelHelper()
  5.  private func selectRow(
  6.    select: Bool,
  7.    tableView: UITableView,
  8.    at indexPath: IndexPath)
  9.  {
  10.    if select {
  11.      tableView.selectRow(
  12.        at: indexPath,
  13.        animated: true,
  14.        scrollPosition: .none)
  15.      } else {
  16.        tableView.deselectRow(
  17.          at: indexPath,
  18.          animated: true)
  19.      }
  20.  }
  21.  ...
  22. }

Here is how I implement multiple selection in tableview events:

  1. class ExportViewController:
  2.  BaseTableViewController // this is my base class on UITableViewController
  3. {
  4.  ...
  5.  func tableView(
  6.    _ tableView: UITableView,
  7.    didDeselectRowAt indexPath: IndexPath)
  8.  {
  9.    selHelper.remove(indexPath: indexPath)
  10.    tableView.reloadRows(at: [indexPath], with: .none)
  11.  }
  12.  ...
  13.  func tableView(
  14.    _ tableView: UITableView,
  15.    didSelectRowAt indexPath: IndexPath)
  16.  {
  17.    selHelper.add(indexPath: indexPath)
  18.    tableView.reloadRows(at: [indexPath], with: .none)
  19.  }
  20.  func tableView(
  21.    _ tableView: UITableView,
  22.    cellForRowAt indexPath: IndexPath)
  23.    -> UITableViewCell // cellForRow event
  24.  {
  25.    let cell = tableView.dequeueReusableCell(
  26.          withIdentifier: "cell")
  27.    ...
  28.    let isSelected =  selHelper.isIndexPathSelected(indexPath)
  29.    cell.isSelected = isSelected
  30.    selectRow(
  31.      select: isSelected,
  32.      tableView: tableView,
  33.      at: indexPath)
  34.    return cell
  35. }

The above codes work perfectly for multiple selections.

Users may edit objects in the "edit" tab view after they make some selections in the "export" view. As mentioned above, in the case of any objects changed, I want to clear all the selections in the "export" tab view. The following codes are added in the event of viewWillAppear to clear all the catched indexPath values.

  1. class ExportViewController:
  2.  BaseTableViewController // this is my base class on UITableViewController
  3. {
  4.  override open func viewWillAppear(
  5.    _ animated: Bool)
  6.  {
  7.    super.viewWillAppear(animated)
  8.    ...
  9.    if myDBModel.dataChanged
  10.    {
  11.      selHelper.clear() // clear all indexPath
  12.    }
  13.  }
  14.  ...
  15. }

The logic is very clear. In the event of viewWillAppear, if the datasource has any changes, I'll clear all the catched selection indexPath values. This clearance will guarantee the cellForRow call to set cells unselected. Since I use a core data source for my export tableview, the cells with objects changed and in the visible area will be called to reload the cell.

Problem for visible cells

However I found a problem. If the visible cells in the tableView have any selections, the selection marks are gone. I verified that the cellForRow event was called after the event of viewWillAppear and all the selected cells are set to unselected. There is a problem: the cells are still in a high-light status. This status causes the cell to not be selected or unselected again!

For example, here is a cell is selected:

I changed the datasource first, and then back to the export tabview. The viewWillAppear event is called and all selections are set to deselected. The visible cell looks like this: the selection check mark is gone, but it looks like it is still highlighted and cannot be selected again.

I could scroll the tableView to move those visible cells to an un-visible area and scroll back. They are back to their normal status: unselected and not hilighted. However, what if there are only a small number of objects and they cannot be moved out of the tableView? The user would be stuck with this frastration situation and not be able to make a selection again. The user has to kill the app and restart the app to get back to normal.

Found a Soltion!

I think that this situation might be a problem or bug in UIKit. I have been struggling to find a way to resolve the issue for days. After several days and various attempts, suddenly, one evening very late, I found a solution to resolve the issue!

The solution is actually very simple. What I need to do is to call my private function selectRow to clear all selection for the visible cells in the event of viewWillDisappear! This clearance is OK. If there were no data changes, the cellForRow would not be called. If there is any data change, the cached selection indexPath values are cleared in the event of viewWillAppear first, and then cellForRow will be called to deselect visible cells.

  1. class ExportViewController:
  2.  BaseTableViewController // this is my base class on UITableViewController
  3. {
  4.  ...
  5.  override func viewWillDisappear(_ animated: Bool)
  6.  {
  7.    super.viewWillDisappear(animated)
  8.    guard let ips = tableViewInBase.indexPathsForSelectedRows
  9.      else { return }
  10.    // deselect all select rows in tableview on exit
  11.    // this will guaranty selection works again on
  12.    // appearance!
  13.    for ip in ips {
  14.      selectRow(select: false,
  15.        tableView: tableViewInBase,
  16.        at: ip)
  17.      }
  18.    }
  19.  ...
  20. }

References

Read More...

Friday, August 19, 2022

iOS Core Data Database Update

The Core Data database is the most commonly used as a data store for iOS apps. Nobody could design the database once and never change it again. I occasionally need to make some changes or update my Core Data database.

When the database scheme is changed, for example, adding a new entity, removing an entity, or changing entity fields, how could such kinds of changes affect your app? Would your app users lose all the data if any changes are made?

If you don't set up your database correctly, you may cause users frustration or pain. Fortunately, Apple provides a very solid and complete core data framework to allow you to migrate database changes during your app's life time without losing any data. In most cases, you would not need to do anything in particular. In some cases, you may need to write some codes to update data since you know what should be done.

Here are some notes regarding this issue.

Set the Correct Core Data Store Options

For the time being, in iOS 10.*, a Core Data store is created and managed by means of NSPersistentContainer. At the time this container is created, some critical options have to be set so that future updates or changes will be migrated smoothly without losing data.

The following is an example of how to set up the container with important options. If you don't set those, any changes to the database store would cause data loss because of a totally new schema.


  1. let storeDesription = NSPersistentStoreDescription(url: url)
  2. storeDesription.shouldInferMappingModelAutomatically = true
  3. storeDesription.shouldMigrateStoreAutomatically = true
  4. container.persistentStoreDescriptions = [storeDesription]
  5. container.loadPersistentStores() {
  6.    (storeDescription, error) in
  7.    if let error = error as NSError? {
  8.        // Handle errors here
  9.    }
  10. }

Add a New Version of the Database

In Xcode 9.4, if you need to change your database schema, don't make the change directly to the database model. Instead, add a new version to your database model and make the new version the active model.

From the menu of Editor->Add Model Version...,



Accepting the recommended model name, a new model version will be added.


In the right-hand inspector, add a new model identifier and select the new version as the current model version.

In this way, you can carry the previous database schema as-it-is to the next new version and make changes to the new version.

In most cases, all your data will be kept in the new database without any loss. Even though you have to test your app after your update to make sure it will keep or present previous database data smoothly.

Add Your Customized Updates

If you need to update your data as you know what the changes are and how to set up data correctly, you can do it at your app startup time.

For example, here is my practice of updating data at the app delegate class:

  1. @UIApplicationMain
  2. class AppDelegate : UIResponder, UIApplicationDelegate {
  3.  func application(_ application: UIApplication,
  4.    didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
  5.    {
  6.       // Override point for customization after application launch.
  7.       MyUserDefaults.shared.setupDefaults()
  8.       AppDatabase.shared.updateDatabase()
  9.       return true
  10.    }
  11. ...
  12. }

I use UserDefaults, i.e., app settings, as a place to save app and database versions and load those versions at the app's startup time. Then in the updateDatabase() method, I'll check if the previous app and database versions are older than a given version. If so, then some updates will be made so that the data will be kept up to date. Here is my example case:

  1. class AppDatabase {
  2.  static var shared: AppDatabase {
  3.    struct local {
  4.      static let instance = AppDatabase()
  5.    }
  6.    return local.instance
  7.  }
  8.  func updateDatabase() {
  9.     guard VersionManager.shared.isOlderThan(.database_v1_2_0) else { return }
  10.     cleanUpDataBase()      // do some cleanup missed in old db
  11.     updateSortProperties() // set sort values for the new fields
  12.  }
  13.  ...
  14. }

References


Read More...

Friday, August 12, 2022

Building a Bridge between Swift and JS

This was a challenge for me to make Swift talk to JS or JS to Swift. I have been working on an iOS app for years. With so many years of practice, I think I am very good at a deep technical level. I have also done a lot of html and JS programming. What I know about JS is mainly based on what I need to do on my blog.

In my app updates, what I need to do is to provide some information to users about how to use the app. An HTML view is a good choice for this purpose. However, I encountered a challenge that some of the information HTML needs is actually available easily on the Swift side. How can I let JS make a request to Swift, and then Swift pass the requested information back to JS?

This is what I mean by a bridge between Swift and JS.

Working Environment

In my project, I use a simple ViewController with a WKWebView UI component. The class is a very simple one. In the viewDidLoad event, an html file will be loaded into WKWebView. The content defined in the html file will be displayed on the view screen.

  1. class MyWebViewController: UIViewController
  2. {
  3.   @IBOutlet weak var webView: WKWebView!
  4.   {
  5.     didSet {
  6.       setup() // Place 1: magic will be injected from here.
  7.     }
  8.   }
  9.   var htmlUrl: URL? = nil
  10.   override func viewDidLoad()
  11.   {
  12.      super.viewDidLoad()
  13.      guard let url = htmlUrl else { return }
  14.      webView.loadFileURL(
  15.            url
  16.            allowingReadAccessTo: url)
  17.      let request = URLRequest(url: url)
  18.      webView.load(request)
  19.   }
  20.    override func viewWillDisappear(_ animated: Bool)
  21.    {
  22.        super.viewWillDisappear(animated)
  23.        // Place 2: some codes to be added here.
  24.    }
  25. }

My html file contains information about how JS is loaded. Normally, a JS script file is defined in the head section. For example,

  1. <head>
  2.   <meta charset='UTF-8'/>
  3.   <!-- JS functions used in html  -->
  4.   <script type="text/javascript" src="../myScriptFile.js"></script>
  5.   ...
  6. </head>

As you can see from the above structure, I have a view controller with a web viewer, in Swift code to present html content. The JS files which will be referenced from html are in my project bundle. This is my working environment.

A Case Study

Here is my case. In my html content, there is one element for displaying my app version.

<h2 class="center">Version <span id="appVersion">to be filed</span></h2>

This could be easily done by using a JS function like this:

  1. function swift2JSCallFor(appVersion) {
  2.    let e = document.getElementById("appVersion");
  3.    e.innerHTML = appVersion;
  4. }

The version string can be easily obtained in Swift code. How can I make a call from Swift to this JS function with version information?

WKScriptMessageHandler as a Gateway

Fortunately, Apple provides an API for the case of my view controller with WKWebView. WKScriptMessageHandler is the name of this API. This handler protocol can be implemented as a message channel gateway between Swift and JS.

This gateway could be implemented in my view controller class. There are some codes required to set it up. The disadvantage of doing this in my view controller is that I would have to repeat a block of similar code again and again in other view controller classes if I needed to do a similar thing. Another point is that adding some codes just for this kind of gateway would pollute my view controller class and make it harder to read and maintain.

Build My Gateway Class

After my thorough study and tests of this framework and a good understanding of what is required, I decided to create a new class to encapsulate the business logic or structure outline inside my class and expose the necessary settings for customizing.

  1. import WebKit
  2. typealias ScriptMessageHandlerBlock =
  3.    ((WKUserContentController,
  4.      WKScriptMessage) -> ())
  5. class MyWKScriptBridgeHelper: NSObject
  6. {
  7.    init(
  8.        observer: String,
  9.        scriptMessageHandlerBlock: ScriptMessageHandlerBlock?
  10.    )
  11.    {
  12.        webObserver = observer
  13.        wKScriptMessageHandlerBlock = scriptMessageHandlerBlock
  14.    }
  15.    private var webObserver: String = ""
  16.    private var wKScriptMessageHandlerBlock:
  17.    ScriptMessageHandlerBlock? = nil
  18.    var webObserverName: String {
  19.        return webObserver
  20.    }
  21. }
  22. extension WKScriptMessageHandler: WKScriptMessageHandler
  23. {
  24.    func userContentController(
  25.        _ userContentController: WKUserContentController,
  26.        didReceive message: WKScriptMessage)
  27.    {
  28.        guard let block = wKScriptMessageHandlerBlock else
  29.        {
  30.            return
  31.        }
  32.        block(userContentController, message)
  33.    }
  34. }

The class logic is simple. Only two parameters are required to create an instance of this class. One is a webObserver name, which will be called from JS to Swift to the gateway implemented in this class. Another one is a block of code where Swift information will be gethered or prepared and JS functions will be called.

Set it up on the Swift Side

OK, so far so good. It is time to put it all together in practice!

In my view controller class, there are two places where I will put some code. The first place is to set up my gateway instance of the MyWKScriptBridgeHelper class.

  1. class MyViewController
  2. {
  3.  private var scriptHelper: MyWKScriptBridgeHelper!
  4.    ...
  5.  private func setup()
  6.  {
  7.    let webObserver = "appVersion"
  8.    let block: ScriptMessageHandlerBlock
  9.        = {
  10.            [weak self] (userController, message) in
  11.            guard let this = self else {
  12.                return
  13.            }
  14.            // Make sure that it is html js function callback
  15.            guard message.name ==
  16.                    webObserver else {
  17.                return
  18.            }
  19.            // get app version string
  20.            let v = ... // get app version
  21.            let jsFunc = String(
  22.                format: "swift2JSCallFor('%@')",
  23.                v)
  24.            // Sends back app version to hml js function
  25.            this.webView.evaluateJavaScript(
  26.                jsFunc,
  27.                completionHandler: nil)
  28.        }
  29.        scriptHelper = MyWKScriptBridgeHelper(
  30.            observer: webObserver,
  31.            scriptMessageHandlerBlock: block)
  32.  }
  33.  ...
  34. }

In this setup(), two parameters are prepared for creating the instance of MyWKScriptBridgeHelper. One is the name of "webObserver" as the message name of the gateway. Another one is the block to verify the right message is received, to prepare the app version, and finally call a JS function "swift2JSCallFor()" to send the app version to the JS side.

The second location is in the view controller disappear event, where you should perform some cleaning by removing any message handlers and deallocating scriptHelper to avoid memory leaks.

  1. override func viewWillDisappear(_ animated: Bool)
  2. {
  3.   super.viewWillDisappear(animated)
  4.   guard let sh = scriptHelper else { return }
  5.   // Clear message handler from script helper
  6.   webView.configuration.userContentController.removeScriptMessageHandler(
  7.       forName: sh.webObserverName)
  8.   scriptHelper = nil
  9. }

That's all I need to do to set my gateway up. First, the gateway will handle a message requesting the app version from the JS side. Then it will call a JS function to pass the app version to JS.

HTML and JS Configuration

On the html and JS side, the first step is to make a request to Swift for the app version. This can be done by calling a JS function on html body element's onload attribute.

  1. <body onload="updateVersion()">
  2. ...
  3. <h2 class="center">Version
  4. <span id="appVersion">to be updated...</span></h2>
  5. ...
  6. </body>

The second step is to set up Javascript functions to make a request and to handle Swift calls.

  1. function updateVersion()
  2. {
  3.  try {
  4.    var msg = {}; // for empty parameter, it has to be {}
  5.    // "appVersion" is the request message name on Swift side
  6.    window.webkit.messageHandlers.appVersion.postMessage(msg);
  7.  } catch(err) {}
  8. }
  9. // function to be called from Swift to pass app version
  10. // to JS.
  11. function swift2JSCallFor(appVersion) {
  12.  let e = document.getElementById("appVersion");
  13.  e.innerHTML = appVersion;
  14. }

The comment description in the Javascript explains everything. That's all. With the above configuration, Swift and JS can talk to each other and pass the required information as needed.

Here is a snapshot of my html view with the correct version updated. I am so happy that this update will be automatically done and I don't need to touch the html file in future updates.

I have a short summary at the conclusion of this blog. Swift-JS communication was new to me. I spent more than one week investigating and doing my tests. The above strategy is based on other resources (see references) and my effort. This is not the best and complete solution. I may miss something. Please leave comments and provide your better solutions. Critics are welcome.

References

Read More...

Tuesday, August 02, 2022

HTML Head Settings

Recently, I have been busy working on my iOS updates. One feature I want to add is to provide some information views in the app.

There are many ways to present information on display in an app. I could use a rich-text component or a text view with attributed strings. However, compared to HTML, I prefer to use a web viewer to display HTML content. The most recent update and recommended strategy by Apple is WKWebView. This component fully supports HTML5 features with extensive Apple support for iOS devices, such as dynamic text size, zooming and pinch support, accessibility support, and more.

ViewController With WKWebView

With the HTML strategy, I could use HTML to format my information content with css styles, images, and js scripts. The way it works is just like a web server/client fully functional environment. My project acts like a web server. I place all my HTML files, images, css files, and js files into groups. Add a view controller class with WKWebView as the main container.

  1. class MyHTML1ViewController: UIViewController {
  2.   private var webView: WKWebView!
  3.   var htmlFile: String = "" // default value, can be changed
  4.   override func viewDidLoad() {
  5.    super.viewDidLoad()
  6.    let url = Bundle.main.url(
  7.            forResource: htmlFile,
  8.            withExtension: "html")
  9.    let request = URLRequest(url: url)
  10.    webViewBase.load(request)
  11.  }
  12. ...
  13. }

Then an html file can be loaded into the view, and the content is displayed in a way similar to a web browser.

Localization

In my project, Xcode provides support for localization. All HTML files, image files, and css files can be localised based on language support in my project. Currently, I have 3 languages to support, plus a base. A total of 4 sets of files are automatically created for me in my project. Taking an HTML file as an example, 4 HTML files are created for each language, and they are placed into a subfolder named by its language identifier. The same is true for images and css files.

Here is a snapshot of my project for groups of HTML-supported files. I group them into js, css, images, and html group names.

As you can see, each localizable item has a list of supported languages. With this visual layout, I can easily pick a language file and do my translation work.

The file structure is very different from the visual view of the project. Actually, all files are in the same root folder of projects. It is really hard to find them if I want to open Finder to find a file. That's why I named all HTML-supported files with a prefix of html_.

Further investigation, I found that within my app main bundle, all HTML supported localizable files within the project are placed in subfolders by the name of language identifiers. In other words, in my app bundle, all localised files are placed in a subfolder named as the language identifier. For example, for English, "en.lproj" subfolder contains all localised files, including my HTML-supported files. One level up from language subfolders is the root path, where all none-localized files sit. For example, js files are at the root level.

As I present all this in the above pictures, I will try to explain my understanding of how web server/client works within my app project. This picture of file layout is the web server's path structure. When an html file is loaded into WKWebViewer, all related images and css files are in the same path as the html file. Up one level is the place where js files are located.

With this understanding, I can edit my html files to refer to other source files and components easily. WKWebView is something like a browser to present HTML content and let users review and interact with it. As a client, the viewer has knowledge about where to get those sources and components from my project. I call it a server.

Keep in mind, I integrated WKWebView views into my project is based on HTML support and functionality. However, my app, built by my project, does not provide any end points for external web clients to access. My app is a native iOS app running on an iOS device.

Duplication of Settings in the head Section

I have several HMTL files to be presented by a number of view controllers with WKWebView, currently about, information and setttings. There will be expanded to more, let's say n HTML contents. Four language sets are supported in my project, and might be increased to more, m languages supported. You can imagine that n x m HTML files are in my project.

One thing I realise is that within an HTML file, in the document.head section, there are many settings. For example, common and specific css source files, common and specific js libray files, and meta configuration for various settings such as view point. Some of them are the same or repeated in all HTML files.

I realised there would be a maintenance issue. If any of these common parts are changed, as I will find some interesting feature support, I have to edit all those HTML files to do just copy and paste work. Is there any better way to do the maintenance job? Actually, I had encountered some issues where I forgot to update some languages, and those language displays did not work in the way I expected.

Seeking Help from SO

StackOverflow is a community of IT programmers' participation network. There are many talented people there to support others with all kinds of questions. After struggling to find a solution, I posted my question there. I was hoping to get advice from talented people.

Before I posted my Q, I tried various ways, including using Swift within my project. There is one way to open an HMTL url from my project. Then I could do parameter replacement of the content of the HTML file as a string. However, I remembered that I tried this method before. I just could not change any files within my application bundle!

The short story is that I tried to use a plist file within my project to save some setting changes. No errors are thrown out when some new changes are saved to the plist file. However, when the settings were read out later, they were back to their original values. I had been struggling for days to find out why, and finally I found that the plist file in the project bondle cannot be changed!

I resolved the issue by copying the plist file to the application sandbox supported folder. The plist file can be edited and saved there. After that, I come to my explanation: it may be a security reason that files within the app bundle cannot be changed.

I could copy the HTML file to outside of the bondle path and make changes there. What about other HTML sources and library files? It just defeats the language support naturally provided by the iOS framework if I have to find out or identify which language is supported, and then copy all those files from specific language subfolders out.

I knew there is another way to load an HTML string directly into WKWebView. The string can be changed with a parameter replacement. This would display HTML content. However, the same issue comes back to me again. How about linking other sources and library files if I load the view with a string? No path information from the string

Since I am using HTML technology, naturally I should find a way in HTML or js to inject common head settings into my loading HTML file.

Partial Working Solution

Within about a day of my post, I got two answers. One is using js to inject common settings from a js function. I tried it immediately. It did not work at first.

When I went back to my Q, my Q was marked as [losed] by a senior member of SO. The reason is that my working environment was not explained clearly. More explanation is required.

With [losed] status, no more answers are allowed. This actually turns many people away. The only way I could ask for help and get attention was to update my Q and add comments. As you can see, I have done several updates, and the Q is quite lengthy. Anyway, I think I have done enough to clarify my Q on SO.

If you read my Q, you will see a solution in it. Based on the only post's answer with codes, I made some changes, and took the meta setting for charset out of my common settings. It works now in my project, just as I expected, to inject the common settings into the head section.

Even though my solution is working, I still have questions about it, and I would like to see if there is any other better solution or advice on this issue.

Since SO is a member participation and support community, I need to get some people's help to turn off the [close] status. What is required is to have 2 more requests at the link of reopen, at the end of my Q.

References

Read More...

Thursday, May 12, 2022

Update Block of Codes with VIM

Recently I have been working on my iOS app project. One thing I need to do is to update several blocks of codes in a code file. The update is to add directives #if...#endif to the matched block of codes. Those blocks of codes have very similar pattern:


  1. private func configureSearchControllerDelegates(_ sc: UISearchController)
  2. {
  3.    log.logMessage() {
  4.        return "configureSearchControllerDelegates"
  5.    }
  6.  ....
  7. }

The first thing is to find the matched block of codes. Use the following command:


\(\s*log.logMessage()\s*{\_.\{-}}\)

Here is the explaination

\( and \) is for grouping. Starting from spaces \s and then log.logMessage(), followed by many spaces till the char of {. After that many lines of any chars till the char of }. \_. is for multiple lines, and {-} for none-greedy match(matches 0 or more of the preceding atom, as few as possible).

In VIM, the matched codes are marked as red.


With above verification, it is time to add my desired directive codes around the matched block of codes. Here is the replacement command.

:%s/(\s*log.logMessage()\s*{\_.\{-}}\)/#if D_1\r\1\r#endif/

Here is the explaination

Replacing the matched codes: insert #if D_1 as the first line, then the matched codes as group by\1. Finally add the last line of #endif after the matched codes. \r is a line break.

Here is the replacement command in VIM:


and wallah is the result:

References

Read More...

Friday, March 18, 2022

Removing Duplicated Lines by VIM

Recently I have interest in GPS location coordinates. In my TapToCount-3W iOS app, there is a feature to record location information for each tap.

I have been puzzled by a scenarior for long time. For example, if I make several taps at same location, the GPS locations spead within a range, several tens of meters to meters apart, 30 meters or 8 meters as examples.

Further invetigation, I found that the decimal points of GPS coordinates are related to location accuracy. The more decical points are in coordindates, the more accuracy.

VIM is a powerful tool. The following is a real case of my invetigation and analysis of GPS coordindates by using VIM.

Export GPS Information

First, I have to get GPS location coordates from my app. I use the Export feature to share the result of cvs file to my mac.


Using Numbers to open the csv file. The tap information includes my sleep times between Dec 2018 to Mar 2022, 7484 lines of taps I made. From GPS coordinates, I see the decimal points up to 14 digits.

For example, here is a coordinate of latitue, longitue, and altitue value:
53.55404449631790,	-113.2990255394140,	692.3739891052250

Find Duplicate GPS Information

7484 lines are quite a lot of information. I need to find out if there is any duplicated information.

Use the following command to find duplicate coordinate information:
/\(T-\d\)\(.*\)\n\(.*\2\n)\+

Match pattern explaination: first group beginning with "T-" and a digit, then any charts (coordinates) as second group, new line, next or more lines of any charts followed by the matched second group (coordinates).

The result is as followings:


Remove Duplicate Coordinate Lines

With about search result, I can then proceed removing duplicate coordinate lines.

Use the following command to remove duplicate coordinate information:
:%s/\(T-\d\)\(.*\)\(\n.*\2\)\+/\1\2/

Replacement command explaination: replace the matched pattern (duplicate GPS coordinate lines with group 1 and group 2 defined in the matched pattern.

Analysis Results

With VIM search and replacement as a convenience and powerful tool, I can do my research and analysis on GPS coordinates collected in my TapToCount-3W app.

Using Numbers, I can get coordinate values with different decimal digits, and find out what duplicate coordinates.

7,485 Taps with GPS coordindates
Decimal
Places
Degrees
Duplicates
Unique
0
0
5246
2239
1
0.1
5245
2240
2
0.01
5245
2240
3
0.001
5222
2263
4
0.000 1
4711
2774
5
0.000 01
4638
2847
14
0.000 000 000
000 00
577
6908

Based on above analysis, I think that the best decimal points should 5, 4, or 3 places, with accuracy corespoinding to +/-0.555m, +/-5.55m, or +/-55.5m. This will reduce duplicate coordinates up to 68% to 70%.

By using VIM, I did further analysis. I export a group of taps from Jan 1, 2022 to now (Mar 19, 2022), which I know for certain that they(454 taps) were tapped at the same location. The following are 2 results: one with altitute into consideration and another with no altitute.

454 Taps with GPS coordindates and altitude
Decimal
Places
Degrees
Duplicates
Unique
0
0
444
10
1
0.1
444
10
2
0.01
444
10
3
0.001
442
12
4
0.000 1
255
199
5
0.000 01
434
20
14
0.000 000 000
000 00
444
10

454 Taps with GPS coordindates and NO altitude
Decimal
Places
Degrees
Duplicates
Unique
0
0
453
1
1
0.1
453
1
2
0.01
453
1
3
0.001
452
2
4
0.000 1
444
10
5
0.000 01
33
421
14
0.000 000 000
000 00
8
446

With above research results, they helps me better to understand GPS coordindate information, and to take better and effective strategies for updating my app freatures and interfaces for my app users.

References

Read More...

Friday, November 26, 2021

WWDC 2021 Videos

This year Apple continued its WWDC online. The second time of the conference videos are much better than the last year. Each one is about less than one hour right on the topic. I waited one month after its finish. In this way, the video list is stable and complete.

The following is the complete list I have watched.
  1. Add Intelligence to your widgets iOS, macOS Sep 11
  2. AR Quick Look, meet Object Capture iOS, macOS Sep 11
  3. ARC in Swift: Basics and beyond iOS, macOS, tvOS, watchOS Sep 11
  4. Accelerate machine learning with Metal Performance Shaders Graph iOS, macOS Sep 11
  5. Accelerate networking with HTTP/3 and QUIC iOS, macOS, tvOS, watchOS Sep 11
  6. Accessibility by design: An Apple Watch for everyone watchOS Sep 11
  7. Add rich graphics to your SwiftUI app iOS, macOS, tvOS, watchOS Sep 11
  8. Add support for Matter in your smart home app iOS Sep 11
  9. Adopt Quick Note iOS, macOS Sep 12
  10. Analyze HTTP traffic in Instruments iOS, macOS, tvOS, watchOS Sep 12
  11. Apple’s privacy pillars in focus iOS Sep 12
  12. Automate CloudKit tests with cktool and declarative schema iOS, macOS, tvOS, watchOS Sep 12
  13. Bring Core Data concurrency to Swift and SwiftUI iOS, macOS, tvOS, watchOS Sep 12
  14. Bring Recurring Leaderboards to your game iOS, macOS, tvOS Sep 13
  15. Bring accessibility to charts in our app iOS, macOS, tvOS, watchOS Sep 13
  16. Build Mail app extensions macOS Sep 13
  17. Build a research and care app, part 1: Setup onboarding iOS Sep 13
  18. Build a research and care app, part 2: Schedule tasks iOS Sep 13
  19. Build a research and care app, part 3: Visualize progress iOS Sep 13
  20. Build a workout app for Apple Watch watchOS Sep 13
  21. Build apps that share data through CloudKit and Core Data iOS, macOS tvOS, watchOS Sep 14
  22. Build custom experiences with Group Activities iOS, macOS, tvOS Sep 14
  23. Build dynamic iOS apps with the Create ML framework iOS Sep 14
  24. Build interactive tutorial using DocC iOS, macOS tvOS, watchOS Sep 14
  25. Build interfaces with style iOS, macOS Sep 14
  26. Build light and fast App Clips iOS Sep 14
  27. Capture and process ProRAW images iOS, macOS Sep 14
  28. Capture high-quality photos using view formats iOS, macOS Sep 15
  29. Classify hand poses and actions with Create ML iOS, macOS Sep 15
  30. Connect Bluetooth devices to Apple Watch watchOS Sep 15
  31. Coordinate media experiences with Group Activities iOS, macOS, tvOS Sep 15
  32. Coordinate media playback in Safari with Group Activities macOS Sep 15
  33. Craft search experiences in SwiftUI iOS, macOS, tvOS, watchOS Sep 15
  34. Create 3D models with Object Capture iOS, macOS Sep 15
  35. Create 3D workflows with USD iOS, macOS Sep 15
  36. Create accessible experiences for watchOS watchOS Sep 15
  37. Create audio drivers with DriverKit macOS Sep 16
  38. Create custom audio experiences with ShazamKit iOS, macOS, tvOS, watchOS Sep 16
  39. Create custom symbols iOS, macOS, tvOS, watchOS Sep 16
  40. Create image processing apps powered by Apple Silicon iOS, macOS Sep 16
  41. Cross reference content with the Apple Music API iOS macOS Sep 16
  42. Customize and resize sheets in UIKit macOS Sep 16
  43. Customize your advanced Code Cloud workflows iOS, macOS, tvOS, watchOS Sep 16
  44. Deliver a great playback experience on tvOS tvOS Sep 16
  45. Demystify SwiftUI iOS, macOS, tvOS, watchOS Sep 16
  46. Design for Group Activities iOS, macOS, tvOS Sep 16
  47. Design for Safari 15 iOS macOS Sep 16
  48. Design for spatial integration iOS watchOS Sep 17
  49. Design create actions for Shortcuts, Sir, and Suggestions iOS, macOS, watchOS Sep 17
  50. Detect and diagnose memory issues iOS, macOS Sep 17
  51. Detect bugs early with the static analyzer iOS, macOS, tvOS, watchOS Sep 17
  52. Detect people faces and poses using Vision iOS, macOS Sep 17
  53. Develop advanced web content iOS, macOS Sep 17
  54. Developer spotlight: Accessibility Sep 17
  55. Diagnose Power and Performance regressions in your app iOS, macOS Sep 17
  56. Diagnose unreliable code with test repetitions iOS, macOS, tyOS, watchOS Sep 17
  57. Direct and reflect focus in SwiftUI iOS, macOS, tvOS, watchOS Sep 17
  58. Discovery Metal debugging, profiling, and asset creation tools iOS, macOS, tvOS Sep 17
  59. Discover Web Inspector improvements iOS, macOS Sep 18
  60. Discover account-driven User Enrollment iOS, macOS Sep 18
  61. Discover and curate Swift Packages using Collections iOS, macOS, tvOS, watchOS Sep 18
  62. Discover breakpoint improvements iOS, macOS, tvOS, watchOS Sep 18
  63. Discover build-in sound classification in SoundAnalysis iOS, macOS, tvOS, watchOS Sep 18
  64. Discover compilation workflows in Metal iOS, macOS, tvOS Sep 18
  65. Discover concurrency in SwiftUI iOS, macOS, tvOS, watchOS Sep 18
  66. Discover geometry-aware audio with the Physical Audio Spatialization Engine (PHASE) iOS, macOS Sep 18
  67. Discover rolling clips with ReplayKit iOS, macOS, tvOS Sep 19
  68. Discoverable design iOS, macOS, tvOS, watchOS Sep 19
  69. Distribute apps in Xcode with cloud signing iOS, macOS, tvOS, watchOS Sep 19
  70. Dive into RealityKit2 iOS macOS Seep 19
  71. Donate intents and expand your app’s presence iOS, watchOS Sep 19
  72. Elevate your DocC documentation in Xcode iOS, macOS, tvOS, watchOS Sep 19
  73. Embrace Expected Failures in XCTest iOS, macOS, tvOS, watchOS Sep 19
  74. Enhance your app with Metal ray tracing iOS, macOS Sep 19
  75. Evaluate videos with the Advanced Video Quality Tool iOS, macOS, tvOS Sep 19
  76. Explore ARKit 5 iOS Sep 19
  77. Explore Core Image kernel improvements iOS, macOS Sep 19
  78. Explore Digital Crown , Trackpad, and iPad pointer automation iOS, macOS, tvOS, watchOS Sep 19
  79. Explore HDR rendering with EDR iOS, macOS Sep 19
  80. Explore HLS variants in AVFoundation iOS, macOS, tvOS, watchOS Sep 19
  81. Explore Nearby Interaction with third-party accessories iOS, macOS, tvOS, watchOS Sep 19
  82. Explore Safari Web Extension improvements iOS, macOS Sep 19
  83. Explore ShazamKit iOS, macOS, tvOS, watchOS Sep 19
  84. Explore UWB-based car keys iOS, macOS Sep 20
  85. Explore Verifiable Health Records iOS Sep 20
  86. Explore WKWebView additions iOS, macOS Sep 20
  87. Explore Xcode Cloud workflows iOS, macOS, tvOS, watchOS Sep 20
  88. Explore advanced project configuration in Xcode iOS, macOS, tvOS, watchOS Sep 20
  89. Explore advanced rendering with RealityKit 2 iOS, macOS Sep 20
  90. Explore bindless rendering in Metal iOS, macOS, tvOS Sep 20
  91. Explore dynamic pre-rolls and mid-rolls in HLS iOS, macOS, tvOS Sep 20
  92. Explore hybrid rendering with Metal ray tracing iOS, macOS Sep 20
  93. Explore low-latency video encoding with VideoToolbox iOS, macOS Sep 21
  94. Explore structured concurrency in Swift iOS, macOS, tvOS, watchOS Sep 21
  95. Explore the SF Symbols 3 app iOS, macOS, tvOS, watchOS Sep 21
  96. Explore the catalog with the Apple Music API iOS Sep 21
  97. Extract document data using Vision iOS, macOS Sep 21
  98. Faster and simpler notarization for Mac apps macOS Sep 21
  99. Focus on iPad keyboard navigation iOS Sep 21
  100. Get ready for iCloud Private Relay iOS, macOS, tvOS, watchOS Sep 21
  101. Get ready to optimize your App Store product page iOS Sep 21
  102. Host and automate your DocC documentation iOS, macOS, tvOS, watchOS Sep 21
  103. Immerse your app in spatial audio iOS, macOS, tvOS Sep 21
  104. Improve MDM assignment of Apps and Books iOS, macOS, tvOS Sep 22
  105. Improve access to Photos in your app iOS, macOS Sep 22
  106. Improve global streaming availability with HLS Content Steering iOS, macOS, tvOS Sep 22
  107. Keynote iOS, macOS, tvOS, watchOS
  108. Localize your SwiftUI app iOS, macOS, tvOS, watchOS Sep 22
  109. Make blazing fast lists and collection views macOS Sep 22
  110. Manage devices with Apple Configurator iOS, macOS Sep 22
  111. Manage in=-app purchases on your server iOS, macOS, tvOS Sep 23
  112. Manage software updates in your organization iOS, macOS Sep 23
  113. Measure health with motion iOS, macOS Sep 23
  114. Meditation for fidgety skeptics Sep 23
  115. Meet AsyncSequcence iOS, macOS, tvOS,watchOS Sep 23
  116. Meet ClassKit for file-based apps iOS Sep 23
  117. Meet DocC documentation in Xcode iOS, macOS, tvOS, watchOS Sep 23
  118. Meet Group Activities iOS, macOS, tvOS Sep 23
  119. Meet MusicKit for Swift iOS, macOS, tvOS watchOS Sep 23
  120. Meet Safari Web Extensions on iOS iOS, macOS Sep 23
  121. Meet Shortcuts for macOS iOS, macOS Sep 24
  122. Meet StoreKit 2 iOS, macOS, tvOS, watchOS Sep 25
  123. Meet TestFlight on Mac iOS, macOS, tvOS Sep 25
  124. Meet TextKit 2 iOS, macOS Sep 25
  125. Meet Xcode Cloud iOS, macOS, tvOS, watchOS Sep 25
  126. Meet async/await in Swift iOS, macOS, tvOS, watchOS Sep 26
  127. Meet declarative device management iOS, macOS Sep 26
  128. Meet in-app events on the App Store iOS, macOS, tvOS Sep 26
  129. Meet private-preserving ad attribution iOS, macOS Sep 26
  130. Meet the Location Button iOS, macOS, tvOS, watchOS Sep 26
  131. Meet the Screen Time API iOS Sep 26
  132. Meet the Swift Algorithms and Collections packages iOS, macOS, tvOS, watchOS Sep 27
  133. Meet the UIKit button system iOS, macOS, tvOS, watchOS Sep 27
  134. Mitigate fraud with App Attest and DeviceCheck iOS, macOS, tvOS Sep 27
  135. Move beyond passwords iOS, macOS Sep 27
  136. Optimize for 5G networks iOS Sep 27
  137. Optimize for variable refresh rate displays iOS, macOS Sep 27
  138. Optimize high-end games for Apple GPUs iOS, macOS, tvOS Sep 27
  139. Out of this world… on to Mars Sep 27
  140. Platforms State of the Union
  141. Practice audio haptic design iOS Sep 27
  142. Principles of great widgets iOS, macOS Sep 27
  143. Protect mutable state with Swift actors iOS, macOS, tvOS, watchOS Sep 27
  144. Qualities of a great Mac Catalyst app macOS Sep 29
  145. Qualities of great iPad and iPhone apps on Macs with M1 iOS, macOS Sep 30
  146. Reduce network delays for your app iOS, macOS, tvOS, watchOS Sep 30
  147. Review code and collaborate in Xcode iOS, macOS, tvOS, watchOS Sep 30
  148. SF Symbols in SwiftUI iOS, macOS, tvOS, watchOS Sep 30
  149. SF Symbols in UIKit and AppKit iOS, macOS, tvOS Sep 30
  150. Safeguard your accounts, promotions, and content iOS, macOS, tvOS, watchOS Sep 30
  151. Secure login with iCloud Keychain verification codes iOS, macOS Oct 1
  152. Send communication and Time Sensitive notifications iOS, macOS, watchOS Oct 2
  153. Showcase app data in Spotlight iOS, macOS Oct 2
  154. Simplify sign in for your tvOS apps tvOS Oct 2
  155. Streamline your localized strings iOS, macOS, tvOS, watchOS Oct 2
  156. Support Full Keyboard Access in our iOS app iOS Oct 2
  157. Support customers and handle refunds iOS, macOS, tvOS, watchOS Oct 2
  158. Swift concurrency: Behind the scenes iOS, macOS, tvOS, watchOS Oct 2
  159. Swift concurrency: Update a sample app iOS, macOS, tvOS, watchOS Oct 3
  160. Swift Accessibility: Beyond the basics iOS, macOS, tvOS, watchOS Oct 3
  161. SwiftUI on the Mac: Build the fundamentals macOS Oct 3
  162. SwiftUI on the Mac: The finishing touches macOS Oct 3
  163. Symbolication: Beyond the basics iOS, macOS, tvOS, watchOS Oct 3
  164. Sync files to the cloud with FileProvider on macOS macOS Oct 3
  165. Tailor the VoiceOver experience in your data-rich apps iOS, macOS Oct 4
  166. Take your iPad apps to the next level iOS Oct 4
  167. Tap into virtual and physical game controllers iOS, macOS, tvOS Oct 4
  168. The practice of inclusive design iOS, macOS, tvOS, watchOS Oct 4
  169. The process of inclusive design iOS, macOS, tvOS, watchOS Oct 4
  170. There and back again: Data transfer on Apple Watch watchOS Oct 4
  171. Transition media gaplessly with HLS iOS, macOS, tvOS Oct 4
  172. Triage TestFlight crashes in Xcode Organizer iOS, macOS, tvOS, watchOS Oct 4
  173. Tune your Core ML models iOS, macOS, tvOS, watchOS Oct 5
  174. Ultimate application performance survival guide iOS, macOS Oct 5
  175. Understand and eliminate hangs from your app iOS, macOS Oct 5
  176. Use Accelerate to improve performance and incorporate encrypted archives iOS, macOS, tvOS, watchOS Oct 5
  177. Use async/await with URLSession iOS, macOS, tvOS, watchOS Oct 5
  178. Use the camera for keyboard input in your app iOS Oct 5
  179. WWDC21 Apple Design Awards iOS, macOS, tvOS, watchOS Oct 5
  180. What’s n ew in AVKit iOS, macOS Oct 5
  181. What’s new in App Analytics iOS, macOS, tvOS, watchOS Oct 5
  182. What’s new in App Clips iOS Oct 5
  183. What’s new in AppKit macOS Oct 5
  184. What’s new in CloudKit iOS, macOS, tvOS, watchOS Oct 5
  185. What’s new in Foundation iOS, macOS, tvOS, watchOS Oct 6
  186. What’s new in Mac Catalyst macOS Oct 6
  187. What’s new in SwiftUI iOS, macOS, tvOS, watchOS Oct 6
  188. What’s new in UIKit iOS Oct 6
  189. What’s new in Wallet and Apple Pay iOS, macOS, tvOS, watchOS Oct 6
  190. What’s new in watchOS 8 watchOS Oct 6
  191. What’s new in Swift iOS, macOS, tvOS, watchOS Oct 6
  192. What’s new in AVFoundation iOS, macOS, tvOS, watchOS Oct 6
  193. What’s new in Game Center: Widgets, friends, and multiplayer improvements iOS, macOS, tvOS Oct 6
  194. What’s new in SF Symbols iOS, macOS, tvOS, watchOS Oct 6
  195. What’s n ewe in camera capture iOS, macOS Oct 7
  196. What’s new in managing Apple devices iOS, macOS Oct 7
  197. Write a DSL in Swift using result builders iOS, macOS, tvOS, watchOS Oct 7
  198. Your guide to keyboard layout iOS Oct 7

References

  • WWDC 21

Read More...

Friday, September 25, 2020

Xcode 12.0 and ToolChain Error

I updated my Xcode two days ago. After the update, I got a warning error about ToolChain failure: 

/Library/Developer/Toolchains/swift-2.2-SNAPSHOT-2015-12-10-a.xctoolchain:1:1: failed to load toolchain: 'Version' parse error: Could not parse version component from: 'swift-2'

There is no further explanation about this error in Xcode. After Google search, I found one solution. It seems that it is caused by Xcode missing remove it when I did Xcode update.


As in the suggestion, the tool chain has to be removed from /Library/Developer/ToolChain/. In my case, there are two items in the direct:

$ ls
swift-2.2-SNAPSHOT-2015-12-10-a.xctoolchain
swift-latest.xctoolchain

The first one is a directry, and the second is a link to the directory. For safe case, I use Finder to the directory, and compress those two items first as Archive.zip. Then Remove them completely.

I have to quit Xcode and relaunch Xcode again to do clean build. This time warning error is gone.

My Update Xcode 12.0


The update process was painful. It toke long time to download. I got failure 2 twice.

I had Xcode update frustrating experience before. There was one time the updated Xcode version could not build my project. I had to rollback to old version from TimeMachine backup.

From that experience, I have been kept copy of previous Xcode to external disk first. Then I remove Xcode from Applications. In this way, this time I did clean installation of Xcode 12.0. Another reason is that I do not have enough space in my hard disk to do update. I had to remove old version to get more space.

This clean installation may missed the step to remove ToolChain.

Read More...

Tuesday, June 23, 2020

One-on-One Support from Apple

WWDC2020 was launched this week. In the past, WWDC conferences were all held in US. This year, because of COVID19 and social distance rules,WWDC is the first time on virtual web. The greatest news is that all Apple registered developers are all able to attend the WWDC without paying expensive registration, travel and hotel fees. This is first time Apple trying virtual WWDC.

On the first day, I watched the keynote speech yesterday. From my personal option, I think the virtual meeting is organized much more efficient and smooth, when transfering from one person to another. This can be done without any delay.

I watched Sean Allen's Swift News on YouTube. Among many topics about WWDC,he mentioned One-on-one Labs support, which was only available on site at WWDC. Now everything is on virtual. I quickly searched from Apple Developer's web page. It is true that one-on-one support is available on request. I made my request. I have been struggling on one UI issue for quite long time and still could not figure out any good solution. Within seconds, I got confirmation that my one-on-one support is scheduled tomorrow morning. That's awesome!

 


I have hight hope that I could get expert support directly from Apple to diagnose my issue and hope a solution would help to get the issue resolved.

Update on Jun 24 11MT: Just finished 1 on 1 labs support. I demonstrated my issue and showed what I have done in Xcode. The issue seems new to Apple support. He could not provide any solution and suggested me to submit a bug report on this issue.

The issue is that I have a screen with toolbar on bottom. There is one UIBarButton there. Most of time, the button shows normally. However, after a while, it would not visible when the screen brought up. I noticed that the issue is related to iPhone without physical Home button, ie, my Xr. The button still reacts to tap action even when it is invisible. It looks like that the button's tint color is as same as toolbar color, which causes button invisible.

References


Read More...

Monday, April 20, 2020

Use div for Table Layout in HTML

table HTML Tag has been in HTML for long time to show table-like layout. Now div is more powerful tag to display a block of text, and this can be used for table-like layout.

The basic concept is to use css styles as a way to instruct div to show block of text in table-like layout. After search on web, I found a couple ways to use div, and I place the correspoding ccs styles in Blogger's templates.

The following are some ccs classes in Blogger template:

/* -- no border table using div class */
.nbTable { 
  display: table;
  width: 100%;
} 
.nbTableRow {
  display: table-row;
}
.nbTableHeadRow {
  display: table-header-group; 
  font-weight: bold;
} 
.nbTableBody {
  display: table-row-group; 
} 
.nbTableFoot {
  display: table-footer-group; 
}
.nbTableCell, .nbTableHead {
  display: table-cell; 
}
.nbTableCell1Line, .nbTableHead1Line {
  display: table-cell;
  white-space: nowrap;
}

/* -- table with border using div class */
.bTable {
  display: table;
  width: 100%;
} 
.bTableRow {
  display: table-row;
}
.bTableCell, .rTableHead {
  display: table-cell;
  padding: 3px 10px;    
  border: 1px solid #999999;
}
.bTableCell1Line, .rTableHead1Line {
  display: table-cell;
  white-space: nowrap;
  padding: 3px 10px;
  border: 1px solid #999999;
}
.bTableHeadRow {
  display: table-header-group;
  background-color: #ddd;
  font-weight: bold;
}
.bTableFoot {
  display: table-footer-group;
  font-weight: bold;
  background-color: #ddd;
}
.bTableBody {
  display: table-row-group;
}

Read More...

Sunday, April 05, 2020

Use VIM to Clean Up HTML

I have set up a blog at Blogger with more than one authors so that we can write our stories, observations about COVID-19. Some authors do not have any knowledge about HTML or how to write clean blogs there. As a result, the blogs they created contains massy HTML tags, either cause them frustration to edit text or inconsistent styles spreading blog text.





I am tech support person working hard behind scenes. One of my jobs is to clean up their blogs to remove unnecessary HTML tags. Here is one example how complexed HTML is:




VIM as Effective Tool


It is really tedious and time consuming to manually remove HTML paired tags. For example:

<span ...>...</span>

I realize that VIM is a great tool for help!

Here is the command to find out span paired block in HTML:

/<span\(\_.\{-}\)\@=\_.\{-}>

search for start patten <span any chars afterwards including mutilple lines till >.

Here is the result:





That's very exiting! With this confirmation test, it will be just line of VIM replace command to clean up span tags:

%s:<span\(\_.\{-}\)\@=\_.\{-}>::g  





More VIM command for finding and replacing


/<\/span\(\_.\{-}\)\@<=\_.\{-}> ## find </span>
:%s:<\/span\(\_.\{-}\)\@=\_.\{-}>::g ## replace </span>


/<div\(\_.\{-}\)\@<=\_.\{-}> ## find <div...>
:%s:<div\(\_.\{-}\)\@=\_.\{-}>::g ## replace <div>


/<\/div\(\_.\{-}\)\@<=\_.\{-}> ## find </div>
:%s:<\/div\(\_.\{-}\)\@=\_.\{-}>::g ## replace </div>

With above a few commands, I cleaned up HTML with great result!





References


Read More...