2

I am following this tutorial. In its AppDelegate it has a customizeAppearance() where UISearchBar & UINavigationBar are type/class properties. Shouldn't they be a property of something like the window or the current viewController we are in?! How can we just message a class and then have it change our UI?

FWIW when I cmmd click...obviously it just takes it to the class definition.

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  var backgroundSessionCompletionHandler: (() -> Void)?
  var window: UIWindow?
  let tintColor =  UIColor(red: 242/255, green: 71/255, blue: 63/255, alpha: 1)

  func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.
    customizeAppearance()
    return true
  }

  func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void) {
    backgroundSessionCompletionHandler = completionHandler
  }

  // MARK - App Theme Customization

  private func customizeAppearance() {
    window?.tintColor = tintColor
    UISearchBar.appearance().barTintColor = tintColor // shouldn't UISearchBar be a property of some other object?
    UINavigationBar.appearance().barTintColor = tintColor // shouldn't UINavigationBar be a property of some other object?
    UINavigationBar.appearance().tintColor = UIColor.whiteColor()
    UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor()]
  }
}
dfrib
  • 70,367
  • 12
  • 127
  • 192
mfaani
  • 33,269
  • 19
  • 164
  • 293
  • 2
    Quoting [the language reference for `UISearchBar`](https://developer.apple.com/reference/uikit/uisearchbar): _"You can customize the appearance of search bars one at a time, or you can use the appearance proxy (`[UISearchBar appearance]`) to customize the appearance of all search bars in an app."_. In the tutorial you follow, they've chosen the latter proxy approach, making use of the static `appearance()` method of as blueprinted in [the `UIAppearance` protocol](https://developer.apple.com/reference/uikit/uiappearance) to which e.g. `UISearchBar` conforms to (via `UIView` inheritance). – dfrib Dec 25 '16 at 20:36
  • @dfri ohh. wow. That's convenient. So if I change one at a time and also customize using appearance. The proxy method would be override right? Also Is this *proxy* mechanism offered elsewhere in Cocoa touch or no? – mfaani Dec 25 '16 at 20:38
  • 1
    I can't really say without testing, but further quoting the language ref. for `UIAppearance`: _"iOS applies appearance changes when a view enters a window, it doesn’t change the appearance of a view that’s already in a window ..."_ as well as _"In any given view hierarchy, the outermost appearance proxy wins."_. So I believe depending on where (or at what depth) you choose to customize your appearance, the default /customized proxy behaviour (loads upon view entering window) _or_ your custom instance-set behaviour will take precedence. Have a look at the ref. docs for `UIAppearance` for det.s. – dfrib Dec 25 '16 at 20:43
  • @dfri Thank you so much. 2 more questions :D. 1) The best place to load such is within `didFinishLaunchingWithOptions` ie use it as a entry point for customization. Right? 2) there is no UISearchBar created here. Only that any searchBar loaded in the coming up classes would be affected by such customization. right? – mfaani Dec 25 '16 at 20:51
  • 1
    1. I can't really say, but based on the tutorial, they've chosen that point, so I believe the RayWenderlichauthor would say _"yes"_ :) 2. Yes, that's also how I interpret it: the `UISearchBar` customization is set for the proxy of `UISearchBar`, and will then be applied _for all instance_ of `UISearchBar` (in the project, I believe?). I becomes tricky, however, if you start defining your custom conformance to [`UIAppearanceContainer`](https://developer.apple.com/reference/uikit/uiappearancecontainer), e.g. for some custom `UISearchBar` of yours. In that case, I can't really speculate over ... – dfrib Dec 25 '16 at 20:56
  • 1
    ... what takes precedence, but in performing this tutorial of yours, it would be an excellent point to test these things out :) and if you have any insights that are not entirely clear from the docs, I would encourage you to add them as an answer to your own question. Addendum: [the following blog post](http://nshipster.com/uiappearance/) is somewhat outdated, but instructive nonetheless. – dfrib Dec 25 '16 at 20:57

1 Answers1

1

(I'll add my comments—answering the OP's question regarding class level customization—as an answer, as comments are not persistent. Possibly the OP himself/herself can add an alternative thorough answer based on trying out the queries discussed in the comments)


Quoting the language reference for UISearchBar:

Customizing Appearance

You can customize the appearance of search bars one at a time, or you can use the appearance proxy ([UISearchBar appearance]) to customize the appearance of all search bars in an app.

The appearance proxy is covered e.g. in the UIKit User Interface Catalog - About Views:

Appearance Proxies

You can use an appearance proxy to set particular appearance properties for all instances of a view in your application. For example, if you want all sliders in your app to have a particular minimum track tint color, you can specify this with a single message to the slider’s appearance proxy.

There are two ways to customize appearance for objects: for all instances and for instances contained within an instance of a container class.

...

As well as in the language reference for the UIAppearance protocol

Use the UIAppearance protocol to get the appearance proxy for a class. You can customize the appearance of instances of a class by sending appearance modification messages to the class’s appearance proxy.

...

  • To customize the appearance of all instances of a class, use appearance() to get the appearance proxy for the class.

In the tutorial you follow, they've chosen to use of the appearance proxy approach, making use of the static appearance() method as blueprinted in the UIAppearance protocol (to which e.g. UISearchBar conforms to, via UIView inheritance) to get and modify the appearance proxy of all UISearchBar (and UINavigationBar) instances, from a class level.


The following blog post covers the subject of the appearance proxy. An instructive read, even though being slightly outdated and using Obj-C rather than Swift:

dfrib
  • 70,367
  • 12
  • 127
  • 192