$30 off During Our Annual Pro Sale. View Details »

UIColor Cluster

UIColor Cluster

第13回 HAKATA.swift「UIColor Cluster」の発表資料です。
https://hakata-swift.connpass.com/event/176661/

#hakataswift

Shigure Shimotori

June 19, 2020
Tweet

More Decks by Shigure Shimotori

Other Decks in Programming

Transcript

  1. @S_Shimotori
    UIColor Cluster
    ୈ13ճ HAKATA.swift

    View Slide

  2. S_Shimotori
    • Twitter: @S_Shimotori_pub

    • ண৭৬ਓ

    • Dark ModeରԠͨ͠

    • Objective CϚδͰΘ͔Βͳ͍

    • ݟಀͯ͠΄͍͠

    View Slide

  3. UIColor Cluster

    View Slide

  4. class UIColor
    • UIKitఏڙͷɺ৭σʔλΛ֨ೲͨ͠ΦϒδΣΫτ

    • ͨ͘͞ΜΠχγϟϥΠβ͕͋Δ

    • ϝιου͸ͦΜͳʹͳ͍

    • Dark ModeରԠͰΊͬͪΌ͓ੈ࿩ʹͳͬͨɹݟ๞͖ͨʂ

    View Slide

  5. var description: String
    UIColor(white: 1, alpha: 1).description


    UIColor(red: 1, green: 1, blue: 1, alpha: 1).description


    UIColor(dynamicProvider: { _ in return .white }).description


    View Slide

  6. var description: String
    UIColor(white: 1, alpha: 1).description

    → UIExtendedGrayColorSpace 1 1
    UIColor(red: 1, green: 1, blue: 1, alpha: 1).description


    UIColor(dynamicProvider: { _ in return .white }).description


    ↓xcassetsͰͷExtended Gray

    View Slide

  7. var description: String
    UIColor(white: 1, alpha: 1).description

    → UIExtendedGrayColorSpace 1 1
    UIColor(red: 1, green: 1, blue: 1, alpha: 1).description

    → UIExtendedSRGBColorSpace 1 1 1 1
    UIColor(dynamicProvider: { _ in return .white }).description


    View Slide

  8. var description: String
    UIColor(white: 1, alpha: 1).description

    → UIExtendedGrayColorSpace 1 1
    UIColor(red: 1, green: 1, blue: 1, alpha: 1).description

    → UIExtendedSRGBColorSpace 1 1 1 1
    UIColor(dynamicProvider: { _ in return .white }).description

    → >

    View Slide

  9. ?? UIDynamicProviderColor ??
    private class͔ͳʁ

    View Slide

  10. UIColor૝૾ਤ
    UIColor
    UIDynamicProviderColor
    UIDynamicSystemColor
    UI??????????Color
    • init(white:alpha:)

    • init(red:green:blue:alpha)
    • systemBackground

    • label
    • init(dynamicProvider:)
    ※ਖ਼֬Ͱ͸ͳ͍
    var description: StringͳͲ͸֤ࣗઃఆ͢Δʂ

    View Slide

  11. Class Cluster ͔ͳʁ

    View Slide

  12. Class Clusterͬͯͳʹ
    • Foundation framework͕ଟ༻͢ΔσβΠϯύλʔϯɺΒ͍͠

    • Abstract FactoryσβΠϯύλʔϯͷ೿ੜ

    • ෳ਺ͷprivateͳsub classΛɺந৅త͕ͩpublicͳsuper classͷԼʹ഑ஔ

    • ػೳͷॆ࣮۩߹͸ͦͷ··ʹɺpublicʹͳ͍ͬͯΔॴ͚ͩʹूதͰ͖Δ

    • super class͸ɺsub classͷΠϯελϯεΛ࡞੒͢ΔϝιουΛ࣋ͭ

    View Slide

  13. Class ClusterͷྫʁɿNSNumber
    NSNumber
    long long int
    long int
    char short int int float double
    NSNumber͸ɺ֤sub classͷΦϒδΣΫτΛ࡞੒͢ΔͨΊͷϝιουΛ࣋ͭʁ

    • numberWithChar:

    • numberWithInt:

    • ͳͲͳͲʁ

    View Slide

  14. ΦʔϓϯιʔεNSNumber͸ʁ
    • ཪ͸CFNumber

    • “An object wrapper for primitive scalar numeric values.”

    • CFNumberCreateͰ୯७ʹbitͱछผΛهԱ͍ͯ͠Δ͚ͩͬΆ͍ʁ

    • Class ClusterͰ͸ͳͦ͞͏……

    View Slide

  15. Class ClusterͷྫʁɿNSArray
    • ෳ਺ͷsuper class͔Βߏ੒͞Ε͍ͯͯ΋OKͱͷ͜ͱ
    NSArray NSMutableArray
    ʁʁʁ
    privateͳԿ͔ʁ

    View Slide

  16. ΦʔϓϯιʔεNSArray͸ʁ
    • internal var _storage = [AnyObject]()

    • open class NSMutableArray : NSArray

    • ΍ͬͺΓClass ClusterͰ͸ͳͦ͞͏……

    View Slide

  17. Class ClusterͷσϝϦοτ
    • sub classΛ௥Ճ͢Δͷ͕໘౗

    • FoundationͰClass ClusterΛ࠾༻͍ͯ͠Δ΋ͷ͸ɺsub classΛ࡞Δ༻ࣄ͕
    ͋·Γͳͦ͞͏ͳ΋ͷ
    ௥Ճ͕ΊΜͲ͍͘͞

    View Slide

  18. UIColorͷ
    sub class࡞੒ʹ௅ઓ͢Δ

    View Slide

  19. UIColor͕෺଍Γͳ͍ͱࢥͬͨΒ
    • Ҋ1ɿ͍ͭ΋௨ΓUIColorΛܧঝ͢Δ

    • Ҋ2ɿUIColorΛϥοϓ͢ΔclassΛ࡞ͬͯޡຐԽ͢

    • private var innerColor: UIColor ͳײ͡ͰͲ͏Ͱ͠ΐ͏

    • Ҋ3ɿextensionͰϝιουΛੜ΍͢

    View Slide

  20. UIColorͷsub class͕ඞཁͳͱ͖
    • ৭ۭؒͷछྨ΍৭ͷϞσϧΛ৽͘͠௥Ճ͢Δͱ͖

    • UIColor͕ѻ͍ͬͯͳ͍৭ۭؒΛѻ͑ΔΑ͏ʹͯ͠ΈΔͱ͔……ʁ

    • dynamic providerͰ৭Λܾఆͯ͠ΈΔͱ͔……ʁ

    View Slide

  21. UIColorΛܧঝͯ͠ΈΔ
    • Class ClusterΛܧঝ͢Δͱ͖ͷ஫ҙ఺ΛकΔʂʂ
    • super classΛܧঝͯ͠࡞Δ͜ͱ

    • ඞཁͳϓϩύςΟΛએݴ͢Δ͜ͱ

    • શͯͷΠχγϟϥΠβΛΦʔόʔϥΠυ͢Δ͜ͱ

    • શͯͷprimitive methodΛΦʔόʔϥΠυ͢Δ͜ͱ

    • UIColorΛܧঝ͢Δͱ͖ͷ஫ҙ఺ΛकΔʂʂ
    • ௥Ճ͢Δϝιου΍ϓϩύςΟ͸ɺεϨουηʔϑͰͳ͚Ε͹ͳΒͳ͍

    View Slide

  22. primitive methodͱ͸
    • ͦͷclassͷΠϯλʔϑΣʔεͷجૅΛ͔ͨͪ࡞Δ΋ͷ

    • NSArrayͰ͍͏ͳΒcountͱobjectAtIndex

    • UIColorͰ͍͏ͳΒͲΕ͔ͳ……ʁ

    • ৭ۭؒͱίϯϙʔωϯτ஋͕ఆ·Βͳ͍ͱࠔΓͦ͏

    View Slide

  23. ୈ1஄ɿ

    ಠࣗͷ৭ۭؒΛαϙʔτ

    View Slide

  24. ಠࣗͷ৭ۭؒΛαϙʔτ͍ͨ͠
    • ಠࣗͷ৭ۭؒΛαϙʔτ͢ΔͨΊͷsub classΛ࡞Δͧʂ

    • RGBʢίϯϙʔωϯτ3+1ݸʣ͸ΊΜͲ͍͘͞ͷͰɺGrayʢ1+1ݸʣͰ௅ઓ

    • UIColor(myWhite: CGFloat, alpha: CGFloat)ͳײ͡ͰͰ͖Ε͹࠷ߴ

    View Slide

  25. UIColorʹඞཁͳύϥϝʔλΛ౉͢
    • UIColorࣗମʹ͸ɺ৭ۭؒ΍ίϯϙʔωϯτ஋ΛهԱͤ͞Δखஈ͕ͳ͍

    • 1൪؆୯ͳͷ͸init(cgColor:)ͰCGColorΛ౉ͯ͠͠·͏΍Γํ

    • CGColorͷΠχγϟϥΠβͳΒ৭ۭؒΛࢦఆՄೳ
    ↓Πϝʔδ͸͜Μͳײ͡↓
    init(myWhite: CGFloat, alpha: CGFloat) {

    super.init(cgColor: CGColor(

    colorSpace: // ここに色空間

    components: // ここにコンポーネント値

    ))!

    }

    View Slide

  26. ΠχγϟϥΠβʹ৮Εͳ͍໰୊
    • UIColorͷrequired initΛΦʔόʔϥΠυ͠ͳ͚Ε͹ͳΒͳ͍

    • UIColorͷrequired initΛΦʔόʔϥΠυͰ͖ͳ͍ʢmethod dispatchͷ౎߹ʣ
    Overriding non-@objc declarations from extensions is not supported
    @nonobjc required convenience init(

    _colorLiteralRed red: Float, green: Float, blue: Float, alpha: Float

    )
    Objective CͳΒͳΜͱ͔ɻ

    View Slide

  27. ิ଍ɿmethod dispatch
    • ͲͷϝιουΛݺͼग़͔͢Λܾఆ͢Δ࢓૊Έͷ͜ͱ

    • static dispatchʢίϯύΠϧ࣌ʹܾఆʣ

    • struct΍enum΍finalͱ͍ͬͨΦʔόʔϥΠυෆՄͳ΋ͷ͕ͬͪ͜

    • extensionͰ௥Ճͨ͠ϝιου΋ͬͪ͜

    • dynamic dispatchʢίϯύΠϧ࣌ʹtable࡞੒ɺ࣮ߦ࣌ʹܾఆʣ

    • ΦʔόʔϥΠυՄೳͳ΋ͷ͸ͬͪ͜

    • extensionͰޙ෇͚ͨ͠ϝιου͸tableʹೖΕͯ΋Β͑ͳ͍
    આ໌ؒҧͬͯͨΒ͝ΊΜͳ͍͞ʂ

    View Slide

  28. SwiftͰ࣮૷ͯ͠Έͨ(1/2)
    private class MyCustomColor: UIColor {

    private static let whitePoint: [CGFloat] = [76.04, 80, 87.12]

    private static let blackPoint: [CGFloat] = [0.1901, 0.2, 0.2178]

    static func create(

    gamma1_5Gray gray: CGFloat, alpha: CGFloat

    ) -> MyCustomColor {

    // 色空間を新しく定義

    let colorSpace = CGColorSpace(

    calibratedGrayWhitePoint: whitePoint,

    blackPoint: blackPoint,

    gamma: 1.5 // ←この値をカスタムしてみた

    )!

    // 色空間とコンポーネント値を設定

    let cgColor = CGColor(

    colorSpace: colorSpace,

    components: [gamma1_5Gray, alpha]

    )!

    // initしたつもり……

    return MyCustomColor(cgColor: cgColor)

    }

    }

    View Slide

  29. SwiftͰ࣮૷ͯ͠Έͨ(2/2)
    extension UIColor {

    // publicなイニシャライザのつもり

    static func create(

    gamma1_5Gray gray: CGFloat, alpha: CGFloat

    ) -> UIColor {

    return MyCustomColor.create(gamma1_5Gray: gray, alpha: alpha)

    }

    }

    // ガンマ値2.2のいつもの白

    let gamma2_2Color = UIColor(white: 1, alpha: 1)

    // ガンマ値1.5の白

    let gamma1_5Color = UIColor.create(gamma1_5Gray: 1, alpha: 1)

    View Slide

  30. SwiftͰ࣮ߦͯ͠Έͨ
    • white = 0.0, 0.1, …, 0.9, 1.0ͷ৭Λฒ΂ͨ

    • ࠨྻɿΨϯϚ2.2ʢ͍ͭ΋ͷʣ

    • ӈྻɿΨϯϚ1.5ʢMyCustomColorʣ
    White: 0.0 →
    White: 1.0 →
    White: 0.5→

    View Slide

  31. ୈ2஄ɿ
    UIDynamicProviderColorΛύΫΔ

    View Slide

  32. ৽͍͠Ϟσϧͬͯ΍ͭΛ࡞Γ͍ͨ
    • ಈతʹ৭Λܾఆ͢Δɺશ͘৽͍͠ϞσϧͷUIColorΛ࡞Δͧʂ

    • UIDynamicProviderColorͱಉ͡΋ͷΛ࡞Δ͜ͱʹ௅ઓ

    • init(myDynamicProvider:)ͳײ͡Ͱ

    • ࠓճ͸ObjCͰؤுΔʢมͳॻ͖ํͯͨ͠ΒεϛϚηϯʣ
    ↓Πϝʔδ͸͜Μͳײ͡↓
    self = [super init];

    if (self) {

    _myDynamicProvider = myDynamicProvider;

    }

    return self;

    View Slide

  33. ຊདྷඞਢͳ৘ใΛൈ͖ʹ࡞͍ͬͯ͘
    • طଘΠχγϟϥΠβ΁৭ۭؒ&ίϯϙʔωϯτ஋Λ౉ͣ͞ʹܧঝ͢ΔͳΒɺ

    UIColorͷϓϩύςΟ΍ϝιουΛશͯਖ਼͘͠ΦʔόʔϥΠυ͢Δඞཁ͕͋Δ

    • ઌ΄Ͳͷ[super init]͚ͩͰ͸ΫϥογϡͷݪҼʹͳΔ

    • UIColorͷϝιου͚ͩͰͳ͘isEqual:ͷΦʔόʔϥΠυ΋๨Εͣʹ

    • ৭ͷ౳஋൑ఆॲཧ΋͜ΕΒͷ৘ใʹґଘ͍ͯ͠ΔͨΊ
    *** -CGColor not defined for the UIColor <ུ>; need to first convert colorspace.

    View Slide

  34. Objective CͰ࣮૷ͯ͠Έͨ(1/3)
    Ұ෦ൈਮ
    @implementation MyDynamicColor: UIColor

    - (instancetype _Nonnull)initWithMyDynamicProvider:(UIColor * _Nonnull
    (^ _Nonnull)(UITraitCollection * _Nonnull
    traitCollection))myDynamicProvider {

    self = [super init];

    if (self) {

    _myDynamicProvider = myDynamicProvider;

    }

    return self;

    }

    - (CGColorRef)CGColor {

    return
    _myDynamicProvider(UITraitCollection.currentTraitCollection).CGColor;

    }

    // その他のメソッドもオーバーライド

    @end

    View Slide

  35. Objective CͰ࣮૷ͯ͠Έͨ(2/3)
    Ұ෦
    @implementation UIColor(MyColor)

    + (UIColor * _Nonnull)initWithMyDynamicProvider:(UIColor * _Nonnull (^
    _Nonnull)(UITraitCollection * _Nonnull
    traitCollection))myDynamicProvider {

    return [[MyDynamicColor alloc]
    initWithMyDynamicProvider:myDynamicProvider];

    }

    @end

    View Slide

  36. Objective CͰ࣮ߦͯ͠Έͨ
    • Dark Modeʹͯ͠΋৭͕มΘΒͳ͍ɻɻɻ
    UIColor(myDynamicProvider: {

    $0.userInterfaceStyle == .dark ? .red : .blue

    })

    View Slide

  37. Objective CͰ࣮૷ͯ͠Έͨ(3/3)
    • _isDynamicΛΦʔόʔϥΠυͯ͠ਅʹ͠ͳ͍ͱมԽ͠ͳ͍

    • privateͳϓϩύςΟͳΜͰ͚͢Ͳ……
    - (BOOL)_isDynamic {

    return YES;

    }

    View Slide

  38. ·ͱΊ

    View Slide

  39. Θ͔ͬͨ͜ͱ
    • Foundation΍UIKitʹ͸ɺClass Clusterͱ͍͏σβΠϯύλʔϯʹଇͬͨΫϥε
    ͕ଘࡏ͍ͯ͠Δʢ͔΋͠Εͳ͍)

    • Swiftʹ͸ԑ͕ͳ͍΋ͷ͔΋ɻɻ

    • Ͳ͏ͯ͠΋sub classΛ࡞Βͳ͚Ε͹͍͚ͳ͍࣌͸৻ॏʹ

    • UIColorͷsub classΛ࡞Δͷ͸େม

    • SwiftͰ΍Δͷ͸͞Βʹແཧ͕͋Δ

    • ৭ۭؒͷઃఆ஋Λ͍͡Δ͘Β͍͕ݶ౓ʁ

    • ΍Ί͓͍ͯͨ΄͏͕͍͍ͱࢥ͍·͢

    View Slide

  40. ങͬͯ΄͍͠
    • Dark ModeରԠ͠Α͏ʂ

    • s-shimotori.booth.pm

    View Slide

  41. ࢀߟจݙͱ͔
    • https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/
    ClassClusters/ClassClusters.html

    • https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/
    ClassCluster.html

    • https://developer.apple.com/documentation/uikit/uicolor

    • http://www.color.org/sRGB.pdf

    • https://github.com/apple/swift-corelibs-foundation/blob/cfac32b92d5fb62a651967cf22756352179b58ba/
    CoreFoundation/NumberDate.subproj/CFNumber.c

    • https://qiita.com/HaNoHito/items/f40bfc1717c1e922a5b0

    • https://stackoverflow.com/questions/55364212/overriding-non-objc-declarations-from-extensions-is-not-
    supported

    • https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001922.html

    • https://github.com/xybp888/iOS-Header/blob/master/13.0/PrivateFrameworks/UIKitCore.framework/UIColor.h

    View Slide