UIColor Cluster

UIColor Cluster

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

#hakataswift

Bf65cc9bdf26321a7579ddca7930cd10?s=128

Shigure Shimotori

June 19, 2020
Tweet

Transcript

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

  2. S_Shimotori • Twitter: @S_Shimotori_pub • ண৭৬ਓ • Dark ModeରԠͨ͠ •

    Objective CϚδͰΘ͔Βͳ͍ • ݟಀͯ͠΄͍͠
  3. UIColor Cluster

  4. class UIColor • UIKitఏڙͷɺ৭σʔλΛ֨ೲͨ͠ΦϒδΣΫτ • ͨ͘͞ΜΠχγϟϥΠβ͕͋Δ • ϝιου͸ͦΜͳʹͳ͍ • Dark

    ModeରԠͰΊͬͪΌ͓ੈ࿩ʹͳͬͨɹݟ๞͖ͨʂ
  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 →
  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
  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 →
  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 → <UIDynamicProviderColor: …; provider = <__NSMallocBlock__: …>>
  9. ?? UIDynamicProviderColor ?? private class͔ͳʁ

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

    systemBackground • label • init(dynamicProvider:) ※ਖ਼֬Ͱ͸ͳ͍ var description: StringͳͲ͸֤ࣗઃఆ͢Δʂ
  11. Class Cluster ͔ͳʁ

  12. Class Clusterͬͯͳʹ • Foundation framework͕ଟ༻͢ΔσβΠϯύλʔϯɺΒ͍͠ • Abstract FactoryσβΠϯύλʔϯͷ೿ੜ • ෳ਺ͷprivateͳsub

    classΛɺந৅త͕ͩpublicͳsuper classͷԼʹ഑ஔ • ػೳͷॆ࣮۩߹͸ͦͷ··ʹɺpublicʹͳ͍ͬͯΔॴ͚ͩʹूதͰ͖Δ • super class͸ɺsub classͷΠϯελϯεΛ࡞੒͢ΔϝιουΛ࣋ͭ
  13. Class ClusterͷྫʁɿNSNumber NSNumber long long int long int char short

    int int float double NSNumber͸ɺ֤sub classͷΦϒδΣΫτΛ࡞੒͢ΔͨΊͷϝιουΛ࣋ͭʁ • numberWithChar: • numberWithInt: • ͳͲͳͲʁ
  14. ΦʔϓϯιʔεNSNumber͸ʁ • ཪ͸CFNumber • “An object wrapper for primitive scalar

    numeric values.” • CFNumberCreateͰ୯७ʹbitͱछผΛهԱ͍ͯ͠Δ͚ͩͬΆ͍ʁ • Class ClusterͰ͸ͳͦ͞͏……
  15. Class ClusterͷྫʁɿNSArray • ෳ਺ͷsuper class͔Βߏ੒͞Ε͍ͯͯ΋OKͱͷ͜ͱ NSArray NSMutableArray ʁʁʁ privateͳԿ͔ʁ

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

    NSMutableArray : NSArray • ΍ͬͺΓClass ClusterͰ͸ͳͦ͞͏……
  17. Class ClusterͷσϝϦοτ • sub classΛ௥Ճ͢Δͷ͕໘౗ • FoundationͰClass ClusterΛ࠾༻͍ͯ͠Δ΋ͷ͸ɺsub classΛ࡞Δ༻ࣄ͕ ͋·Γͳͦ͞͏ͳ΋ͷ

    ௥Ճ͕ΊΜͲ͍͘͞
  18. UIColorͷ sub class࡞੒ʹ௅ઓ͢Δ

  19. UIColor͕෺଍Γͳ͍ͱࢥͬͨΒ • Ҋ1ɿ͍ͭ΋௨ΓUIColorΛܧঝ͢Δ • Ҋ2ɿUIColorΛϥοϓ͢ΔclassΛ࡞ͬͯޡຐԽ͢ • private var innerColor: UIColor

    ͳײ͡ͰͲ͏Ͱ͠ΐ͏ • Ҋ3ɿextensionͰϝιουΛੜ΍͢
  20. UIColorͷsub class͕ඞཁͳͱ͖ • ৭ۭؒͷछྨ΍৭ͷϞσϧΛ৽͘͠௥Ճ͢Δͱ͖ • UIColor͕ѻ͍ͬͯͳ͍৭ۭؒΛѻ͑ΔΑ͏ʹͯ͠ΈΔͱ͔……ʁ • dynamic providerͰ৭Λܾఆͯ͠ΈΔͱ͔……ʁ

  21. UIColorΛܧঝͯ͠ΈΔ • Class ClusterΛܧঝ͢Δͱ͖ͷ஫ҙ఺ΛकΔʂʂ • super classΛܧঝͯ͠࡞Δ͜ͱ • ඞཁͳϓϩύςΟΛએݴ͢Δ͜ͱ •

    શͯͷΠχγϟϥΠβΛΦʔόʔϥΠυ͢Δ͜ͱ • શͯͷprimitive methodΛΦʔόʔϥΠυ͢Δ͜ͱ • UIColorΛܧঝ͢Δͱ͖ͷ஫ҙ఺ΛकΔʂʂ • ௥Ճ͢Δϝιου΍ϓϩύςΟ͸ɺεϨουηʔϑͰͳ͚Ε͹ͳΒͳ͍
  22. primitive methodͱ͸ • ͦͷclassͷΠϯλʔϑΣʔεͷجૅΛ͔ͨͪ࡞Δ΋ͷ • NSArrayͰ͍͏ͳΒcountͱobjectAtIndex • UIColorͰ͍͏ͳΒͲΕ͔ͳ……ʁ • ৭ۭؒͱίϯϙʔωϯτ஋͕ఆ·Βͳ͍ͱࠔΓͦ͏

  23. ୈ1஄ɿ
 ಠࣗͷ৭ۭؒΛαϙʔτ

  24. ಠࣗͷ৭ۭؒΛαϙʔτ͍ͨ͠ • ಠࣗͷ৭ۭؒΛαϙʔτ͢ΔͨΊͷsub classΛ࡞Δͧʂ • RGBʢίϯϙʔωϯτ3+1ݸʣ͸ΊΜͲ͍͘͞ͷͰɺGrayʢ1+1ݸʣͰ௅ઓ • UIColor(myWhite: CGFloat, alpha:

    CGFloat)ͳײ͡ͰͰ͖Ε͹࠷ߴ
  25. UIColorʹඞཁͳύϥϝʔλΛ౉͢ • UIColorࣗମʹ͸ɺ৭ۭؒ΍ίϯϙʔωϯτ஋ΛهԱͤ͞Δखஈ͕ͳ͍ • 1൪؆୯ͳͷ͸init(cgColor:)ͰCGColorΛ౉ͯ͠͠·͏΍Γํ • CGColorͷΠχγϟϥΠβͳΒ৭ۭؒΛࢦఆՄೳ ↓Πϝʔδ͸͜Μͳײ͡↓ init(myWhite: CGFloat,

    alpha: CGFloat) {
 super.init(cgColor: CGColor(
 colorSpace: // ここに色空間
 components: // ここにコンポーネント値
 ))!
 }
  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ͳΒͳΜͱ͔ɻ
  27. ิ଍ɿmethod dispatch • ͲͷϝιουΛݺͼग़͔͢Λܾఆ͢Δ࢓૊Έͷ͜ͱ • static dispatchʢίϯύΠϧ࣌ʹܾఆʣ • struct΍enum΍finalͱ͍ͬͨΦʔόʔϥΠυෆՄͳ΋ͷ͕ͬͪ͜ •

    extensionͰ௥Ճͨ͠ϝιου΋ͬͪ͜ • dynamic dispatchʢίϯύΠϧ࣌ʹtable࡞੒ɺ࣮ߦ࣌ʹܾఆʣ • ΦʔόʔϥΠυՄೳͳ΋ͷ͸ͬͪ͜ • extensionͰޙ෇͚ͨ͠ϝιου͸tableʹೖΕͯ΋Β͑ͳ͍ આ໌ؒҧͬͯͨΒ͝ΊΜͳ͍͞ʂ
  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) }
 }
  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)
  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→
  31. ୈ2஄ɿ UIDynamicProviderColorΛύΫΔ

  32. ৽͍͠Ϟσϧͬͯ΍ͭΛ࡞Γ͍ͨ • ಈతʹ৭Λܾఆ͢Δɺશ͘৽͍͠ϞσϧͷUIColorΛ࡞Δͧʂ • UIDynamicProviderColorͱಉ͡΋ͷΛ࡞Δ͜ͱʹ௅ઓ • init(myDynamicProvider:)ͳײ͡Ͱ • ࠓճ͸ObjCͰؤுΔʢมͳॻ͖ํͯͨ͠ΒεϛϚηϯʣ ↓Πϝʔδ͸͜Μͳײ͡↓

    self = [super init];
 if (self) {
 _myDynamicProvider = myDynamicProvider;
 }
 return self;
  33. ຊདྷඞਢͳ৘ใΛൈ͖ʹ࡞͍ͬͯ͘ • طଘΠχγϟϥΠβ΁৭ۭؒ&ίϯϙʔωϯτ஋Λ౉ͣ͞ʹܧঝ͢ΔͳΒɺ
 UIColorͷϓϩύςΟ΍ϝιουΛશͯਖ਼͘͠ΦʔόʔϥΠυ͢Δඞཁ͕͋Δ • ઌ΄Ͳͷ[super init]͚ͩͰ͸ΫϥογϡͷݪҼʹͳΔ • UIColorͷϝιου͚ͩͰͳ͘isEqual:ͷΦʔόʔϥΠυ΋๨Εͣʹ •

    ৭ͷ౳஋൑ఆॲཧ΋͜ΕΒͷ৘ใʹґଘ͍ͯ͠ΔͨΊ *** -CGColor not defined for the UIColor <ུ>; need to first convert colorspace.
  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
  35. Objective CͰ࣮૷ͯ͠Έͨ(2/3) Ұ෦ @implementation UIColor(MyColor) + (UIColor * _Nonnull)initWithMyDynamicProvider:(UIColor *

    _Nonnull (^ _Nonnull)(UITraitCollection * _Nonnull traitCollection))myDynamicProvider { return [[MyDynamicColor alloc] initWithMyDynamicProvider:myDynamicProvider]; } @end
  36. Objective CͰ࣮ߦͯ͠Έͨ • Dark Modeʹͯ͠΋৭͕มΘΒͳ͍ɻɻɻ UIColor(myDynamicProvider: {
 $0.userInterfaceStyle == .dark

    ? .red : .blue
 })
  37. Objective CͰ࣮૷ͯ͠Έͨ(3/3) • _isDynamicΛΦʔόʔϥΠυͯ͠ਅʹ͠ͳ͍ͱมԽ͠ͳ͍ • privateͳϓϩύςΟͳΜͰ͚͢Ͳ…… - (BOOL)_isDynamic { return

    YES; }
  38. ·ͱΊ

  39. Θ͔ͬͨ͜ͱ • Foundation΍UIKitʹ͸ɺClass Clusterͱ͍͏σβΠϯύλʔϯʹଇͬͨΫϥε ͕ଘࡏ͍ͯ͠Δʢ͔΋͠Εͳ͍) • Swiftʹ͸ԑ͕ͳ͍΋ͷ͔΋ɻɻ • Ͳ͏ͯ͠΋sub classΛ࡞Βͳ͚Ε͹͍͚ͳ͍࣌͸৻ॏʹ

    • UIColorͷsub classΛ࡞Δͷ͸େม • SwiftͰ΍Δͷ͸͞Βʹແཧ͕͋Δ • ৭ۭؒͷઃఆ஋Λ͍͡Δ͘Β͍͕ݶ౓ʁ • ΍Ί͓͍ͯͨ΄͏͕͍͍ͱࢥ͍·͢
  40. ങͬͯ΄͍͠ • Dark ModeରԠ͠Α͏ʂ • s-shimotori.booth.pm

  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