Upgrade to Pro — share decks privately, control downloads, hide ads and more …

iosdc-2018-black-magic.pdf

hirose yudai
August 31, 2018
3k

 iosdc-2018-black-magic.pdf

hirose yudai

August 31, 2018
Tweet

Transcript

  1. J04%$
    dd̈̈̈̈࣫ࠇͷຐ๏0CKFDJUWF$3VOUJNF"1*̈̈̈̈dd

    View Slide

  2. ࣗݾ঺հ
    *%CBOO[BJ
    ॴଐגࣜձࣾ"TPCJDB
    ৬ۀ&OHJOFFS
    ݺশελʔޤ৯
    CBOO[BJ
    @CBOO[[email protected]

    View Slide

  3. ࠓ೔͸ͳ͢͜ͱ
    ࠇຐज़✡

    View Slide

  4. ࠓ೔͸ͳ͢͜ͱ
    ࠇຐज़✡

    View Slide

  5. ࠓ೔͸ͳ͢͜ͱ
    "TTPDJBUJWF3FGFSFODFT
    .FUIPE4XJ[[MJOH
    &OVNFSBUJPO.VUBUJPO)BOEMFS

    View Slide

  6. "TTPDJBUJWF3FGFSFODFT

    View Slide

  7. "TTPDJBUJWF3FGFSFODFT
    [email protected]"TTPDJBUFE0CKFDU
    [email protected]"TTPDJBUFE0CKFDU

    View Slide

  8. ࣮૷ͷ׬੒ܗ

    View Slide

  9. ࣮૷ͷ׬੒ܗ

    View Slide

  10. [email protected]"TTPDJBUFE0CKFDU
    [email protected]"TTPDJBUFE0CKFDU JEPCKFDU DPOTUWPJELFZ
    JEWBMVF [email protected]"TTPDJBUJPO1PMJDZQPMJDZ

    Sets an associated value for a given object using a
    given key and association policy.
    ެࣜυΩϡϝϯτ
    [email protected]CKFDU
    MBOHVBHFPCKD

    View Slide

  11. [email protected]"TTPDJBUFE0CKFDU
    [email protected]"TTPDJBUFE0CKFDU JEPCKFDU DPOTUWPJELFZ
    JEWBMVF [email protected]"TTPDJBUJPO1PMJDZQPMJDZ

    Sets an associated value for a given object using a
    given key and association policy.
    ެࣜυΩϡϝϯτ
    [email protected]CKFDU
    MBOHVBHFPCKD
    LFZͱQPMJDZΛ࢖༻ͯ͠౉ͨ͠
    PCKFDUʹWBMVFΛؔ࿈͚ͮΔ

    View Slide

  12. [email protected]"TTPDJBUFE0CKFDU
    [email protected]"TTPDJBUFE0CKFDU JEPCKFDU DPOTUWPJELFZ
    JEWBMVF [email protected]"TTPDJBUJPO1PMJDZQPMJDZ

    Sets an associated value for a given object using a
    given key and association policy.
    ެࣜυΩϡϝϯτ
    [email protected]CKFDU
    MBOHVBHFPCKD
    LFZͱQPMJDZΛ࢖༻ͯ͠౉ͨ͠
    PCKFDUʹWBMVFΛؔ࿈͚ͮΔ

    View Slide

  13. [email protected]"TTPDJBUFE0CKFDU
    id objc_getAssociatedObject(id object, const
    void *key);
    Returns the value associated with a given object for a
    given key.
    ެࣜυΩϡϝϯτ
    [email protected]CKFDU
    MBOHVBHFPCKD

    View Slide

  14. [email protected]"TTPDJBUFE0CKFDU
    id objc_getAssociatedObject(id object, const
    void *key);
    Returns the value associated with a given object for a
    given key.
    ެࣜυΩϡϝϯτ
    [email protected]CKFDU
    MBOHVBHFPCKD
    PCKFDUʹؔ࿈͍ͮͨWBMVFΛLFZΛݩʹฦ͢Ͱ

    View Slide

  15. ࣮૷ͷ׬੒ܗ

    View Slide

  16. $POW
    extension UICollectionView {
    var mainConv: Conv? {
    set {
    dataSource = newValue
    delegate = newValue
    newValue?.collectionView = self
    objc_setAssociatedObject(
    self,
    &UICollectionViewAssociatedObjectHandle.oldConvKey,
    newValue,
    .OBJC_ASSOCIATION_RETAIN_NONATOMIC
    )
    }
    get {
    return objc_getAssociatedObject(
    self,
    &UICollectionViewAssociatedObjectHandle.oldConvKey
    ) as? Conv
    }
    }
    }
    IUUQTHJUIVCDPNCBOO[BJ$POWCMPCNBTUFS$POW$POW6*$PMMFDUJPO7JFX&YUFOTJPOTXJGU

    View Slide

  17. .FUIPE4XJ[[MJOH

    View Slide

  18. .FUIPE4XJ[[MJOH
    - طʹఆٛ͞Ε͍ͯΔϝιουͷ࣮૷ΛೖΕସ͑Δ
    - Swizzle Stick Ͱ͔͖ࠞͥΔ๮Β͍͠ͷͰɺ୯ޠͷΠϝʔδͱ͠
    ͯ͸ͦΜͳײ͡
    - https://eow.alc.co.jp/search?q=swizzle

    View Slide

  19. .FUIPE4XJ[[MJOH
    - ϝιουͷऔಘ
    - class_getInstanceMethod
    - class_getClassMethod
    - ೖΕସ͑Δ
    - method_exchangeImplementations

    View Slide

  20. ϝιουͷએݴ
    - (void)viewDidLoad {
    NSLog(@“viewDidLoad”)
    }
    - (void)_viewDidLoad {
    NSLog(@“_viewDidLoad”)
    }

    View Slide

  21. .FUIPE4XJ[[MJOHͷॲཧ
    Method originalMethod = class_getInstanceMethod([self class],
    @selector(viewDidLoad));
    Method exchangeMethod = class_getInstanceMethod([self class],
    @selector(_viewDidLoad));
    method_exchangeImplementations(originalMethod, exchangeMethod);

    View Slide

  22. .FUIPE4XJ[[MJOHͷॲཧ
    Method originalMethod = class_getInstanceMethod([self class],
    @selector(viewDidLoad));
    Method exchangeMethod = class_getInstanceMethod([self class],
    @selector(_viewDidLoad));
    method_exchangeImplementations(originalMethod, exchangeMethod);

    View Slide

  23. ݺΜͰΈΔ
    ViewController *viewController = [ViewController new];
    [viewController viewDidLoad];
    ྑ͍ࢠ͸Ϛωͪ͠Όμϝͩͧ

    View Slide

  24. ݺΜͰΈΔ
    ViewController *viewController = [ViewController new];
    [viewController viewDidLoad];
    @WJFX%JE-PBE

    View Slide

  25. ϝιουͷએݴ
    - (void)viewDidLoad {
    NSLog(@“viewDidLoad”)
    }
    - (void)_viewDidLoad {
    NSLog(@“_viewDidLoad”)
    }

    View Slide

  26. &YBNQMF

    View Slide

  27. &YBNQMF

    View Slide

  28. &YBNQMF
    - (void)viewDidLoad {
    [super viewDidLoad];
    UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc]
    initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil
    action:nil]
    self.navigationItem.backBarButtonItem = backButtonItem;
    }

    View Slide

  29. &YBNQMF
    + (void)load {
    @autoreleasepool {
    Method originalMethod = class_getInstanceMethod([self class],
    @selector(viewDidLoad));
    Method exchangeMethod = class_getInstanceMethod([self class],
    @selector(_viewDidLoad));
    method_exchangeImplementations(originalMethod,
    exchangeMethod);
    }
    }

    View Slide

  30. &YBNQMF
    + (void)load {
    @autoreleasepool {
    Method originalMethod = class_getInstanceMethod([self class],
    @selector(viewDidLoad));
    Method exchangeMethod = class_getInstanceMethod([self class],
    @selector(_viewDidLoad));
    method_exchangeImplementations(originalMethod,
    exchangeMethod);
    }
    }

    View Slide

  31. ͖ͬ͞ͷ
    .FUIPE4XJ[[MJOHͷॲཧ
    Method originalMethod = class_getInstanceMethod([self class],
    @selector(viewDidLoad));
    Method exchangeMethod = class_getInstanceMethod([self class],
    @selector(exchangedViewDidLoad));
    method_exchangeImplementations(originalMethod, exchangeMethod);

    View Slide

  32. &YBNQMF
    - (void)_viewDidLoad {
    UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc]
    initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil
    action:nil];
    self.navigationItem.backBarButtonItem = backButtonItem;
    [self _viewDidLoad];
    }

    View Slide

  33. &YBNQMF
    - (void)_viewDidLoad {
    UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc]
    initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil
    action:nil];
    self.navigationItem.backBarButtonItem = backButtonItem;
    [self _viewDidLoad];
    }

    View Slide

  34. &YBNQMF
    - (void)_viewDidLoad {
    UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc]
    initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil
    action:nil];
    self.navigationItem.backBarButtonItem = backButtonItem;
    [self _viewDidLoad];
    }

    View Slide

  35. ˞஫ҙ఺
    - (void)viewDidLoad {
    [super viewDidLoad];

    }

    View Slide

  36. 4FHVF"EEJUJPO
    public extension UIViewController {
    fileprivate func swizzling() {
    let prepareForSegue = class_getInstanceMethod(type(of: self),
    #selector(UIViewController.prepare))
    let _prepare = class_getInstanceMethod(type(of: self),
    #selector(UIViewController._prepare(segue:sender:)))
    method_exchangeImplementations(prepareForSegue!, _prepare!)
    }
    public func performSegue(_ withIdentifier: String, closure:
    ((UIStoryboardSegue) -> Void)? = nil) {
    swizzling()
    self.performSegue(withIdentifier: withIdentifier, sender:
    SegueEventHolder(segueClosure: closure))
    swizzling()
    }
    }
    IUUQTHJUIVCDPNCBOO[BJ4FHVF"EEJUJPOCMPCNBTUFS$MBTTFT4FHVF"EEJUJPOTXJGU

    View Slide

  37. &OVNFSBUJPO.VUBUJPO)BOEMFS

    View Slide

  38. &OVNFSBUJPO.VUBUJPO)BOEMFS
    - objc_enumerationMutation
    - objc_setEnumerationMutationHandler

    View Slide

  39. [email protected]
    [email protected] JEPCK

    Inserted by the compiler when a mutation is detected
    during a foreach iteration.
    ެࣜυΩϡϝϯτ
    [email protected]BUJPO
    MBOHVBHFPCKD

    View Slide

  40. [email protected]
    [email protected] JEPCK

    Inserted by the compiler when a mutation is detected
    during a foreach iteration.
    ެࣜυΩϡϝϯτ
    [email protected]BUJPO
    MBOHVBHFPCKD
    ҙ༁GPSFBDIͰJUFSBUJPO͍ͯ͠Δ్தͰ
    ഑ྻʹมߋΛՃ͑Δͱ͜ͷؔ਺ΛׂΓࠐΜͰݺͿΑ

    View Slide

  41. [email protected]
    Discussion
    The compiler inserts this function when it detects that an object is
    mutated during a foreach iteration. The function is called when a
    mutation occurs, and the enumeration mutation handler is enacted if it
    is set up (via
    the objc_setEnumerationMutationHandler function). If the
    handler is not set up, a fatal error occurs.

    View Slide

  42. [email protected]
    Discussion
    The compiler inserts this function when it detects that an object is
    mutated during a foreach iteration. The function is called when a
    mutation occurs, and the enumeration mutation handler is enacted if it
    is set up (via
    the objc_setEnumerationMutationHandler function). If the
    handler is not set up, a fatal error occurs.

    [email protected]&OVNFSBUJPO.VUBUJPO)BOEMFS
    ͰTFUVQ͞Εͨؔ਺͕ηοτ͞Ε͍ͯͳ͔ͬͨΒ
    GBUBMFSSPSΛىͥ͜͢

    View Slide

  43. 'BUBM&SSPSͷݕূ
    NSMutableArray *array = @[@1, @2, @3].mutableCopy;
    for (NSNumber *number in array) {
    [array removeObject:number];
    }

    View Slide

  44. 'BUBM&SSPSͷݕূ
    NSMutableArray *array = @[@1, @2, @3].mutableCopy;
    for (NSNumber *number in array) {
    [array removeObject:number];
    }

    View Slide

  45. 'BUBM&SSPSͷݕূ
    2018-08-31 00:20:49.538515+0900 iOSDC-BlackMagick[65259:1688283] *** Terminating app due to uncaught exception 'NSGenericException', reason: '***
    Collection <__NSArrayM: 0x6000000523f0> was mutated while being enumerated.'
    *** First throw call stack:
    (
    0 CoreFoundation 0x000000011085c1e6 __exceptionPreprocess + 294
    1 libobjc.A.dylib 0x000000010fef1031 objc_exception_throw + 48
    2 CoreFoundation 0x00000001108d004c __NSFastEnumerationMutationHandler + 124
    3 iOSDC-BlackMagick 0x000000010f5ea20c -[ViewController enumerationMutation] + 556
    4 iOSDC-BlackMagick 0x000000010f5e9a69 -[ViewController viewDidLoad] + 393
    5 UIKit 0x0000000110e7d131 -[UIViewController loadViewIfRequired] + 1215
    6 UIKit 0x0000000110ec420c -[UINavigationController _updateScrollViewFromViewController:toViewController:] + 6
    7 UIKit 0x0000000110ec44ea -[UINavigationController _startTransition:fromViewController:toViewController:] +
    136
    8 UIKit 0x0000000110ec561e -[UINavigationController _startDeferredTransitionIfNeeded:] + 870
    9 UIKit 0x0000000110ec686c -[UINavigationController __viewWillLayoutSubviews] + 150
    10 UIKit 0x000000011111ed0b -[UILayoutContainerView layoutSubviews] + 231
    11 UIKit 0x000000012d7e361c -[UILayoutContainerViewAccessibility layoutSubviews] + 42
    12 UIKit 0x0000000110da87a8 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1515
    13 QuartzCore 0x0000000116847456 -[CALayer layoutSublayers] + 177
    14 QuartzCore 0x000000011684b667 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 395
    15 QuartzCore 0x00000001167d20fb _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 343
    16 QuartzCore 0x00000001167ff79c _ZN2CA11Transaction6commitEv + 568
    17 UIKit 0x0000000110cf3269 __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 141
    18 CoreFoundation 0x00000001107feb0c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    19 CoreFoundation 0x00000001107e32db __CFRunLoopDoBlocks + 331
    20 CoreFoundation 0x00000001107e2a84 __CFRunLoopRun + 1284
    21 CoreFoundation 0x00000001107e230b CFRunLoopRunSpecific + 635
    22 GraphicsServices 0x00000001159d0a73 GSEventRunModal + 62
    23 UIKit 0x0000000110cd9057 UIApplicationMain + 159
    24 iOSDC-BlackMagick 0x000000010f5eab0f main + 111
    25 libdyld.dylib 0x00000001142b9955 start + 1
    26 ??? 0x0000000000000001 0x0 + 1
    )
    libc++abi.dylib: terminating with uncaught exception of type NSException

    View Slide

  46. 'BUBM&SSPSͷݕূ
    2018-08-31 00:20:49.538515+0900 iOSDC-BlackMagick[65259:1688283] *** Terminating app due to uncaught exception 'NSGenericException', reason: '***
    Collection <__NSArrayM: 0x6000000523f0> was mutated while being enumerated.'
    *** First throw call stack:
    (
    0 CoreFoundation 0x000000011085c1e6 __exceptionPreprocess + 294
    1 libobjc.A.dylib 0x000000010fef1031 objc_exception_throw + 48
    2 CoreFoundation 0x00000001108d004c __NSFastEnumerationMutationHandler + 124
    3 iOSDC-BlackMagick 0x000000010f5ea20c -[ViewController enumerationMutation] + 556
    4 iOSDC-BlackMagick 0x000000010f5e9a69 -[ViewController viewDidLoad] + 393
    5 UIKit 0x0000000110e7d131 -[UIViewController loadViewIfRequired] + 1215
    6 UIKit 0x0000000110ec420c -[UINavigationController _updateScrollViewFromViewController:toViewController:] + 6
    7 UIKit 0x0000000110ec44ea -[UINavigationController _startTransition:fromViewController:toViewController:] +
    136
    8 UIKit 0x0000000110ec561e -[UINavigationController _startDeferredTransitionIfNeeded:] + 870
    9 UIKit 0x0000000110ec686c -[UINavigationController __viewWillLayoutSubviews] + 150
    10 UIKit 0x000000011111ed0b -[UILayoutContainerView layoutSubviews] + 231
    11 UIKit 0x000000012d7e361c -[UILayoutContainerViewAccessibility layoutSubviews] + 42
    12 UIKit 0x0000000110da87a8 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1515
    13 QuartzCore 0x0000000116847456 -[CALayer layoutSublayers] + 177
    14 QuartzCore 0x000000011684b667 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 395
    15 QuartzCore 0x00000001167d20fb _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 343
    16 QuartzCore 0x00000001167ff79c _ZN2CA11Transaction6commitEv + 568
    17 UIKit 0x0000000110cf3269 __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 141
    18 CoreFoundation 0x00000001107feb0c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    19 CoreFoundation 0x00000001107e32db __CFRunLoopDoBlocks + 331
    20 CoreFoundation 0x00000001107e2a84 __CFRunLoopRun + 1284
    21 CoreFoundation 0x00000001107e230b CFRunLoopRunSpecific + 635
    22 GraphicsServices 0x00000001159d0a73 GSEventRunModal + 62
    23 UIKit 0x0000000110cd9057 UIApplicationMain + 159
    24 iOSDC-BlackMagick 0x000000010f5eab0f main + 111
    25 libdyld.dylib 0x00000001142b9955 start + 1
    26 ??? 0x0000000000000001 0x0 + 1
    )
    libc++abi.dylib: terminating with uncaught exception of type NSException
    5FSNJOBUJOHBQQEVFUPVODBVHIUFYDFQUJPO/4(FOFSJD&YDFQUJPO SFBTPO
    [email protected]@/4"SSBZ.YGXBTNVUBUFEXIJMF
    CFJOHFOVNFSBUFE

    View Slide

  47. [email protected]
    Discussion
    The compiler inserts this function when it detects that an object is
    mutated during a foreach iteration. The function is called when a
    mutation occurs, and the enumeration mutation handler is enacted if it
    is set up (via
    the objc_setEnumerationMutationHandler function). If the
    handler is not set up, a fatal error occurs.

    View Slide

  48. [email protected]&OVNFSBUJPO.VUBUJPO)BOEMFS
    [email protected]&OVNFSBUJPO.VUBUJPO)BOEMFS WPJE IBOEMFS

    JE


    Sets the current mutation handler.
    ެࣜυΩϡϝϯτ
    [email protected]NVUBUJPOIBOEM
    MBOHVBHFPCKD

    View Slide

  49. [email protected]&OVNFSBUJPO.VUBUJPO)BOEMFS
    [email protected]&OVNFSBUJPO.VUBUJPO)BOEMFS WPJE IBOEMFS

    JE


    Sets the current mutation handler.
    ެࣜυΩϡϝϯτ
    [email protected]NVUBUJPOIBOEM
    MBOHVBHFPCKD
    ҙ༁มߋ͞Εͨ࣌ͷॲཧΛTFU͢Δͥ

    View Slide

  50. ࢖ͬͯΈͨ
    void function(NSMutableArray *array) {
    NSLog(@"array: %@", array);
    }
    - (void)enumerationMutation {
    objc_setEnumerationMutationHandler(function);
    NSMutableArray *array = @[@1, @2, @3].mutableCopy;
    for (NSNumber *number in array) {
    [array removeObject:number];
    }
    }

    View Slide

  51. ࢖ͬͯΈͨ
    void function(NSMutableArray *array) {
    NSLog(@"array: %@", array);
    }
    - (void)enumerationMutation {
    objc_setEnumerationMutationHandler(function);
    NSMutableArray *array = @[@1, @2].mutableCopy;
    for (NSNumber *number in array) {
    [array removeObject:number];
    }
    }

    View Slide

  52. ࢖ͬͯΈͨ
    void function(NSMutableArray *array) {
    NSLog(@"array: %@", array);
    }
    - (void)enumerationMutation {
    objc_setEnumerationMutationHandler(function);
    NSMutableArray *array = @[@1, @2].mutableCopy;
    for (NSNumber *number in array) {
    [array removeObject:number];
    }
    }

    View Slide

  53. ϩά
    array: (
    2,
    3
    )
    array: (
    3
    )

    View Slide

  54. ࢖ͬͯΈͨ
    void function(NSMutableArray *array) {
    NSLog(@“͓ئ͍ࢮͳͳ͍Ͱʂ”);
    }
    - (void)enumerationMutation {
    objc_setEnumerationMutationHandler(function);
    NSMutableArray *array = @[@1, @2].mutableCopy;
    for (NSNumber *number in array) {
    [array removeObject:number];
    }
    objc_setEnumerationMutationHandler(nil);
    }

    View Slide

  55. ࢖ͬͯΈͨ
    void function(NSMutableArray *array) {
    NSLog(@“͓ئ͍ࢮͳͳ͍Ͱʂ”);
    }
    - (void)enumerationMutation {
    objc_setEnumerationMutationHandler(function);
    NSMutableArray *array = @[@1, @2].mutableCopy;
    for (NSNumber *number in array) {
    [array removeObject:number];
    }
    objc_setEnumerationMutationHandler(nil);
    }
    ௒ศར

    View Slide

  56. ࢖ͬͯΈͨ
    void function(NSMutableArray *array) {
    NSLog(@“͓ئ͍ࢮͳͳ͍Ͱʂ”);
    }
    - (void)enumerationMutation {
    objc_setEnumerationMutationHandler(function);
    NSMutableArray *array = @[@1, @2].mutableCopy;
    for (NSNumber *number in array) {
    [array removeObject:number];
    }
    objc_setEnumerationMutationHandler(nil);
    }
    ӕͰ͢

    View Slide

  57. ࢖ͬͯΈͨ
    void function(NSMutableArray *array) {
    NSLog(@“͓ئ͍ࢮͳͳ͍Ͱʂ”);
    }
    - (void)enumerationMutation {
    objc_setEnumerationMutationHandler(function);
    NSMutableArray *array = @[@1, @2].mutableCopy;
    for (NSNumber *number in array) {
    [array removeObject:number];
    }
    objc_setEnumerationMutationHandler(nil);
    }
    ࢧ཭໓྾ͳࢥߟɾൃݴ

    View Slide

  58. ࠷ޙʹ
    You typically don't need to use the Objective-C
    runtime library directly when programming in
    Objective-C. This API is useful primarily for
    developing bridge layers between Objective-C and
    other languages, or for low-level debugging.

    View Slide

  59. ࠷ޙʹ
    You typically don't need to use the Objective-C
    runtime library directly when programming in
    Objective-C. This API is useful primarily for
    developing bridge layers between Objective-C and
    other languages, or for low-level debugging.

    ීஈͷ։ൃͰ͋Ε͹3VOUJNF"1*࢖͏ඞཁ͕ͳ͍
    ଞͷݴޠͷϒϦοδϯά΍௿ϨΠϠʔͷσόοάʹ͸ͱͯ΋
    ໾ཱͭΑ

    View Slide

  60. ࠷ޙʹ
    You typically don't need to use the Objective-C
    runtime library directly when programming in
    Objective-C. This API is useful primarily for
    developing bridge layers between Objective-C and
    other languages, or for low-level debugging.

    ීஈͷ։ൃͰ͋Ε͹3VOUJNF"1*࢖͏ඞཁ͕ͳ͍
    ଞͷݴޠͷϒϦοδϯά΍௿ϨΠϠʔͷσόοάʹ͸ͱͯ΋
    ໾ཱͭΑ

    View Slide

  61. ·ͱΊ
    - ϓϩύςΟΛੜ΍ͤΔ
    - ϝιουΛೖΕସ͑ΒΕΔ
    - ͓ئ͍ࢮͳͳ͍Ͱʂ͕දݱͰ͖Δ
    - ελʔ͍ͩ͘͞

    View Slide

  62. ͓͠·͍a ?P?

    View Slide