Slide 1

Slide 1 text

ϝοηʔδ ػೳվળ׆ಈ shibuya.swift #2 @nakajijapan

Slide 2

Slide 2 text

About Me

Slide 3

Slide 3 text

@nakajijapan Software Engineer GMO PEPABO inc. iOS / Web / OS X

Slide 4

Slide 4 text

GitHub

Slide 5

Slide 5 text

NKJMultiMovieCaptureView NKJMovieComposer NKJPagerViewController PhotoSlider etc Teiten

Slide 6

Slide 6 text

NKJMultiMovieCaptureView NKJMovieComposer NKJPagerViewController PhotoSlider etc Teiten SwiftԽʂʂʂʂ

Slide 7

Slide 7 text

minne iOS / Android

Slide 8

Slide 8 text

400 million app download ࠃ಺࠷େͷϋϯυϝΠυϚʔέοτ

Slide 9

Slide 9 text

Google Play™ετΞ ʮ2015೥ϕετΞϓ Ϧʯʹબग़ʂ

Slide 10

Slide 10 text

௠ँ

Slide 11

Slide 11 text

Talk about

Slide 12

Slide 12 text

ϝοηʔδ ػೳվળ׆ಈ

Slide 13

Slide 13 text

ϝοηʔδ ػೳ

Slide 14

Slide 14 text

ϝοηʔδػೳ • 2014೥08݄ϦϦʔε • ࡞Ո͞ΜͱίϛϡχέʔγϣϯͰ͖Δ • ؾܰʹϝοηʔδަ׵ͯ͠΄͍͠

Slide 15

Slide 15 text

ϝοηʔδػೳվળ׆ಈ • ܦҢ • มߋ಺༰ • ϝοηʔδೖྗ • Ұཡ • ·ͱΊ

Slide 16

Slide 16 text

ܦҢ

Slide 17

Slide 17 text

ܦҢ • όʔδϣϯΞοϓͰΠϯλʔϑΣʔε ΛҰ৽͕ͨ͠ɺΠϯλϥΫγϣϯͷ վળ͸์ஔؾຯͩͬͨ • ཁ๬΍όάͷ૿Ճ

Slide 18

Slide 18 text

ܦҢ • όʔδϣϯΞοϓͰΠϯλʔϑΣʔε ΛҰ৽͕ͨ͠ɺΠϯλϥΫγϣϯͷ վળ͸์ஔؾຯͩͬͨ • ཁ๬΍όάͷ૿Ճ ΋ͬͱ҆৺͍ͤͨ͞ʂ

Slide 19

Slide 19 text

վળ

Slide 20

Slide 20 text

લఏ஌ࣝ

Slide 21

Slide 21 text

Text Kit

Slide 22

Slide 22 text

UITextView • ෳ਺ߦͷςΩετྖҬɾεΫϩʔϧΛ؅ཧ͢Δ • Πϯελϯεੜ੒࣌ʹҎԼͷΠϯελϯε΋ੜ੒ • NSTextContainer • NSLayoutManager • NSTextStorage • ͍ͣΕ΋readOnly

Slide 23

Slide 23 text

Text Kit • NSTextContainer • ςΩετͷ࠲ඪͱܗঢ়Λ؅ཧ • NSLayoutManager • ϨΠΞ΢τͱϨϯμϦϯάΛௐ੔ • NSTextStorage • NSMutableAttributedStringͷαϒΫϥε

Slide 24

Slide 24 text

ϝοηʔδೖྗ

Slide 25

Slide 25 text

ϝοηʔδೖྗ • Growing Text View • ಈతʹTextྖҬΛ֦ு͢Δ • ϦΞϧλΠϜϓϨϏϡʔ • ૹ৴ͨ͠ঢ়ଶͱಉ͡΋ͷΛදࣔ͢Δ

Slide 26

Slide 26 text

MITextInputView MITextView NSLayoutConstraint *heightConstraint;

Slide 27

Slide 27 text

Growing Text View • ೖྗͨ࣌͠ͷΠϕϯτΛܭଌ͢Δ • ߴ͞Λܭଌ͠ɺViewΛߋ৽͢Δ

Slide 28

Slide 28 text

Growing Text View [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:UITextViewTextDidChangeNotification object:nil];

Slide 29

Slide 29 text

Growing Text View ςΩετ UITextView

Slide 30

Slide 30 text

roundf(textView.font.lineHeight * numberOfLines) textView.textContainerInset.bottom textView.textContainerInset.top Growing Text View ςΩετ UITextView

Slide 31

Slide 31 text

Growing Text View • ྖҬ֦େ࣌ͷ࠷େ஋Λߦ਺Ͱࢦఆ • ࡉ͔͍ߴ͞ͷௐ੔͕Մೳ • ΫϥεΛར༻͢Δ΋ͷ͕ຖ౓ߴ͞Λ ҙࣝ͠ͳͯ͘ࡁΉ

Slide 32

Slide 32 text

վߦҐஔͷݻఆ վߦ࣌͸ ΧʔιϧΛৗʹ࠷ԼҐʹ ഑ஔͰ͖ΔΑ͏ʹ͢Δ

Slide 33

Slide 33 text

վߦҐஔͷݻఆ • ࠷େߦ਺ҎԼ • Viewͷ੍໿ʢߴ͞ʣΛߋ৽͢Δ • ৗʹ࠷্෦΁εΫϩʔϧͤ͞Δ • ࠷େߦ਺Λ௒͑ͨ • Viewͷ੍໿ʢߴ͞ʣΛߋ৽͢Δ • ৗʹ࠷Լ෦΁εΫϩʔϧͤ͞Δ

Slide 34

Slide 34 text

վߦҐஔͷݻఆ [self.textView setContentOffset:CGPointMake(0.f, 0.f) animated:NO]; if (self.textView.selectedRange.location == self.textView.text.length) { NSRange range = NSMakeRange(self.textView.text.length, 0.f); self.textView.selectedRange = range; CGFloat scrollY = self.textView.contentSize.height - self.textView.bounds.size.height; if (scrollY < 0.f) { scrollY = 0.f; } CGPoint scrollPoint = CGPointMake(0.f, scrollY); [self.textView setContentOffset:scrollPoint animated:YES]; } ࠷େߦ਺Ҏ಺ ࠷େߦ਺Ҏ্

Slide 35

Slide 35 text

ϦΞϧλΠϜ ϓϨϏϡʔ

Slide 36

Slide 36 text

ϦΞϧλΠϜϓϨϏϡʔ

Slide 37

Slide 37 text

ϦΞϧλΠϜϓϨϏϡʔ

Slide 38

Slide 38 text

ϦΞϧλΠϜϓϨϏϡʔ

Slide 39

Slide 39 text

ϦΞϧλΠϜϓϨϏϡʔ

Slide 40

Slide 40 text

ϦΞϧλΠϜϓϨϏϡʔ • ը૾౤ߘͷϩδοΫΛվળ • ࠓ·Ͱ • ը૾બ୒࣌ʹαʔόʹPOST • TextViewʹදࣔ͞ΕΔͷ͸ͦͷURL

Slide 41

Slide 41 text

ϦΞϧλΠϜϓϨϏϡʔ • ը૾౤ߘͷϩδοΫΛվળ • ࠓ·Ͱ • ը૾બ୒࣌ʹαʔόʹPOST • TextViewʹදࣔ͞ΕΔͷ͸ͦͷURL ➡ϝοηʔδૹ৴࣌ʹ·ͱΊͯૹ৴ ➡౤ߘͨ͠ը૾ΛϓϨϏϡʔͤ͞Δ

Slide 42

Slide 42 text

ϦΞϧλΠϜϓϨϏϡʔ NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.textInputView.textView.attributedText]; NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init]; textAttachment.image = image; textAttachment.bounds = CGRectMake(0.f,0.f,100.f,100.f); NSAttributedString *attrStringWithImage = [NSAttributedString attributedStringWithAttachment:textAttachment]; [attributedString replaceCharactersInRange:self.textInputView.textView.selectedRange withAttributedString:attrStringWithImage]; [self.textInputView setAttributedText:attributedString]; ը૾બ୒࣌

Slide 43

Slide 43 text

ϦΞϧλΠϜϓϨϏϡʔ NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.textInputView.textView.attributedText]; NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init]; textAttachment.image = image; textAttachment.bounds = CGRectMake(0.f,0.f,100.f,100.f); NSAttributedString *attrStringWithImage = [NSAttributedString attributedStringWithAttachment:textAttachment]; [attributedString replaceCharactersInRange:self.textInputView.textView.selectedRange withAttributedString:attrStringWithImage]; [self.textInputView setAttributedText:attributedString]; ը૾બ୒࣌ ը૾ͷૠೖ

Slide 44

Slide 44 text

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.textInputView.textView.attributedText]; NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init]; textAttachment.image = image; textAttachment.bounds = CGRectMake(0.f,0.f,100.f,100.f); NSAttributedString *attrStringWithImage = [NSAttributedString attributedStringWithAttachment:textAttachment]; [attributedString replaceCharactersInRange:self.textInputView.textView.selectedRange withAttributedString:attrStringWithImage]; [self.textInputView setAttributedText:attributedString]; ը૾બ୒࣌ Χʔιϧʹ͋ΔҐஔʹը૾Λૠೖ ը૾બ୒ޙͷಈ͖

Slide 45

Slide 45 text

ը૾બ୒ޙͷಈ͖ ݱࡏͷߴ͞Λࢉग़ͯ͠ TextViewྖҬΛ޿͛Δ

Slide 46

Slide 46 text

TextViewͷྖҬΛ֦ு self.textViewHeightConstraint.constant = [self heightForLines:self.maxNumberOfLines];

Slide 47

Slide 47 text

ొ࿥ॲཧ

Slide 48

Slide 48 text

ϝοηʔδૹ৴ - վળલ • ը૾બ୒࣌ʹ௨৴ͯ͠ը૾Λొ࿥ • ͦͷޙɺURLΛऔಘ͢Δ • ϝοηʔδొ࿥ • ੔ܗ͞Εͨϝοηʔδͷૹ৴

Slide 49

Slide 49 text

ϝοηʔδૹ৴ - վળޙ • ϝοηʔδొ࿥࣌ͷྲྀΕ • ొ࿥͞Εͨը૾ͷૹ৴ • औಘͨ͠ը૾URLͱը૾Λஔ׵ • ੔ܗ͞Εͨϝοηʔδͷૹ৴

Slide 50

Slide 50 text

GCD

Slide 51

Slide 51 text

GCD • dispatch queue ͱ͍͏ΩϡʔʹॲཧΛߦ͍ͨ ͍಺༰(λεΫ)Λ௥Ճͯ͠ߦ͘ • Ωϡʔʹ௥Ճ͞ΕͨλεΫ͸FIFOͰॱ൪ʹ࣮ ߦ͞ΕΔ • λεΫͷ࣮ߦ͸ผεϨου্Ͱ࣮ߦ͞ΕΔ IUUQTHJUIVCDPNNJYJJODJ045SBJOJOHXJLJ(SBOE$FOUSBM%JTQBUDI

Slide 52

Slide 52 text

dispatch group • ͍͔ͭ͘ͷॲཧΛ෼ࢄͯ͠ߦ͍͍ͨɺ ͦͯ͠෼ࢄͯ͠ॲཧΛߦͬͨ݁ՌΛ ·ͱΊͯར༻͍ͨ͠ɺͱ͍ͬͨ࣌ʹ ར༻Ͱ͖Δ΋ͷ IUUQTHJUIVCDPNNJYJJODJ045SBJOJOHXJLJ(SBOE$FOUSBM%JTQBUDI

Slide 53

Slide 53 text

ϝοηʔδૹ৴ ϝοηʔδૹ৴ - վળલ

Slide 54

Slide 54 text

άϧʔϓ։࢝ ऴྃॲཧ ؔ࿈෇͚։࢝ EJTQBUDI@HSPVQ@FOUFS ؔ࿈෇͚ऴྃ ը૾ొ࿥ ϝοηʔδૹ৴ EJTQBUDI@HSPVQ@MFBWF EJTQBUDI@HSPVQ@OPUJGZ EJTQBUDI@HSPVQ@DSFBUF ϝοηʔδૹ৴ - վળޙ

Slide 55

Slide 55 text

άϧʔϓ։࢝ ऴྃॲཧ ؔ࿈෇͚։࢝ EJTQBUDI@HSPVQ@FOUFS ؔ࿈෇͚ऴྃ ը૾ొ࿥ ϝοηʔδૹ৴ EJTQBUDI@HSPVQ@MFBWF EJTQBUDI@HSPVQ@OPUJGZ EJTQBUDI@HSPVQ@DSFBUF ϝοηʔδૹ৴ - վળޙ ը૾ͷ഑ஔҐஔΛอ͍࣋ͯ͠Ε͹ ॱෆಉʹͳͬͯ΋໰୊ͳ͍

Slide 56

Slide 56 text

ϝοηʔδૹ৴ self.dispatchGroup = dispatch_group_create(); // attributedString͔Βը૾Λநग़ if (images.count > 0) { for (UIImage *tmpImage in images) { [self sendImage:tmpImage]; } } dispatch_group_notify(self.dispatchGroup, dispatch_get_main_queue(), ^{ [self operationDidFinishWithAttributedString:attributedString indexPath:indexPath]; }); dispatch_group_enter(self.dispatchGroup); // snip AFHTTPRequestOperation *operation = [client HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) { // snip dispatch_group_leave(self.dispatchGroup); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { dispatch_group_leave(self.dispatchGroup); }]; [self.messageQueue addOperation:operation]; άϧʔϓͷ࡞੒

Slide 57

Slide 57 text

ϝοηʔδૹ৴ self.dispatchGroup = dispatch_group_create(); self.savedImageTags = [NSMutableArray array]; // snip if (images.count > 0) { for (UIImage *tmpImage in images) { [self sendImage:tmpImage]; } } dispatch_group_notify(self.dispatchGroup, dispatch_get_main_queue(), ^{ [self operationDidFinishWithAttributedString:attributedString indexPath:indexPath]; }); dispatch_group_enter(self.dispatchGroup); // snip AFHTTPRequestOperation *operation = [client HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) { // snip dispatch_group_leave(self.dispatchGroup); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { dispatch_group_leave(self.dispatchGroup); }]; [self.messageQueue addOperation:operation]; ؔ࿈෇͚։࢝ ؔ࿈෇͚ऴྃ

Slide 58

Slide 58 text

ϝοηʔδૹ৴ self.dispatchGroup = dispatch_group_create(); // attributedString͔Βը૾Λநग़ if (images.count > 0) { for (UIImage *tmpImage in images) { [self sendImage:tmpImage]; } } dispatch_group_notify(self.dispatchGroup, dispatch_get_main_queue(), ^{ [self operationDidFinishWithAttributedString:attributedString indexPath:indexPath]; }); dispatch_group_enter(self.dispatchGroup); // snip AFHTTPRequestOperation *operation = [client HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) { // snip dispatch_group_leave(self.dispatchGroup); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { dispatch_group_leave(self.dispatchGroup); }]; [self.messageQueue addOperation:operation]; ϝοηʔδొ࿥ॲཧ

Slide 59

Slide 59 text

࠶ૹॲཧ

Slide 60

Slide 60 text

࠶ૹॲཧ • λΠϜΞ΢τ࣌ • ࣦഊͨ͜͠ͱΛ௨஌ • ࠶ૹͰ͖Δঢ়ଶʹ

Slide 61

Slide 61 text

Ұཡ

Slide 62

Slide 62 text

Ұཡ • ٯʹϖʔδϯά͢Δํ๏ • ௨ৗͷϖʔδϯά • ٯʹ͢Δͱͳʹ͕໰୊͔

Slide 63

Slide 63 text

ϖʔδϯά

Slide 64

Slide 64 text

௨ৗͷϖʔδϯά Loading

Slide 65

Slide 65 text

௨ৗͷϖʔδϯά - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { if (section == 1) { self.indicatorView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"MIIndicatorFooterView"]; [self getReviews]; return self.indicatorView; } return nil; } FooterView͕දࣔ͞ΕͨλΠϛϯάͰߦ͏

Slide 66

Slide 66 text

௨ৗͷϖʔδϯά - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { if (section == 1) { self.indicatorView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"MIIndicatorFooterView"]; [self getReviews]; return self.indicatorView; } return nil; } FooterView͕දࣔ͞ΕͨλΠϛϯάͰߦ͏ ϔομʹҠಈ͢Ε͹͍͍ͷͰ͸ʁ

Slide 67

Slide 67 text

௨ৗͷϖʔδϯά - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { if (section == 1) { self.indicatorView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"MIIndicatorFooterView"]; [self getReviews]; return self.indicatorView; } return nil; } FooterView͕දࣔ͞ΕͨλΠϛϯάͰߦ͏ ϔομʹҠಈ͢Ε͹͍͍ͷͰ͸ʁ

Slide 68

Slide 68 text

Կ͕໰୊͔ • σʔλ্͕෦ʹ௥Ճ͞Ε͍ͯ͘ • reloadData()࣌ʹcontentOffsetͷ஋͕ ͣΕΔ • ׳ੑ͕࢒͍ͬͯΔঢ়گͩͱڧ੍తʹ Ҡಈ͞Εͯ͠·͏

Slide 69

Slide 69 text

ௐࠪ • ඪ४ϝοηʔδΞϓϦͷಈ͖ • දࣔ࣌ʹϩʔσΟϯά։࢝ • ׳ੑεΫϩʔϧ͕ఀࢭͨ͠λΠϛϯ άͰऔಘ։࢝

Slide 70

Slide 70 text

ௐࠪ • ඪ४ϝοηʔδΞϓϦͷಈ͖ • දࣔ࣌ʹϩʔσΟϯά։࢝ • ׳ੑεΫϩʔϧ͕ఀࢭͨ͠λΠϛϯ άͰऔಘ։࢝

Slide 71

Slide 71 text

ղܾࡦ • ׳ੑεΫϩʔϧ͕ఀࢭͨ͠ • ScrollToTop࣌͸׳ੑεΫϩʔϧ͕ൃ ੜ͠ͳ͍ - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView

Slide 72

Slide 72 text

·ͱΊ

Slide 73

Slide 73 text

·ͱΊ • ࡉ͔͍UXͷվળ • ςΩετೖྗɺ௨৴ॲཧɺϖʔδϯά • ͍ΖΜͳΞϓϦͷUXΛૢ࡞ɾݕূɺϓ ϥάΠϯͷ࣮૷ΛಡΜͩΓ͢Δͱࢳޱ ͕ݟ͑Δ

Slide 74

Slide 74 text

ࢀߟ JSQMessagesViewController SlackTextViewController etc

Slide 75

Slide 75 text

Thanks.