安定的 60 fps をめざす / the way to 60 fps

86b45faad28dfccd89b4ec04ef00c62e?s=47 Taishi Ikai
January 29, 2018

安定的 60 fps をめざす / the way to 60 fps

iOS app
at Otemachi.swift x Kyobashi.swift #02
https://kyobashi-swift.connpass.com/event/75379/

86b45faad28dfccd89b4ec04ef00c62e?s=128

Taishi Ikai

January 29, 2018
Tweet

Transcript

  1. 1 ҆ఆత 60 fps ΛΊ͟͢ ழࣂ େࢤ ೔ຊܦࡁ৽ฉࣾ Otemachi.swift x

    Kyobashi.swift #02
  2. <ಈը>

  3. 3 FPS ͸ Frames Per Second ͷུ 1 ඵؒʹදࣔ͢ΔϑϨʔϜ਺ ͜Ε͕େ͖͍ͱɺ׈Β͔ʹݟ͑ΔʢňψϧψϧʼnײɺUX

    ʹӨڹ͢ΔԾઆʣ UIScreen.main.maximumFramesPerSecond ࠷େ FPS Λऔಘ͢ΔɻiOS σόΠεͰ͸ɺ௨ৗ 60 ϝΠϯεϨουͰߦ͏ॲཧͷ਺ͱॏ͞ΛۃྗݮΒͯ͠ɺ࣮ݱΛ໨ࢦ͢ ࠓ͔Β͸ɺҰൠతͳઓུͱɺView ଆʹϑΥʔΧεͨ͠࿩Λ͠·͢ FPS ʹ͍ͭͯ
  4. 4 ඞཁͳ͜ͱ͚ͩ͢Δ UIεϨουΛܰ͘͢ΔɺϒϩοΫ͠ͳ͍ Կ౓΋͠ͳ͍ ଎͘͢Δ ༧Ί΍Δ → Instruments Λݟͳ͕Βɺॏ͍ͱ͜Ζ͔ΒରԠΛ͍ͯ͘͠ FPS

    ͸໨ࢹʹΑΔ֬ೝɺInstruments ͷ Core Animation Ͱ֬ೝ ՄೳͳݶΓݹ͍୺຤Λར༻ ํ਑
  5. 5 ͦͷ࣌఺ͰෆཁͳσʔλΛ֎͢ ࢖͍ͬͯͳ͍ϩδοΫΛফ͢ ֤୺຤Ͱ΍Δඞཁ͕͋Δ΋ͷ͚ͩड͚औΔ Ͳͷ୺຤Ͱ΋ಉ͡ॲཧʹͳΔͳΒɺ API Ͱ੔ܗ͓ͯ͘͠ unixtime Ͱड͚औΔͳͲ Ͳ͏ͯ͠΋

    UI εϨου͡Όͳ͍ͱͰ͖ͳ͍͜ͱ͚ͩ΍Δ ❌ ௨৴΍σΟεΫॻ͖ࠐΈ ❌ NSAttributedString ͷੜ੒ɺηϧͷߴ͞ͷܭࢉɺΦϑεΫϦʔϯඳը ඞཁͳ͜ͱ͚ͩ΍Δ
  6. 6 UITableViewCell, UITableView(Header|Footer)View ͳͲ͸࠶ར༻͢Δ εΫϩʔϧͷͨͼʹੜ੒͢Δͱ݁ߏॏ͍ ϖʔδ UI ͳΒɺVC ΋࠶ར༻Ͱ͖Δͱྑͦ͞͏ ಉ͡ΧϥʔɺϑΥϯτɺਖ਼نදݱɺϑΥʔϚολʔ͸࠶ར༻͢Δ

    UIColor, UIFont, NSRegularExpression, DateFormatter, NumberFormatter ຖ౓ੜ੒͢Δඞཁͳ͚Ε͹ఆ਺Խ͢ΔɺΩϟογϡ͢Δ Computed property ͸ຖճධՁ͞ΕΔ νϦπϞͰ݁ߏͳϘτϧωοΫʹͳ͍ͬͯΔ͜ͱ΋ Կ౓΋͠ͳ͍
  7. 7 ߴ଎ͳ DBɺΩϟογϡɺπʔϧΛ࢖͏ Realm ͳͲ ंྠͷ࠶ൃ໌͍ͯ͠ͳ͍͔ UITableViewCell ͷߴ͞ܭࢉɺcell ͷ਺ͳͲ͸ɺ஗Ԇͤ͞ʹ͍͘ ؤுͬͯ଎͘΍Δɺࣄલʹϩʔυ͢Δ

    ଎͘΍Δ
  8. 8 UITableView ͷଓ͖ΛಡΉͱ͖ͳͲɺUITableView ʹηϧΛ௥Ճ͢Δલʹɺ
 ઌʹߴ͞Λܭࢉ͓ͯ͘͠ & ΦϑεΫϦʔϯඳըͪ͠Ό͏ ϝϞϦޮ཰ͷ఺Ͱ͸ɺඍົ͔΋͠Εͳ͍? ༧Ί΍Δ

  9. ۩ମతʹ 9

  10. UITableViewCell Λܧঝ͢ΔΫϥεͰ init() ͳͲͰ UILabel, UIImageView Λ contentView ʹ௥Ճ Constraints,

    StackView Λ͔ͭͬͯ഑ஔ cellForRow(at indexPath:) ͷதͰ dequeueReusableCell(withIdentifier identifier:, for indexPath:) Ͱ
 ηϧΛऔಘ (όοΫάϥ΢ϯυͰ) ը૾Λऔಘͯ͠ UIImageView ʹ౉͢ ηϧͷཁૉ͕૿͑Δʹ࿈Εͯɺॏ͘ͳͬͯ͘Δ 10 UITableView Ͱͷσʔλදࣔ
  11. UITableViewCell Λܧঝ͢ΔΫϥεͰ init() ͳͲͰ UILabel, UIImageView Λ contentView ʹ௥Ճ Constraints,

    StackView Λ͔ͭͬͯ഑ஔ cellForRow(at indexPath:) ͷதͰ dequeueReusableCell(withIdentifier identifier:, for indexPath:) Ͱ
 ηϧΛऔಘ (όοΫάϥ΢ϯυͰ) ը૾Λऔಘͯ͠ UIImageView ʹ౉͢ ηϧͷཁૉ͕૿͑Δʹ࿈Εͯɺॏ͘ͳͬͯ͘Δ 11 UITableView Ͱͷσʔλදࣔ
  12. 12 ҆ఆత 60 fps Λ࣮ݱ͢Δʹ͸ɺAuto Layoutɺ Stack View Ͱ͸೉͍͠ ൺֱత৽͍͠୺຤Ͱ΋ɺཁૉ

    (view) ͕ଟ͘ͳΔͱΧΫ͍ͭͯ͘Δ ಛʹ೔ຊޠ͕ೖΔͱɺϑΥϯτબ୒ ୤ Auto LayoutɺखಈϨΠΞ΢τͷਏΈ ηϧͷߴ͞ܭࢉΛࣗ෼Ͱߦ͏ Ϩϕϧ 1 → 3 ʹ෼͚͓ͯ࿩͠͠·͢ Auto Layout Λ΍ΊΔ
  13. 13 UILabel, UIImageView ͷ frame Λࣗ෼Ͱܭࢉͯ͠഑ஔ͍ͯ͘͠ ৔߹ʹΑͬͯ Auto Resizing Mask

    Λར༻ Auto Layout Ҏલͷ࣌୅Ͱ͸ओྲྀ ίʔυߦ਺͸ׂΓͱ૿Ճ ߴ͞ܭࢉ΋खಈ UILabel, UIImageView ͸ϝΠϯεϨουͰ৮ΕΔඞཁ͕͋ΔͷͰɺ
 NSString, NSAttributedString ͷ boundingRect Λར༻ Ϩϕϧ1: खಈϨΠΞ΢τ + Auto Resizing Mask
  14. 14 UILabel, UIImageView Λ࢖ΘͣʹɺखಈͰඳը͢Δ શͯखಈͰϨΠΞ΢τ UIView (, UITableViewCell) ͷ draw(_:)

    Λ্ॻ͖ͯ͠ɺ
 NSString, NSAttributedString ͷ draw ܥͰॻ͖ࠐΉ NSAttributedString ͸ɺόοΫάϥ΢ϯυͰ૷০͓ͯ͘͠ Ϩϕϧ2: ௚઀ඳ͘
  15. 15 override func draw(_ rect: CGRect) { guard let context

    = UIGraphicsGetCurrentContext() else { return nil } var remainRect = rect var attributedStringRect = self.attributedString.boundingRectCached( scope: "emblem", size: remainRect.size, options: [.usesLineFragmentOrigin, .truncatesLastVisibleLine]) self.attributedString.draw( with: remainRect, options: [.usesLineFragmentOrigin, .truncatesLastVisibleLine], context: nil ) remainRect.origin.y += attributedStringRect.bounds.height remainRect.size.height -= attributedStringRect.bounds.height // // ཁૉͷ਺෼܁Γฦ͢ // UIGraphicsEndImageContext() }
  16. 16 UILabel, UIImageView Λ࢖ΘͣʹɺखಈͰඳը͢Δ drawRect ͤͣʹɺόοΫάϥ΢ϯυͰ UIGraphicsBeginImageContextWithOptions
 ͯ͠ɺίϯςΩετΛ࡞Γɺͦ͜ʹॻ͖ࠐΉ ࠷ऴతʹ͸ɺඳըྖҬͷ CGImage

    Λ࡞͓͍ͬͯͯɺ
 ͦΕΛΩϟογϡ͓ͯ͘͠ ॾʑͷॲཧΛ࣮֬ʹόοΫάϥ΢ϯυʹ
 ࿈Ε͍͚ͯΔͱ͍͏ϝϦοτ Ϩϕϧ3: CGImage ΛόοΫάϥ΢ϯυͰͭͬͯ͘షΔ
  17. 17 Func getImage(with bounds: CGSize) -> CGImage { if let

    image = CacheStore.get(/* ৚݅ */) { return image } // όοΫάϥ΢ϯυΩϡʔͰɺcontext Λ࡞੒ UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0) guard let context = UIGraphicsGetCurrentContext() else { return nil } // ࣗ෼Ͱߴ͞ܭࢉΛ͠ͳ͕ΒɺNSAttributedString ͷ draw ͳͲͰ context ʹॻ͖ࠐΜͰ͍͘ attributedString.draw(with: bounds, options: drawingOptions, context: nil) // ऴΘͬͨΒ makeImage() ͯ͠ context Λऴ͑Δ let image = context.makeImage() UIGraphicsEndImageContext() if let image = image { CacheStore.set(image, forKey: key) } return image } ը૾΋όοΫάϥ΢ϯυͰऔಘͯ͠ɺ
 CGLayer ͷ cgImage ʹషΔ
  18. 18 UIView Ͱ backgroundColor Λ୯৭ʹ
 UIView Ͱ opaque: true ޮՌ͸͋·Γ࣮ײͰ͖ͣ...

    > Blended view layers often cause slow table scrolling.
 https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/MeasuringGraphicsPerformance.html Blended Layers Λͳ͘͢
  19. ϝΠϯεϨουΛۃྗ࢖Θͳ͍ҙ͕ࣝॏཁ όοΫάϥ΢ϯυͰ CGImage ʹॻ͖ࠐΉͷޮՌ͋ͬͨ ඳըʹؔΘΔॲཧΛશͯόοΫάϥ΢ϯυʹ΋͍͚ͬͯͨ ஗͘ͳΓ͗͢Δͱന͍ηϧ͕ը໘ʹͰͯ͘Δ Auto Layout, StackView ΍Ίͯɺ͍ͩͿૣ͘ͳͬͨ

    খ͍͞Օॴ͕ੵ΋ͬͯҾ͔͔ͬΔ͜ͱ͕ଟʑ͋ͬͨ NSAttributedString ΍ UIFont Ͱ΋Ωϟογϡ͔ఆ਺Խ 19 ·ͱΊ 20% 10% 40% 30% खಈϨΠΞ΢τ CGImage νϦ
  20. Pinterest ͷਓ͕ͨͪத৺ʹ։ൃ͍ͯ͠Δඇಉظతͷ UI ඳըϑϨʔϜϫʔΫ
 RxSwift ͱ૊Έ߹Θͤͯ࢖͏ࣄྫ͕গͳ͔ͬͨ &
 View ·ΘΓ૯ͱ͔͕ͬ͑ඞཁͦ͏ͩͬͨͷͰݟૹͬͨ "Native"

    Ͱ͋Δҙٛͱͯ͠ 60 fps ͷୡ੒Λҙ͍ࣝͯ͠Δ
 Core Text ͳͲ௿ϨΠϠʔͳ API ʹ΋ׂΓͱ৮͍ͬͯͨ &
 ஌ݟ͕গͳ͘ϦϦʔε೔ʹؒʹ߹ΘͤΔࣗ৴͕࣋ͯͣɺݟૹͬͨ 20 ࠓޙݕ౼͍ͨ͠ چ໊শ: AsyncDisplayKit
  21. 21 ழࣂ େࢤʢ͍͔͍ ͍ͨ͠ʣ ೔ຊܦࡁ৽ฉࣾॴଐͷΤϯδχΞ ͍ͭͬͯ͘Δ΋ͷ: iPhone ͷ೔ܦిࢠ൛ΞϓϦ iPhone /

    iPad ͷࢴ໘ϏϡʔΞʔΞϓϦ ΞϓϦͷόοΫΤϯυܥ (w/αʔόʔϨε) About me