Learning Swift — Day 224-5(238-9)

How to open a link in Safari

Following this video by Sean Allen.

Import SafariServices.

func showSafariVC(for url: String) {
	guard let url = URL(string: url) else {
		// show an invalid URL error alert
		return
	}

	let safariVC = SFSafariViewController(url: url)
	present(safariVC, animated: true)
}

Inside an action of a button call this function with a proper string URL.

Work with DateComponents

Following this video by Sean Allen.

The video already contains a finished file, which I do not want to override. You can find it in the description.

Advanced Coordinators in iOS

Following this video by Paul Hudson

Six questions:

  1. Using child coordinators
  2. Navigating backwards
  3. Passing data between controllers
  4. Coordinated tab bar controllers
  5. Handling segues
  6. Protocols and closures

1. Child Coordinators

Crazy … I had to use YouTube functionality of turning down the speed to 0.75 to be able to follow anything at all. Really crazy…

Anyway, not that I could understand a lot of this, it is a very complicated topic to me. In short:

  1. We created a new class, BuyCoordinator, that conforms to the Coordinator protocol, gave it a weak reference to an optional MainCoordinator, initialised the navigation controller to the required variable, then, in the start() method, we cut-pasted the code that was previously in the buySubscription() method of the MainCoordinator class.
  2. In BuyViewController change the type of coordinator to be an optional BuyCoordinator.
  3. In MainCoordinator we replaced the cut-out code with a declaration of our BuyCoordinator class, passing in the navigationController property as argument, then set its parentCoordinator to self, before appending it to the array of childCoordinators and calling the start method on the child. Then we added a childDidFinish(_:) method which loops over the enumerated version of the child coordinators array and if the coordinator is equal to the child (using the === operator), then it would remove at the index before breaking from the loop.
  4. Back in BuyCoordinator we added a didFinishBuying() method which called the childDidFinish(self) method on the parent coordinator.
  5. Last thing, we call viewDidDisappear(_:) in the BuyViewController calling coordinator?.didFinishBuying().

Now let’s see if I can reproduce it alone for the other view controller we added.

I DID IT! YES!

2. NAVIGATING BACK

To avoid issues with the coordinator stack once our apps get bigger and bigger we need to perform some changes:

  1. In BuyCoordinator comment out the didFinishBuying method.
  2. In BuyViewController comment out the viewDidDisappear method.
  3. In MainCoordinator, make the class be a subclass of NSObject and add conformance to the UINavigationControllerDelegate protocol. Then, at the beginning of the start() method, make self be the delegate of the navigation controller. Now implement the navigationController(_:didShow:animated:) method. This will check that a bound constant called fromViewController will be equal to the viewController(forKey: .from) return value called on the transitionCoordinator or the navigationController. Then, if the navigation controller’s view controllers array contains the fromViewController we will return from the method, meaning that we should not get out of this screen. At this point, if it is possible to conditionally bind the fromViewController to a constant, conditionally down casting it as a BuyViewController, then we will call the childDidFinish method passing in the buyViewController.coordinator.

It’s a bit obscure to me how this is popping the view controller but … well … who knows? Anyway, I now try to repeat the same process for the other coordinator.

DONE! YES!

3. PASSING DATA

This part had to be slightly modified to work with our new version of the file, but don’t worry, it’s easy.

  1. Drag a segmented control onto the Storyboard and create an outlet for it into the ViewController file, calling it product.
  2. Inside BuyCoordinator add a property var selectedProduct = 0.
  3. In MainCoordinator modify the buySubscription method to accept an integer parameter, then call child.selectedProduct = productType (assuming you called to productType: Int the parameter!).
  4. In ViewController modify the call to buySubscription adding the to: argument name and passing in product.selectedSegmentIndex.

As before, I will try now and replicate it with the other coordinator to see if I can do it!

DONE! Also corrected a stupid error I had made!

4. COORDINATED TAB BARS

This was neat! Just … will I be able to use it in my apps in the future? Well … I don’t know, I need to make some test in the huge amount of time available!

  1. Create a new subclass of UITabBarController called MainTabBarController, give it a MainCoordinator property called main passing in a new instance of UINavigationController as its only argument. Then, inside its viewDidLoad method, call start on main and set the viewControllers array property to be an array containing main’s navigation controller.
  2. Go to MainCoordinator and add a property to start() called vc.tabBarItem and set it equal to UITabBarItem with a tab bar system item of .favorites and a tag of 0.
  3. Now, in the SceneDelegate, comment out the previous coordinator code and just change the window’s root view controller to be a new instance of MainTabBarController.

5. USING SEGUES

Lol … just throw them away!

6. PROTOCOLS AND CLOSURES

Coordinators are just protocols! Maybe a little specialised!

  1. Add a new Swift file called Buying, create a protocol called Buying and make it conform to the AnyObject protocol before giving it a method called buySubscription. Repeat the process for another file and protocol called AccountCreating and give it a method called createAccount.
  2. In MainCoordinator make the class conform to Buying, AccountCreating
  3. In ViewController change the type of coordinator to be (Buying & AccountCreating)?. That’s it!

If you want to use closures:

  1. In ViewController scrap the line where the coordinator is created and add two optional empty closures that return nothing tied to the buyAction and createAccountAction variable properties. Inside the buyTapped and createAccountTapped methods, call them optionally.
  2. In MainCoordinator modify the start method so that it doesn’t set the vc’s coordinator to self but instead sets each action to the corresponding method, making sure it captures self weakly before.

Wow, this was a journey!

I can’t wait to try this in my future apps! Well … yeah … one day I will!


Some Xcode in 20 Seconds videos by Paul Hudson (& similar)

  1. Project filtering: at the bottom of the project navigator section we have two icons, one which looks like a clock and shows the files we have worked on recently and the other that looks like the source control navigator icon. This last one shows files that are under source control, have some changes but have not been committed yet.
  2. Renaming code: select a property then go to Editor > Refactor > Rename
  3. Fix all issues: go to Editor > Fix all issues, for example when changing Swift versions.
  4. Integer multiples in Swift:
  5. Finding callers: once the cursor is inside a method, we can click in the top left of the editor area on that icon that looks like four squares with little arrow between them, called “Navigate to related items”. There, a list opens and we can check which files are calling or are called by our method.
  6. Counting items in Swift:
    This is new in Swift 5.0
  7. Transforming and unwrapping dictionary values with compactMapValues():
  8. Quick Help: hold Option and then click on the name of the variable/method you want to explore.
  9. Toggling Boolean:
  10. Find in project: press Shift-Command-O, then type to search for a file before opening it (one can even press Option-Shift-Enter to decide where to open it in the editor). Once this is open, pressing Shift-Cmd-J will select it in the project.
  11. Adding Documentation: press Option-Command-/. For the Italian keyboard add the Shift key to access the forward-slash character.
  12. Locking views: in the storyboard, in the Identity Inspector, change the Lock property to “All Properties”.
  13. Vector artwork: using vector artwork is a very good choice to preserve scaling and image qualities. Select all your artworks in the assets, then go to the Attributes Inspector, select “Preserve Vector Data” and then change the Scales property to “Single Scale”
  14. Jump to a line: from tip 10 of this list you can add a colon : followed by a line number to jump straight to that line.
  15. Code coverage: Hold Option then go to Product > Test. Then select Code Coverage > Gather coverage. Then Editor > Show Code Coverage.
  16. To detect issues with some code that throws invisible errors (such as networking code), we can create a breakpoint in the gutter and then edit it so that it has an action playing a sound. Remember to check the “Automatically continue after evaluating actions” option.
  17. When we get a crash or something that interrupts execution of our code, in the lower left portion of the Debug Area there is Quick Look button which lets us preview the value of variables at the moment the code execution was interrupted.

That’s it for today!

Thank you for reading!


If you like what I’m doing here please consider liking this article and sharing it with some of your peers. If you are feeling like being really awesome, please consider making a small donation to support my studies and my writing (please appreciate that I am not using advertisement on my articles).

If you are interested in my music engraving and my publications don’t forget visit my Facebook page and the pages where I publish my scores (Gumroad, SheetMusicPlus, ScoreExchange and on Apple Books).

You can also support me by buying Paul Hudson’s books from this Affiliate Link.

Anyways, thank you so much for reading!

Till the next one!

Published by Michele Galvagno

Professional Musical Scores Designer and Engraver Graduated Classical Musician (cello) and Teacher Tech Enthusiast and Apprentice iOS / macOS Developer Grafico di Partiture Musicali Professionista Musicista classico diplomato (violoncello) ed insegnante Appassionato di tecnologia ed apprendista Sviluppatore iOS / macOS

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: