Upgrade to Pro — share decks privately, control downloads, hide ads and more …

UIColor Anatomy

UIColor Anatomy

iOSDC Japan 2020 #iosdc
「大解剖!UIColorファミリー」発表資料です。

https://fortee.jp/iosdc-japan-2020/proposal/8617aa4c-5386-4629-abf4-3e93ebfe2962

Shigure Shimotori

September 21, 2020
Tweet

More Decks by Shigure Shimotori

Other Decks in Programming

Transcript

  1. UIColor var red: CGFloat var green: CGFloat var blue: CGFloat

    ม׵? init(white:alpha:) init(cgColor:) ❌ 10
  2. ΋͠UIColor͕୯ମͰଘࡏ͍ͯͨ͠Β(1/2) class UIColor { private let redComponent: CGFloat? private let

    greenComponent: CGFloat? private let blueComponent: CGFloat? private let whiteComponent: CGFloat? private let alphaComponent: CGFloat? private let provider: ((UITraitCollection) -> UIColor)? private let image: UIImage? 以下略 12
  3. ΋͠UIColor͕୯ମͰଘࡏ͍ͯͨ͠Β(2/2) func withAlphaComponent() -> UIColor { if /*RGBで表現されているとき*/ { }

    else if /*色空間がdisplay P3のとき*/ { } else if /*パターンイメージを使うとき*/ { } else if /*dynamic colorのとき*/ { 以下略 13
  4. ࣮ࡍͷUIColor͸͜Μͳײ͡ʁ UIColor public init(red: CGFloat, ..., alpha: CGFloat) { return

    UIDeviceRGBColor() } public init(patternImage: CGFloat) { return UIDynamicPatternColor() } var cgColor: CGColor { get } UIDeviceRGBColor UIDynamicPatternColor let redComponent: CGFloat override var cgColor: CGColor { /*適切な処理*/ } let image: UIImage override var cgColor: CGColor { /*適切な処理*/ } RGB୲౰ ύλʔϯΠϝʔδ୲౰ 17 ஫ɿਖ਼֬Ͱ͸͋Γ·ͤΜ
  5. ৭ͷܾఆํ๏͕͍ͬͺ͍ʂ • init(white:alpha:) • init(red:green:blue:alpha:) / init(hue:saturation:brightness:alpha:) • init(displayP3Red:green:blue:alpha:) •

    init(named:) / init(named:in:compatibleWith:) • init(dynamicProvider:) • init(ciColor:) • init(cgColor:) • init(patternImage:) • init(_:) ※SwiftUI.ColorɻiOS14.0ʙ શ෦ҧ͏αϒΫϥε͕ฦͬͯ͘Δ ʢ΋ͪΖΜݟ͔͚͸public class UIColorʣ 18 గਖ਼ʢ2020/09/20ʣ
 init(_:)͸طଘͷΫϥεΛฦ͢໛༷ɻ
  6. ͦͷલʹɿUIColorͷཪଆΛ࡯͢Δखஈ • class-dump • Objective CͷϔομΛ೷͚Δπʔϧ • Method swizzlingɺXcodeͷSymbolic Breakpoint

    • ಛఆͷϝιου͕ݺ͹ΕͨॠؒΛั·͑Δ • ԿΛ͍ͯ͠Δ͔΋ͪΐͬͱΘ͔Δ • object_getClass(_:) • ܕ໊ͷऔಘ • type(of:)ͩͱ͏·͘औΕͳ͍ 21
  7. class-dumpͰ೷͍ͯΈͨ UIKitCore.framework/UIDeviceRGBColor.hʢҰ෦ൈਮʣ #import <UIKitCore/UIColor.h> __attribute__((visibility("hidden"))) @interface UIDeviceRGBColor : UIColor {

    double redComponent; double greenComponent; double blueComponent; double alphaComponent; struct CGColor *_cachedColor; } - (_Bool)getWhite:(double *)arg1 alpha:(double *)arg2; Copyright (C) 1997-2019 Steve Nygard. 22
  8. 14. UICIColor • init(ciColor:)ͰಘΒΕΔΫϥε • CIColorΛड͚औͬͯอ࣋͢Δ͔ΒUICIColor • CI = CoreImage.framework

    • ड͚औͬͨCIColorΛ಺෦ʹӅ͍࣋ͬͯ͠Δ • var ciColor: CIColor { get } ͸ͦͷ··ฦ͚ͩ͢ͷॲཧΛ͍ͯ͠ΔΈ͍ͨ 39
  9. 16-17. UI(Cached)PatternCGColor • init(cgColor:)ͰಘΒΕΔΫϥεͦͷ2 • PatternͳCGColorͷͨΊͷΫϥε • ڪΒ͘ var pattern:

    CGPattern? { get } Λ͍࣋ͬͯΔΑ͏ͳCGColor • खͬऔΓૣ͍ྫɿUIColor.init(cgColor: UIColor.init(patternImage: image).cgColor) • CachedΫϥεΛ࣋ͭʢUICachedPatternCGColorʣ 41
  10. UIPatternCGColorΛ࡞Δ let drawPattern: CGPatternDrawPatternCallback = { info, context in let

    subunit = CGFloat(20.0) context.setFillColor(red: 0.5, green: 0, blue: 0, alpha: 1) context.fill(CGRect(x: 0, y: 0, width: subunit, height: subunit)) context.setFillColor(red: 1, green: 0.3, blue: 0.3, alpha: 1) context.fill(CGRect(x: subunit, y: subunit, width: subunit, height: subunit)) context.setFillColor(red: 0.7, green: 0.3, blue: 0, alpha: 1) context.fill(CGRect(x: 0, y: subunit, width: subunit, height: subunit)) context.setFillColor(red: 0.7, green: 0.3, blue: 0, alpha: 1) context.fill(CGRect(x: subunit, y: 0, width: subunit, height: subunit)) } var callbacks = CGPatternCallbacks(version: 0, drawPattern: drawPattern, releaseInfo: nil) let pattern = CGPattern(info: nil, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), matrix: CGAffineTransform(a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0), xStep: 40, yStep: 40, tiling: .constantSpacing, isColored: true, callbacks: &callbacks)! let color = UIColor(cgColor: CGColor(patternSpace: CGColorSpace(patternBaseSpace: nil)!, pattern: pattern, components: [1, 1, 1, 1])!) ਺ࣈ͸ద౰Ͱ͢ 42
  11. DataܕΛհͯ͠৭σʔλΛ෮ݩͰ͖ͪΌͬͨ Cocoa.NSColor→Data→UIColor let color = Cocoa.NSColor(calibratedWhite: 0.5, alpha: 0.5) let

    colorData = try! NSKeyedArchiver.archivedData( withRootObject: color, requiringSecureCoding: true ) try! colorData.write(to: URL(fileURLWithPath: 略)) let data = try! Data(contentsOf: URL(fileURLWithPath: 略)) let color = try! NSKeyedUnarchiver.unarchivedObject( ofClasses: [UIColor.self], from: data ) // ここでUIKit.NSColor.init(coder:)が呼ばれる print(color) // Optional(UIExtendedGrayColorSpace 0.5 0.5) 45
  12. • ·ͣ͸αϒΫϥεΛ࡞Δ • ϓϩύςΟ΍ϝιουΛܧঝͯ͠ઐ༻ͷॲཧΛ࣮૷͓ͯ͘͠ ྫ͑͹͜Μͳײ͡ (1/2) @implementation MyColor: UIColor -

    (instancetype _Nonnull)initWithMyProperty:略 { 略 return self; } - (CGColorRef)CGColor { // 必要なプロパティやメソッドを継承 return 略; } 略 @end 49
  13. αϒΫϥεʹࢧ͑ΒΕͨϝιου&ϓϩύςΟ • withAlphaComponent(_:) • resolvedColor(with:) • cgColor, ciColor • set(),

    setFill(), setStroke() • getHue(ུ) / getRed(ུ) / getWhite(ུ) • isEqual(to:) ⚠αϒΫϥε͝ͱʹಈ࡞͕ҟͳΔ͔΋⚠ 55
  14. withAlphaComponent(_:) • UIPlaceholderColor͸ಛఆͷ৭Λࢦ͍ͯ͠ͳ͍ͷͰΫϥογϡ • static colorͰ͸୯७ʹalpha componentΛ্ॻ͖͢Ε͹OK • ݩͱಉ͡Ϋϥε͕໭Γ஋ͱͯ͠ฦ͞ΕΔ •

    alpha componentҎ֎͸มߋ͞Εͳ͍ • dynamic color͸ղܾͷͨͼʹalpha componentΛ্ॻ͖͢Δඞཁ͕͋Δ • ͭ·ΓUIDynamicModifiedColor͕ཁΔ • ͜ͷϝιουΛ࣮ߦͯ͠΋ݩͷUIDynamicColor͸ҡ࣋͞ΕΔ 56
  15. isEqual(to:) • UIPlaceholderColor͸ಛఆͷ৭Λࢦ͍ͯ͠ͳ͍ͷͰΫϥογϡ • ಉ͡αϒΫϥεͰɺϓϩύςΟ͕౳஋ͳΒਅʁ • ྫɿUIColor.whiteͱUIColor(white: 1, alpha: 1)͸ਅ

    • ྫɿUIColor(red: 1, green: 1, blue: 1, alpha: 1)ͱUIColor(white: 1, alpha: 1)͸ِ • UICIColorͱUICGColorͱͷ൑ఆ͸ِʹͳΔ • UIDynamicProviderColor͸ಉҰੑ൑ఆ͕ਅͰͳ͚Ε͹౳஋൑ఆ΋ਅʹͳΒͳ͍ • UIDynamicAppDefinedColorʹ͢Ε͹౳஋൑ఆ͕ਅʹͳΕΔ 58
  16. ࢀߟจݙͱ͔໘നͦ͏ͳϖʔδͱ͔ • Randomizing UIColor with Method Swizzling | Jonathan Cole

    • ʲIOS ARCʳ UIColor͕ϝϞϦʹ࢒͍ͬͯΔΑ͏ͳؾ͕͢Δ &#8211; ඥ෇͚ͳ೔ʑ • Patterns • Core Graphics Tutorial: Patterns | raywenderlich.com • iOS ൌགྷapp∍ന໛ࣜ - ࡥ඀ • nygard/class-dump: Generate Objective-C headers from Mach-O files. • nst/RuntimeBrowser: Objective-C Runtime Browser, for Mac OS X and iOS 63