Swiftで行うアプリ開発 ~Objective-CからSwiftへの移行~

Swiftで行うアプリ開発 ~Objective-CからSwiftへの移行~

IBM Watson Summit 2016 Day2 F2-4の
"Swiftのオープンソース化がもたらすアプリケーションの未来とIBMの取り組み - 進化するアプリ開発の新世界へご招待 -"
の後半の資料です。

Ae276805027a01983503c3edafbdb6b2?s=128

Taiki Suzuki

May 26, 2016
Tweet

Transcript

  1. Swi$Ͱߦ͏ΞϓϦ։ൃ 【F2-4】 ʙObjec*ve-C͔ΒSwi$΁ͷҠߦʙ גࣜձࣾαΠόʔΤʔδΣϯτ ླ໦େو

  2. ࣗݾ঺հ szk-atmosphere SzkAtmosphere CyberAgent, Inc. SAHistoryNavigationViewController MisterFusion URLEmbeddedView

  3. •  Swi$ʹ஫໨͢Δཧ༝ – ݴޠಛੑ – ੒௕εϐʔυ – ίϛϡχςΟ – ϞόΠϧΞϓϦ։ൃͱ΢ΣϒΞϓϦ։ൃ •  ۀ຿ͰͷSwi$ར༻ – Objectve-C͔ΒͷҠߦ – Objectve-Cͱͷڞଘ

    ຊ೔ͷ಺༰
  4. 4XJGUʹ஫໨͢Δཧ༝ ݴޠಛੑ

  5. •  ܕਪ࿦ ݴޠಛੑ

  6. ม਺΍ؔ਺ͷܕΛએݴ͠ͳͯ͘΋ ࣗಈతʹܕΛܾఆ͢Δػߏ ܕਪ࿦ͱ͸

  7. typedef NS_ENUM(NSInteger, TNProfilePath) {! TNProfilePathFollowing,! TNProfilePathFollowers,! TNProfilePathTalk! };! ! TNProfilePath

    profilePath = TNProfilePathTalk;! switch (profilePath) {! case TNProfilePathTalk:! NSLog(@"Talk");! break;! ! case TNProfilePathFollowers:! NSLog(@"Followers");! break;! ! case TNProfilePathFollowing:! NSLog(@"Following");! break;! } 0CKFDUJWF$ͷྫ
  8. let profilePath = TNProfilePath.Talk! switch profilePath {! case .Talk:! print("Talk")!

    ! case .Followers:! print("Followers")! ! case .Following:! print("following")! } ܕਪ࿦
  9. // Objective-C! UIView *view = [UIView new];! view.backgroundColor = [UIColor

    redColor];! ! // Swift! let view = UIView()! view.backgroundColor = .redColor() ܕਪ࿦
  10. ܕͷهड़ΛݮΒ͢͜ͱ͕Ͱ͖ΔͷͰ ৑௕ͳίʔυ͕ݮΔ ܕਪ࿦

  11. •  ܕਪ࿦ •  Op*onalܕ ݴޠಛੑ

  12. ม਺ͷܕͷ௨ৗͷ஋ʹՃ͑ͯ ஋͕ແ͍ঢ়ଶΛอ࣋Ͱ͖Δܕ 0QUJPOBMܕͱ͸

  13. TNUserModel *user = ...; // औಘࣦഊͳͲͰnil NSMutableArray *array = [NSMutableArray

    array]; [array addObject:user]; // <- Ϋϥογϡ! 0CKFDUJDF$ͰͷOJMͷѻ͍
  14. 0CKFDUJDF$ͰͷOJMͷѻ͍ nilνΣοΫΛ͢Δ͜ͱͰճආ͸Մೳ…

  15. TNUserModel *user = ...; // औಘࣦഊͳͲͰnil NSMutableArray *array = [NSMutableArray

    array]; if (user != nil) { [array addObject:user]; } 0CKFDUJDF$ͰͷOJMͷѻ͍
  16. var user: UserModel? = ... // औಘࣦഊͰnil var array =

    [UserModel]() array.append(user) // ίϯύΠϧ࣌఺Ͱ͢ͰʹΤϥʔ 0QUJPOBMܕ
  17. ΞϓϦ࣮ߦ࣌ʹΫϥογϡ͢ΔͷͰ͸ͳ͘ ίϯύΠϧ࣌ʹΤϥʔʹͳΔͨΊ҆શ 0QUJPOBMܕ

  18. 0QUJPOBMܕ var user: UserModel? = ... var array = [UserModel]()

    if let user = user as? UserModel { array.append(user) }
  19. •  ܕਪ࿦ •  Op*onalܕ •  ॊೈͳEnum ݴޠಛੑ

  20. ఆ਺ʹ໊લΛ͚ͭͯऔΓѻ͑Δܕ &OVNͱ͸

  21. typedef NS_ENUM(NSInteger, TNProfilePath) {! TNProfilePathFollowing = 0,! TNProfilePathFollowers = 1,!

    TNProfilePathTalk = 2! }; 0CKFDUJWF$ͷ&OVN
  22. Enum͔ΒPathΛऔಘ͢Δʹ͸… 0CKFDUJWF$ͷ&OVN

  23. ɹ// TNProfilePathManager.m! @implementation TNProfilePathManager! ! static NSArray *kPathList = nil;!

    static dispatch_once_t kOnceToken;! ! + (NSString *)pathWithProfilePath:(TNProfilePath)path {! dispatch_once(&kOnceToken, ^{! kPathList = @[! @"/following", // 0! @"/followers", // 1! @"/talk“ // 2! ];! });! return kPathList[path];! } ! @end 0CKFDUJWF$ͷ&OVN
  24. NSString *path = [TNProfilePathManager pathWithProfilePath:TNProfilePathTalk];! ! NSLog(@“path = %@”, path);

    // "/talk" 0CKFDUJWF$ͷ&OVN
  25. enum ProfilePath: String {! case Following = "/following"! case Followers

    = "/followers"! case Talk = "/talk"! } 3BX7BMVF&OVN
  26. let path = ProfilePath.Talk.rawValue! print(path) // "/talk" 3BX7BMVF&OVN

  27. enum ProfilePath {! case Following(userId: Int, limit: Int)! case Followers(userId:

    Int, limit: Int)! case Talk(talkId: Int)! } "TTPDJBUFE7BMVF&OVN
  28. enum ProfilePath {! case Following(userId: Int, limit: Int)! case Followers(userId:

    Int, limit: Int)! case Talk(talkId: Int)! ! var value: String {! switch self {! case .Following(let userId, let limit):! return "/following?userId=\(userId)&limit=\(limit)"! case .Followers(let userId, let limit):! return "/followers?userId=\(userId)&limit=\(limit)"! case .Talk(let talkId):! return "/talk?talkId=\(talkId)"! }! }! } "TTPDJBUFE7BMVF&OVN
  29. let path = ProfilePath.Following(userId: 192, limit: 30)! print(path.value) // "/following?userId=192&limit=30"

    "TTPDJBUFE7BMVF&OVN
  30. Enumʹ஋Λ࣋ͨͤΔ͜ͱͰΑΓ҆શʹ ॊೈͳ&OVN

  31. •  ܕਪ࿦ •  Op*onalܕ •  ॊೈͳEnum •  δΣωϦΫε ݴޠಛੑ

  32. ܕͷ҆શΛҡ࣋ͭͭ͠ ܕΛύϥϝʔλͱͯ͠ѻ͏͜ͱ͕Ͱ͖Δ δΣωϦΫεͱ͸

  33. - (void)swapIntValues:(NSInteger *)left right:(NSInteger *)right { NSInteger temp = *left;

    *left = *right; *right = temp; } - (void)swapStringValues:(NSString **)left right:(NSString **)right { NSString *temp = *left; *left = *right; *right = temp; } 0CKFDUJWF$ͷྫ
  34. NSInteger a = 10; NSInteger b = 20; [self swapIntValues:&a

    right:&b]; // a = 20, b = 10 NSString *abc = @"abc"; NSString *def = @"def"; [self swapStringValues:&abc right:&def]; // abc = def, def = abc 0CKFDUJWF$ͷྫ
  35. func swapValues<T>(inout left: T, inout _ right: T) { let

    temp = left left = right right = temp } δΣωϦΫε
  36. var a: Int = 10 var b: Int = 20

    swapValues(&a, &b) var abc: String = "abc" var def: String = "def" swapValues(&abc, &def) δΣωϦΫε
  37. δΣωϦΫε ܕͷ҆શΛ୲อͭͭ͠ ༷ʑͳܕΛѻ͏͜ͱ͕Ͱ͖ ৑௕ͳίʔυ͕ݮΔ

  38. •  ܕਪ࿦ •  Op*onalܕ •  ॊೈͳEnum •  δΣωϦΫε •  ԋࢉࢠͷΦʔόʔϩʔυ

    ݴޠಛੑ
  39. +, - ͳͲͷԋࢉࢠʹ௨ৗͷڍಈͱ͸ ҟͳΔڍಈΛՃ͑Δ ԋࢉࢠͷΦʔόʔϩʔυͱ͸

  40. 0CKFDUJWF$ͷྫ Viewͷx, y, width, heightΛഒʹ͍ͨ͠…

  41. UIView *view = ...;! CGRect frame = view.frame;! frame.origin.x *=

    2.0f;! frame.origin.y *= 2.0f;! frame.size.width *= 2.0f;! frame.size.height *= 2.0f;! view.frame = frame; 0CKFDUJWF$ͷྫ
  42. func * (left: CGRect, right: CGFloat) -> CGRect {! return

    CGRect(! x: left.origin.x * right,! y: left.origin.y * right,! width: left.size.width * right,! height: left.size.height * right! )! } ԋࢉࢠͷΦʔόʔϩʔυ
  43. let view: UIView = ...! let frame = view.frame! view.frame

    = frame * 2 ԋࢉࢠͷΦʔόʔϩʔυ
  44. ԋࢉࢠͷΦʔόʔϩʔυ ಉ͡ԋࢉࢠͰࣅͨΑ͏ͳ࣮૷Λ ෳ਺ߦ͏ࡍʹ·ͱΊΔ͜ͱ͕Ͱ͖ΔͷͰ ৑௕ͳίʔυ͕ݮΔ

  45. •  ܕਪ࿦ •  Op*onalܕ •  ॊೈͳEnum •  δΣωϦΫε •  ԋࢉࢠͷΦʔόʔϩʔυ

    •  ΧελϜԋࢉࢠ ݴޠಛੑ
  46. infix operator +- { associativity left precedence 140 }! func

    +- (left: CGFloat, right: CGFloat) -> (CGFloat, CGFloat) {! return (left + right, left - right)! }! ! // (12, 8)! let (plusValue, minusValue) = 10 +- 2 ΧελϜԋࢉࢠ
  47. ௚ײతͰΘ͔Γ΍͍͢ԋࢉࢠΛఆٛͰ͖Δ ΧελϜԋࢉࢠ

  48. 4XJGUʹ஫໨͢Δཧ༝ ੒௕εϐʔυ

  49. •  2014/08 Swi$ 1.0 ੒௕εϐʔυ

  50. •  2014/08 Swi$ 1.0 •  2014/10 Swi$ 1.1 ੒௕εϐʔυ

  51. •  2014/08 Swi$ 1.0 •  2014/10 Swi$ 1.1 •  2015/04

    Swi$ 1.2 ੒௕εϐʔυ
  52. •  classͰsta*c propertyΛ࣋ͯΔΑ͏ʹͳͬͨ   4XJGU

  53. // Swift 1.2ະຬ class Manager { class var sharedInstance: Manager

    { struct Static { static let instance = Manager() } return Static.instance } } // Swift 1.2Ҏ্ class Manager { static let sharedInstance = Manager() } 4XJGU
  54. •  classͰsta*c propertyΛ࣋ͯΔΑ͏ʹͳͬͨ •  ωΠςΟϒͷSet͕௥Ճ͞Εͨ   4XJGU

  55. // Swift 1.2ະຬ override func touchesBegan(touches: NSSet, withEvent event: UIEvent)

    {} // Swift 1.2Ҏ্ override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {} 4XJGU
  56. •  classͰsta*c propertyΛ࣋ͯΔΑ͏ʹͳͬͨ •  ωΠςΟϒͷSet͕௥Ճ͞Εͨ •  as!͕௥Ճ͞ΕͨͨΊɺas!·ͨ͸as?Ͱهड़͠ ͳ͚Ε͹ͳΒͳ͘ͳͬͨ •  etc...

     4XJGU
  57. // Swift 1.2ະຬ let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell //

    Swift 1.2Ҏ্ let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell 4XJGU
  58. •  2014/08 Swi$ 1.0 •  2014/10 Swi$ 1.1 •  2015/04

    Swi$ 1.2 •  2015/09 Swi$ 2.0 ੒௕εϐʔυ
  59. •  guardจ͕௥Ճ͞Εͨ 4XJGU

  60. // Swift 2.0ະຬ if let URL = NSURL(string: "https://...") {

    let request = NSURLRequest(URL: URL) } // Swift 2.0Ҏ্ guard let URL = NSURL(string: "https://...") else { return } let request = NSURLRequest(URL: URL) 4XJGU
  61. •  guardจ͕௥Ճ͞Εͨ •  ΤϥʔϋϯυϦϯά͕௥Ճ͞Εͨ 4XJGU

  62. let data: NSData = ... // Swift 2.0ະຬ var error:

    NSError? let json = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &error) if let error = error { println(error) } // Swift 2.0Ҏ্ do { let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) } catch let error as NSError { print(error) } 4XJGU
  63. •  guardจ͕௥Ճ͞Εͨ •  ΤϥʔϋϯυϦϯά͕௥Ճ͞Εͨ •  Protocol Extensionʹ࣮૷͕Ͱ͖ΔΑ͏ʹ ͳͬͨ •  etc...

    4XJGU
  64. protocol ImageSettable { var imageView: UIImageView! { get set }

    func setImage(image: UIImage?) } extension ImageSettable { func setImage(image: UIImage?) { imageView.image = image } } class UserInfoView: UIView, ImageSettable { @IBOutlet var imageView: UIImageView! var iconImage: UIImage? { didSet { setImage(iconImage) } } } 4XJGU
  65. •  2014/08 Swi$ 1.0 •  2014/10 Swi$ 1.1 •  2015/04

    Swi$ 1.2 •  2015/09 Swi$ 2.0 •  2015/10 Swi$ 2.1 ੒௕εϐʔυ
  66. •  2014/08 Swi$ 1.0 •  2014/10 Swi$ 1.1 •  2015/04

    Swi$ 1.2 •  2015/09 Swi$ 2.0 •  2015/10 Swi$ 2.1 •  2015/12 Swi$ ΦʔϓϯιʔεԽ ੒௕εϐʔυ
  67. h'ps://swi..org/ 4XJGUΦʔϓϯιʔεԽ

  68. h'ps://github.com/apple 4XJGUΦʔϓϯιʔεԽ

  69. •  h'ps://github.com/apple/swi. – 30,000Ҏ্ͷελʔ਺ – 2,500݅Ҏ্ͷPull Request 4XJGUΦʔϓϯιʔεԽ

  70. •  h'ps://github.com/apple/swi. – 30,000Ҏ্ͷελʔ਺ – 2,500݅Ҏ্ͷPull Request •  h'ps://github.com/apple/swi.-evolu<on – 95݅ͷఏҊ – 4XJGU2.2Ͱ࣮૷͞Εͨ΋ͷ͸7݅ – 4XJGU3.0Ͱ࣮૷͞ΕΔ΋ͷ͸35݅

    – ࣮૷͸ܾ·͍ͬͯΔ΋ͷ͸23݅ – ࣮૷͠ͳ͍͜ͱ͕ܾ·͍ͬͯΔ΋ͷ͸9݅ 4XJGUΦʔϓϯιʔεԽ
  71. •  2014/08 Swi$ 1.0 •  2014/10 Swi$ 1.1 •  2015/04

    Swi$ 1.2 •  2015/09 Swi$ 2.0 •  2015/10 Swi$ 2.1 •  2015/12 Swi$ ΦʔϓϯιʔεԽ •  2016/03 Swi$ 2.2 ੒௕εϐʔυ
  72. •  #selector͕ಋೖ͞Εͨ(SE-0021) 4XJGU

  73. // Swift 2.2ະຬ let selector = Selector("handleTapGesture:") let tapGesture =

    UITapGestureRecognizer(target: self, action: selector) // Swift 2.2Ҏ্ let selector = #selector(UserInfoView.handleTapGesture(_:)) let tapGesture = UITapGestureRecognizer(target: self, action: selector) 4XJGU
  74. •  #selector͕ಋೖ͞Εͨ(SE-0021) •  ++, -- ԋࢉࢠ͕ඇਪ঑ͱͳͬͨ(SE-0004) 4XJGU

  75. •  #selector͕ಋೖ͞Εͨ(SE-0021) •  ++, -- ԋࢉࢠ͕ඇਪ঑ͱͳͬͨ(SE-0004) •  CελΠϧͷforϧʔϓ͕ඇਪ঑ʹͳͬͨ (SE-0007) 4XJGU

  76. // Swift 2.2ͰԼهͷهड़Λ͢ΔͱWarning for var i = 0; i <

    100; i++ { print(i) } for var i = 100; i > 0; i-- { print(i) } // Swift 2.2Ͱ΋Warning͕Ͱͳ͍ for i in 0..<100 { print(i) } for i in 100.stride(to: 0, by: -1) { print(i) } 4XJGU
  77. •  #selector͕ಋೖ͞Εͨ SE-0021  •  ++, --ԋࢉࢠ͕ඇਪ঑ͱͳͬͨ SE-0004) •  CελΠϧͷforϧʔϓ͕ඇਪ঑ʹͳͬͨ

    (SE-0007) •  enumʹ@objc͕͚ͭΒΕΔΑ͏ʹͳͬͨ •  etc... 4XJGU
  78. // UserStatus.swift @objc enum UserStatus: Int { case Launch case

    SendSMS case Registered } // ViewController.m #import ”<ProjectName>-Swift.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UserStatus status = UserStatusRegistered; } @end 4XJGU
  79. •  2014/08 Swi$ 1.0 •  2014/10 Swi$ 1.1 •  2015/04

    Swi$ 1.2 •  2015/09 Swi$ 2.0 •  2015/10 Swi$ 2.1 •  2015/12 Swi$ ΦʔϓϯιʔεԽ •  2016/03 Swi$ 2.2 h'ps://developer.apple.com/library/ios/documenta<on/Swi./Conceptual/ Swi._Programming_Language/RevisionHistory.html ੒௕εϐʔυ
  80. 4XJGUʹ஫໨͢Δཧ༝ ίϛϡχςΟ

  81. USZ4XJGU h'p://www.tryswi.conf.com/ @tryswi$conf

  82. USZ4XJGU •  ظؒ –  2016/03/02 ʙ 2016/03/04 •  ։࠵৔ॴ – 

    ौ୩ϚʔΫγςΟ΢Τετ 13֊ גࣜձࣾαΠόʔΤʔδΣϯτ
  83. •  ։࠵ୈҰճ USZ4XJGU

  84. •  ։࠵ୈҰճ •  σΠϦʔ500ਓҎ্͕ࢀՃ – 3ׂ͕ւ֎͔ΒͷࢀՃऀ USZ4XJGU

  85. •  ։࠵ୈҰճ •  σΠϦʔ500ਓҎ্͕ࢀՃ – 3ׂ͕ւ֎͔ΒͷࢀՃऀ •  ొஃऀ͕33ਓ USZ4XJGU

  86. •  ։࠵ୈҰճ •  σΠϦʔ500ਓҎ্͕ࢀՃ – 3ׂ͕ւ֎͔ΒͷࢀՃऀ •  ొஃऀ͕33ਓ •  ໿40ࣾͷεϙϯαʔ USZ4XJGU

  87. •  ։࠵ୈҰճ •  σΠϦʔ500ਓҎ্͕ࢀՃ – 3ׂ͕ւ֎͔ΒͷࢀՃऀ •  ొஃऀ͕33ਓ •  ໿40ࣾͷεϙϯαʔ • 

    τϥϯεϨʔλʹΑΔಉ࣌຋༁ USZ4XJGU
  88. •  ։࠵ୈҰճ •  σΠϦʔ500ਓҎ্͕ࢀՃ – 3ׂ͕ւ֎͔ΒͷࢀՃऀ •  ొஃऀ͕33ਓ •  ໿40ࣾͷεϙϯαʔ • 

    τϥϯεϨʔλʹΑΔಉ࣌຋༁ •  ϋογϡλά͕౰೔ͷτϨϯυʹ USZ4XJGU
  89. h'ps://itunes.apple.com/jp/app/try!/ id1083944488?l=en&mt=8 USZ4XJGU"QQ

  90. USZ4XJGU"QQ

  91. h'ps://github.com/tryswi. USZ4XJGU

  92. •  Do you believe in magic? The making of try!

    Swi$ Conference Tokyo 2016 –  h'ps://www.natashatherobot.com/try-swi.- conference-tokyo-2016/ •  try! Swi$ શ೔ఔฉ͖ى͜͠·ͱΊ –  h'p://niwatako.hatenablog.jp/entry/ 2016/03/05/022452 •  try! Swi$ ࢿྉ·ͱΊ –  h'p://qiita.com/mishimay/items/ 895d676eb9940d75e639 USZ4XJGU
  93. 4XJGUʹ஫໨͢Δཧ༝ ϞόΠϧΞϓϦ։ൃͱ΢ΣϒΞϓϦ։ൃ

  94. Swi$͕ϦϦʔε͞Εͨ͜Ζ͸ Objec*ve-Cͷ୅ΘΔ iOSΞϓϦ։ൃΛߦ͏ݴޠ ϞόΠϧΞϓϦ։ൃͱ΢ΣϒΞϓϦ։ൃ

  95. ϞόΠϧΞϓϦ։ൃΛSwi$Ͱߦ͍ͬͯΔ ΤϯδχΞ͕KituraͷϦϦʔεʹΑΓ ΢ΣϒΞϓϦ։ൃʹ৮ΕΔػձ͕Ͱ͖Δ ϞόΠϧΞϓϦ։ൃͱ΢ΣϒΞϓϦ։ൃ

  96. KituraͷϥΠϑαΠΫϧΛཧղ͢Δ͜ͱͰ ΫϥΠΞϯταΠυͷΤϯδχΞ͕ Swi$Λհͯ͠αʔόʔϓϩάϥϛϯά͕ Ͱ͖ΔΑ͏ʹͳΔ ϞόΠϧΞϓϦ։ൃͱ΢ΣϒΞϓϦ։ൃ

  97. ۀ຿Ͱͷ4XJGUར༻ 0CKFDUJWF$͔ΒͷҠߦ

  98. •  ΑΓ҆શͳίʔυʹͳΔ ͳͥ0CKFDUJWF$͔ΒҠߦ͢΂͖͔

  99. •  ΑΓ҆શͳίʔυʹͳΔ •  ৑௕ͳίʔυΛݮΒͤΔ ͳͥ0CKFDUJWF$͔ΒҠߦ͢΂͖͔

  100. •  ΑΓ҆શͳίʔυʹͳΔ •  ৑௕ͳίʔυΛݮΒͤΔ •  ϝϯςϯφϯε͕͠΍͘͢ͳΔ – Objec*ve-C͸.mɺ.h͕͋ΔͷͰϑΝΠϧ਺͕ ଟ͘ͳΓ͕ͪ ͳͥ0CKFDUJWF$͔ΒҠߦ͢΂͖͔

  101. •  ΑΓ҆શͳίʔυʹͳΔ •  ৑௕ͳίʔυΛݮΒͤΔ •  ϝϯςϯφϯε͕͠΍͘͢ͳΔ – Objec*ve-C͸.mɺ.h͕͋ΔͷͰϑΝΠϧ਺͕ ଟ͘ͳΓ͕ͪ •  ֶੜ΋Swi$ͰiOSΞϓϦ։ൃΛߦ͍ͬͯΔ

    – Swi$͔ΒΞϓϦ։ൃΛ࢝ΊΔਓ΋ࠓޙ૿͑ͯ ͘Δ ͳͥ0CKFDUJWF$͔ΒҠߦ͢΂͖͔
  102. •  .mͷinterface಺ͷpropertyΛ͢΂ͯɺ.hʹҠ͢ 0CKFDUJWF$͔ΒͷҠߦ

  103. •  .mͷinterface಺ͷpropertyΛ͢΂ͯɺ.hʹҠ͢ •  .mͷϝιουΛ͢΂ͯ.hʹఆٛ͢Δ 0CKFDUJWF$͔ΒͷҠߦ

  104. @interface TNQRCodeViewController: UIViewController! ! @property (weak, nonatomic) IBOutlet UIView* qrCodeReaderView;!

    @property (weak, nonatomic) IBOutlet UIView* mainContainerView;! @property (weak, nonatomic) IBOutlet UIButton *toggleButton;! @property (copy, nonatomic) NSString *userName;! ! - (void)showQRCode;! ! @end! IϑΝΠϧ
  105. •  .mͷinterface಺ͷpropertyΛ͢΂ͯɺ.hʹҠ͢ •  .mͷϝιουΛ͢΂ͯ.hʹఆٛ͢Δ •  .hΛBridge-Header.h಺Ͱimport͢Δ 0CKFDUJWF$͔ΒͷҠߦ

  106. •  .mͷinterface಺ͷpropertyΛ͢΂ͯɺ.hʹҠ͢ •  .mͷϝιουΛ͢΂ͯ.hʹఆٛ͢Δ •  .hΛBridge-Header.h಺Ͱimport͢Δ •  Objec*ve-CͷΫϥεͷExtensionΛੜ੒ 0CKFDUJWF$͔ΒͷҠߦ

  107. •  .mͷinterface಺ͷpropertyΛ͢΂ͯɺ.hʹҠ͢ •  .mͷϝιουΛ͢΂ͯ.hʹఆٛ͢Δ •  .hΛBridge-Header.h಺Ͱimport͢Δ •  Objec*ve-CͷΫϥεͷExtensionΛੜ੒ •  Extension಺ͰඞཁͳfuncΛ࣮૷͢Δ

    0CKFDUJWF$͔ΒͷҠߦ
  108. extension TNQRCodeViewController {! @IBAction func didTapToggleControl(sender: UIButton) {! showQRCode()! }!

    ! func createQRCode() {! // QRίʔυੜ੒ॲཧ }! } TXJGUϑΝΠϧ
  109. •  .mͷinterface಺ͷpropertyΛ͢΂ͯɺ.hʹҠ͢ •  .mͷϝιουΛ͢΂ͯ.hʹఆٛ͢Δ •  .hΛBridge-Header.h಺Ͱimport͢Δ •  Objec*ve-CͷΫϥεͷExtensionΛੜ੒ •  Extension಺ͰඞཁͳfuncΛ࣮૷͢Δ

    •  l<ProjectName>-Swi$.hzΛObjec*ve-CͰimportͯ͠ɺ ExtensionͷfuncΛݺͿ 0CKFDUJWF$͔ΒͷҠߦ
  110. #import "<ProjectName>-Swift.h"! ! @implementation TNQRCodeViewController! ! - (void)viewDidLoad {! [super

    viewDidLoad];! ! [self createQRCode];! }! ! @end NϑΝΠϧ
  111. •  .mͷinterface಺ͷpropertyΛ͢΂ͯɺ.hʹҠ͢ •  .mͷϝιουΛ͢΂ͯ.hʹఆٛ͢Δ •  .hΛBridge-Header.h಺Ͱimport͢Δ •  Objec*ve-CͷΫϥεͷExtensionΛੜ੒ •  Extension಺ͰඞཁͳfuncΛ࣮૷͢Δ

    •  l<ProjectName>-Swi$.hzΛObjec*ve-CͰimportͯ͠ɺ ExtensionͷfuncΛݺͿ •  ExtensionʹϝιουΛ͢΂ͯҠߦͰ͖ͨΒɺSwi$ ͰΫϥεΛ࡞Δ 0CKFDUJWF$͔ΒͷҠߦ
  112. •  .mͷinterface಺ͷpropertyΛ͢΂ͯɺ.hʹҠ͢ •  .mͷϝιουΛ͢΂ͯ.hʹఆٛ͢Δ •  .hΛBridge-Header.h಺Ͱimport͢Δ •  Objec*ve-CͷΫϥεͷExtensionΛੜ੒ •  Extension಺ͰඞཁͳfuncΛ࣮૷͢Δ

    •  l<ProjectName>-Swi$.hzΛObjec*ve-CͰimportͯ͠ɺ ExtensionͷfuncΛݺͿ •  ExtensionʹϝιουΛ͢΂ͯҠߦͰ͖ͨΒɺSwi$ ͰΫϥεΛ࡞Δ •  Swi$ͷΫϥεʹ.hͷpropertyΛ͢΂ͯҠ͢ 0CKFDUJWF$͔ΒͷҠߦ
  113. class QRCodeViewController: UIViewController { @IBOutlet weak var qrCodeReaderView: UIView! @IBOutlet

    weak var mainContainerView: UIView! @IBOutlet weak var toggleBu'on: UIBu'on! var userName: String override func viewDidLoad() { super.viewDidLoad() createQRCode() } @IBAc<on func didTapToggleControl(sender: UIBu'on) { showQRCode() } func createQRCode() { // QRίʔυੜ੒ॲཧ } }  TXJGUϑΝΠϧ
  114. ۀ຿Ͱͷ4XJGUར༻ 0CKFDUJWF$ͱͷڞଘᶃ

  115. + (void)sendLogWithCategoryName:(NSString *)categpryName ! pageId:(NSString *)pageId {! // ϩάૹ৴ͷॲཧ }!

    ! [LogPageCategory sendLogWithCategoryName:@"profile" ! pageId:@"/profile/followers"]; ϩάૹ৴ͷྫ
  116. จࣈྻͰCategoryͱPageIdΛ ࢦఆ͍ͯ͠ΔͷͰ ೖྗϛε͕ى͖ΔՄೳੑ͕͋Δ ϩάૹ৴ͷྫ

  117. enum LogPageCategory { case Search (SearchPageId) case Home (HomePageId) case

    Profile (ProfilePageId) case Notification (NotificationPageId) } ϩάૹ৴ͷྫ
  118. protocol PageIdPathGettable { static var CategoryName: String { get }

    var rawValue: Int { get } var value: String { get } var path: String { get } } extension PageIdPathGettable { var path: String { return self.dynamicType.CategoryName + value } } ϩάૹ৴ͷྫ
  119. @objc enum ProfilePageId: Int, PageIdPathGettable { static let CategoryName =

    "profile" case Following case Followers case Talk var value: String { switch self {     case .Following: return "/following" case .Followers: return "/followers" case .Talk: return "/talk” } } } ϩάૹ৴ͷྫ
  120. extension LogPageCategory { var path: String { return pageId.path }

    var categoryName: String { return pageId.dynamicType.CategoryName } private var pageId: PageIdPathGettable { switch self { case .Profile (let pageId): return pageId } } } } ϩάૹ৴ͷྫ
  121. class LogSendManager: NSObject { class func sendLog(logPageCategory logPageCategory: LogPageCategory) {

    let categoryName = logPageCategory.categoryName let path = logPageCategory.path // ϩάΛૹΔॲཧ } } ϩάૹ৴ͷྫ
  122. LogSendManager.sendLog(logPageCategory: .Profile(.Followers)) ϩάૹ৴ͷྫ

  123. EnumͰ஋Λ࣋ͭ͜ͱʹΑͬͯ ͦΕͧΕͷCategoryͱPageId͕ ܕʹରͯ͠1ରnͷؔ܎ʹͳΔͷͰ ύεͷೖྗϛε͕ݮΔ ͷϩάૹ৴ͷྫ

  124. class LogContainer: NSObject { let category: LogPageCategory init(category: LogPageCategory) {

    self.category = category super.init() } } ϩάΛ0CKFDUJWF$ͱڞଘ
  125. class LogContainer: NSObject { let category: LogPageCategory init(category: LogPageCategory) {

    self.category = category super.init() } class func profile(pageId: ProfilePageId) -> LogContainer { return LogContainer(category: .Profile(pageId)) } } ϩάΛ0CKFDUJWF$ͱڞଘ
  126. class LogSendManager: NSObject { class func sendLog(logPageCategory logPageCategory: LogPageCategory) {

    let categoryName = logPageCategory.categoryName() let path = logPageCategory.path() // ϩάΛૹΔॲཧ } class func sendLog(logContainer logContainer: LogContainer) { sendLog(logPageCategory: logContainer.category) } } ϩάΛ0CKFDUJWF$ͱڞଘ
  127. class LogSendManager: NSObject { class func sendLog(logPageCategory logPageCategory: LogPageCategory) {

    let categoryName = logPageCategory.categoryName() let path = logPageCategory.path() // ϩάΛૹΔॲཧ } class func sendLog(logContainer logContainer: LogContainer) { sendLog(logPageCategory: logContainer.category) } } ϩάΛ0CKFDUJWF$ͱڞଘ
  128. LogContainer *container = [LogContainer    profileWithPageId:TNProfilePageIdFollower] [LogSendManager sendLogWithLogContainer:container]; ϩάΛ0CKFDUJWF$ͱڞଘ

  129. ۀ຿Ͱͷ4XJGUར༻ 0CKFDUJWF$ͱͷڞଘᶄ

  130. ͱ͸ h'ps://itunes.apple.com/jp/app/755-nanagogo- zuato-ji-neng/id736573849?mt=8

  131. ͱ͸

  132. ͷϨΠΞ΢τͷྫ

  133. ͷϨΠΞ΢τͷྫ

  134. ͷϨΠΞ΢τͷྫ

  135. ͷϨΠΞ΢τͷྫ

  136. ͷϨΠΞ΢τͷྫ

  137. ͷϨΠΞ΢τͷྫ ଞͷϢʔβʔͷ౤ߘ

  138. ͷϨΠΞ΢τͷྫ Ϣʔβʔͷ౤ߘ ଞͷϢʔβʔͷ౤ߘ

  139. ͷϨΠΞ΢τͷྫ Ϣʔβʔͷ౤ߘ ଞͷϢʔβʔͷ౤ߘ ϦτʔΫ

  140. ͷϨΠΞ΢τͷྫ Ϣʔβʔͷ౤ߘ ଞͷϢʔβʔͷ౤ߘ ϦτʔΫ

  141. ͷϨΠΞ΢τͷྫ Ϣʔβʔͷ౤ߘ ଞͷϢʔβʔͷ౤ߘ ϦτʔΫ

  142. ͷϨΠΞ΢τͷྫ

  143. Viewʹ੍໿Λ͚ͭΔ͜ͱʹΑͬͯ ը໘αΠζͷҟͳΔσόΠεͰ΋ ੍໿ʹैͬͨViewͷϨΠΞ΢τΛߦ͏ "VUPMBZPVUͱ͸

  144. NSLayoutConstraintΛ࢖༻ͯ͠ Viewʹ੍໿Λ͚ͭΔ ίʔυͰ"VUPMBZPVU

  145. TNUserInfoView *userInfoView = [TNUserInfoView new]; userInfoView.translatesAutoresizingMaskIntoConstraints = NO; [self.contentView addSubview:

    userInfoView]; [self.contentView addConstraints:@[ [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f ], [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f ], [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f ], [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f ] ]]; 7JFXʹ੍໿Λ͚ͭΔ
  146. TNUserInfoView *userInfoView = [TNUserInfoView new]; userInfoView.translatesAutoresizingMaskIntoConstraints = NO; [self.contentView addSubview:

    userInfoView]; [self.contentView addConstraints:@[ [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f ], [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f ], [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f ], [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f ] ]]; 7JFXʹ੍໿Λ͚ͭΔ
  147. [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f ]; 7JFXʹ੍໿Λ͚ͭΔ

  148. let userInfoView = UserInfoView() userInfoView.translatesAutoresizingMaskIntoConstraints = false self.contentView.addSubview(userInfoView) self.contentView.addConstraints([ NSLayoutConstraint(item:

    userInfoView, attribute: .Top, relatedBy: .Equal, toItem: self.contentView, attribute: .Top, multiplier: 1, constant: 0), NSLayoutConstraint(item: userInfoView, attribute: .Right, relatedBy: .Equal, toItem: self.contentView, attribute: .Right, multiplier: 1, constant: 0), NSLayoutConstraint(item: userInfoView, attribute: .Left, relatedBy: .Equal, toItem: self.contentView, attribute: .Left, multiplier: 1, constant: 0), NSLayoutConstraint(item: userInfoView, attribute: .Bottom, relatedBy: .Equal, toItem: self.contentView, attribute: .Bottom, multiplier: 1, constant: 0) ]) 7JFXʹ੍໿Λ͚ͭΔ
  149. let userInfoView = UserInfoView() userInfoView.translatesAutoresizingMaskIntoConstraints = false self.contentView.addSubview(userInfoView) self.contentView.addConstraints([ NSLayoutConstraint(item:

    userInfoView, attribute: .Top, relatedBy: .Equal, toItem: self.contentView, attribute: .Top, multiplier: 1, constant: 0), NSLayoutConstraint(item: userInfoView, attribute: .Right, relatedBy: .Equal, toItem: self.contentView, attribute: .Right, multiplier: 1, constant: 0), NSLayoutConstraint(item: userInfoView, attribute: .Left, relatedBy: .Equal, toItem: self.contentView, attribute: .Left, multiplier: 1, constant: 0), NSLayoutConstraint(item: userInfoView, attribute: .Bottom, relatedBy: .Equal, toItem: self.contentView, attribute: .Bottom, multiplier: 1, constant: 0) ]) 7JFXʹ੍໿Λ͚ͭΔ
  150. NSLayoutConstraint(item: userInfoView, attribute: .Top, relatedBy: .Equal, toItem: self.contentView, attribute: .Top,

    multiplier: 1, constant: 0) 7JFXʹ੍໿Λ͚ͭΔ
  151. let userInfoView = UserInfoView() userInfoView.translatesAutoresizingMaskIntoConstraints = false self.contentView.addSubview(userInfoView) self.contentView.addConstraints([ NSLayoutConstraint(item:

    userInfoView, attribute: .Top, relatedBy: .Equal, toItem: self.contentView, attribute: .Top, multiplier: 1, constant: 0), NSLayoutConstraint(item: userInfoView, attribute: .Right, relatedBy: .Equal, toItem: self.contentView, attribute: .Right, multiplier: 1, constant: 0), NSLayoutConstraint(item: userInfoView, attribute: .Left, relatedBy: .Equal, toItem: self.contentView, attribute: .Left, multiplier: 1, constant: 0), NSLayoutConstraint(item: userInfoView, attribute: .Bottom, relatedBy: .Equal, toItem: self.contentView, attribute: .Bottom, multiplier: 1, constant: 0) ]) 7JFXʹ੍໿Λ͚ͭΔ TNUserInfoView *userInfoView = [TNUserInfoView new]; userInfoView.translatesAutoresizingMaskIntoConstraints = NO; [self.contentView addSubview: userInfoView]; [self.contentView addConstraints:@[ [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f ], [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f ], [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f ], [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f ] ]];
  152. h'ps://github.com/szk-atmosphere/MisterFusion

  153. let userInfoView = UserInfoView() self.contentView.addLayoutSubview(view, andConstraints: userInfoView.Top |==| self.contentView.Top |*|

    1 |+| 0, userInfoView.Right |==| self.contentView.Right |*| 1 |-| 0, userInfoView.Left |==| self.contentView.Left |*| 1 |+| 0, userInfoView.Bottom |==| self.contentView.Bottom |*| 1 |-| 0 ) .JTUFS'VTJPO
  154. let userInfoView = UserInfoView() self.contentView.addLayoutSubview(view, andConstraints: userInfoView.Top |==| self.contentView.Top |*|

    1 |+| 0, userInfoView.Right |==| self.contentView.Right |*| 1 |-| 0, userInfoView.Left |==| self.contentView.Left |*| 1 |+| 0, userInfoView.Bottom |==| self.contentView.Bottom |*| 1 |-| 0 ) .JTUFS'VTJPO let userInfoView = UserInfoView() userInfoView.translatesAutoresizingMaskIntoConstraints = false self.contentView.addSubview(userInfoView) self.contentView.addConstraints([ NSLayoutConstraint(item: userInfoView, attribute: .Top, relatedBy: .Equal, toItem: self.contentView, attribute: .Top, multiplier: 1, constant: 0), NSLayoutConstraint(item: userInfoView, attribute: .Right, relatedBy: .Equal, toItem: self.contentView, attribute: .Right, multiplier: 1, constant: 0), NSLayoutConstraint(item: userInfoView, attribute: .Left, relatedBy: .Equal, toItem: self.contentView, attribute: .Left, multiplier: 1, constant: 0), NSLayoutConstraint(item: userInfoView, attribute: .Bottom, relatedBy: .Equal, toItem: self.contentView, attribute: .Bottom, multiplier: 1, constant: 0) ])
  155. public class MisterFusion: NSObject { private let item: UIView? private

    let attribute: NSLayoutAttribute? private let relatedBy: NSLayoutRelation? private let toItem: UIView? private let toAttribute: NSLayoutAttribute? private let multiplier: CGFloat? private let constant: CGFloat? private let priority: UILayoutPriority? private let horizontalSizeClass: UIUserInterfaceSizeClass? private let verticalSizeClass: UIUserInterfaceSizeClass? private let identifier: String? } .JTUFS'VTJPOͷ಺෦
  156. infix operator |==| { associativity left precedence 95 } func

    |==| (left: MisterFusion, right: MisterFusion) -> MisterFusion { return MisterFusion(item: left.item, attribute: left.attribute, relatedBy: .Equal, toItem: right.item, toAttribute: right.attribute, multiplier: nil, constant: nil, priority: nil, horizontalSizeClass: nil, verticalSizeClass: nil, identifier: left.identifier) } .JTUFS'VTJPOͷ಺෦
  157. func addLayoutConstraint(misterFusion: MisterFusion) -> NSLayoutConstraint? { let item: UIView =

    misterFusion.item ?? self let attribute: NSLayoutAttribute = misterFusion.attribute ?? .NotAnAttribute let relatedBy: NSLayoutRelation = misterFusion.relatedBy ?? .Equal let toAttribute: NSLayoutAttribute = misterFusion.toAttribute ?? attribute let toItem: UIView? = toAttribute == .NotAnAttribute ? nil : misterFusion.toItem ?? self let multiplier: CGFloat = misterFusion.multiplier ?? 1 let constant: CGFloat = misterFusion.constant ?? 0 let constraint: NSLayoutConstraint = ... constraint.priority = misterFusion.priority ?? UILayoutPriorityRequired constraint.identifier = misterFusion.identifier addConstraint(constraint) return constraint } .JTUFS'VTJPOͷ಺෦
  158. NSLayoutConstraintͱಉ͡propertyΛ MisterFusionͰอ࣋͠ ΧελϜԋࢉࢠͰద੾ͳ݁߹Λߦ͍ NSLayoutConstraintʹม׵ͯ͠add͢Δ .JTUFS'VTJPOͷ಺෦

  159. var Equal: MisterFusion -> MisterFusion? { return { [weak self]

    in guard let me = self else { return nil } return me |==| $0 } } .JTUFS'VTJPOΛ0CKFDUJWF$Ͱ࢖͏
  160. TNUserInfoView *userInfoView = [TNUserInfoView new]; [self.contentView addLayoutSubview:userInfoView andConstraints:@[ userInfoView.Top .Equal(self.contentView.Top)

    .Multiplier(1.0f).Constant(0.0f), userInfoView.Right .Equal(self.contentView.Right) .Multiplier(1.0f).Constant(0.0f), userInfoView.Left .Equal(self.contentView.Left) .Multiplier(1.0f).Constant(0.0f), userInfoView.Bottom.Equal(self.contentView.Bottom).Multiplier(1.0f).Constant(0.0f) ]]; .JTUFS'VTJPOΛ0CKFDUJWF$Ͱ࢖͏
  161. TNUserInfoView *userInfoView = [TNUserInfoView new]; [self.contentView addLayoutSubview:userInfoView andConstraints:@[ userInfoView.Top .Equal(self.contentView.Top)

    .Multiplier(1.0f) .Constant(0.0f), userInfoView.Right .Equal(self.contentView.Right) .Multiplier(1.0f) .Constant(0.0f), userInfoView.Left .Equal(self.contentView.Left) .Multiplier(1.0f) .Constant(0.0f), userInfoView.Bottom .Equal(self.contentView.Bottom) .Multiplier(1.0f) .Constant(0.0f) ]]; .JTUFS'VTJPOΛ0CKFDUJWF$Ͱ࢖͏ TNUserInfoView *userInfoView = [TNUserInfoView new]; userInfoView.translatesAutoresizingMaskIntoConstraints = NO; [self.contentView addSubview: userInfoView]; [self.contentView addConstraints:@[ [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f ], [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f ], [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f ], [NSLayoutConstraint constraintWithItem:userInfoView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f ] ]];
  162. ࠷ޙʹ

  163. •  ΞϓϦͷ࣮ߦ࣌ʹΤϥʔ͕ى͖ʹ͍͘จ๏ •  ৑௕ͳίʔυͷ࡟ݮ •  ίϛϡχςΟͷ੝Γ্͕Γ 

  164. ͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ szk-atmosphere