<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # Aspect Oriented Programming 面向切面編程 Aspect Oriented Programming (AOP,面向切面編程) 在 Objective-C 社區內沒有那么有名,但是 AOP 在運行時可以有巨大威力。 但是因為沒有事實上的標準,Apple 也沒有開箱即用的提供,也顯得不重要,開發者都不怎么考慮它。 引用 [Aspect Oriented Programming](http://en.wikipedia.org/wiki/Aspect-oriented_programming) 維基頁面: > An aspect can alter the behavior of the base code (the non-aspect part of a program) by applying advice (additional behavior) at various join points (points in a program) specified in a quantification or query called a pointcut (that detects whether a given join point matches). (一個切面可以通過在多個 join points 中 實行 advice 改變基礎代碼的行為(程序的非切面的部分) ) 在 Objective-C 的世界里,這意味著使用運行時的特性來為 _切面_ 增加適合的代碼。通過切面增加的行為可以是: - 在類的特定方法調用前運行特定的代碼 - 在類的特定方法調用后運行特定的代碼 - 增加代碼來替代原來的類的方法的實現 有很多方法可以達成這些目的,但是我們沒有深入挖掘,不過它們主要都是利用了運行時。 [Peter Steinberger](https://twitter.com/steipete) 寫了一個庫,[Aspects](https://github.com/steipete/Aspects) 完美地適配了 AOP 的思路。我們發現它值得信賴以及設計得非常優秀,所以我們就在這邊作為一個簡單的例子。 對于所有的 AOP庫,這個庫用運行時做了一些非常酷的魔法,可以替換或者增加一些方法(比 method swizzling 技術更有技巧性) Aspect 的 API 有趣并且非常強大: ~~~ + (id<AspectToken>)aspect_hookSelector:(SEL)selector withOptions:(AspectOptions)options usingBlock:(id)block error:(NSError **)error; - (id<AspectToken>)aspect_hookSelector:(SEL)selector withOptions:(AspectOptions)options usingBlock:(id)block error:(NSError **)error; ~~~ 比如,下面的代碼會對于執行 `MyClass` 類的 `myMethod:` (實例或者類的方法) 執行塊參數。 ~~~ [MyClass aspect_hookSelector:@selector(myMethod:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) { ... } error:nil]; ~~~ 換一句話說:這個代碼可以讓在 `@selector` 參數對應的方法調用之后,在一個 `MyClass` 的對象上(或者在一個類本身,如果方法是一個類方法的話)執行 block 參數。 我們為 `MyClass` 類的 `myMethod:` 方法增加了切面。 通常 AOP 用來實現橫向切面的完美的適用的地方是統計和日志。 下面的例子里面,我們會用AOP用來進行統計。統計是iOS項目里面一個熱門的特性,有很多選擇比如 Google Analytics, Flurry, MixPanel, 等等. 大部分統計框架都有教程來指導如何追蹤特定的界面和事件,包括在每一個類里寫幾行代碼。 在 Ray Wenderlich 的博客里有 [文章](http://www.raywenderlich.com/53459/google-analytics-ios) 和一些示例代碼,通過在你的 view controller 里面加入 [Google Analytics](https://developers.google.com/analytics/devguides/collection/ios/) 進行統計。 ~~~ - (void)logButtonPress:(UIButton *)button { id<GAITracker> tracker = [[GAI sharedInstance] defaultTracker]; [tracker send:[[GAIDictionaryBuilder createEventWithCategory:@"UX" action:@"touch" label:[button.titleLabel text] value:nil] build]]; } ~~~ 上面的代碼在按鈕點擊的時候發送了特定的上下文事件。但是當你想追蹤屏幕的時候會更糟糕。 ~~~ - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; id<GAITracker> tracker = [[GAI sharedInstance] defaultTracker]; [tracker set:kGAIScreenName value:@"Stopwatch"]; [tracker send:[[GAIDictionaryBuilder createAppView] build]]; } ~~~ 對于大部分有經驗的iOS工程師,這看起來不是很好的代碼。我們讓 view controller 變得更糟糕了。因為我們加入了統計事件的代碼,但是它不是 view controller 的職能。你可以反駁,因為你通常有特定的對象來負責統計追蹤,并且你將代碼注入了 view controller ,但是無論你隱藏邏輯,問題仍然存在 :你最后還是在`viewDidAppear:` 后插入了代碼。 你可以用 AOP 來追蹤屏幕視圖來修改 `viewDidAppear:` 方法。同時,我們可以用同樣的方法,來在其他感興趣的方法里面加入事件追蹤,比如任何用戶點擊按鈕的時候(比如頻繁地調用IBAction) 這個方法是干凈并且非侵入性的: - 這個 view controller 不會被不屬于它的代碼污染 - 為所有加入到我們代碼的切面定義一個 SPOC 文件 (single point of customization)提供了可能 - SPOC 應該在 App 剛開始啟動的時候就加入切面 - 公司負責統計的團隊通常會提供統計文檔,羅列出需要追蹤的事件。這個文檔可以很容易映射到一個 SPOC 文件。 - 追蹤邏輯抽象化之后,擴展到很多其他統計框架會很方便 - 對于屏幕視圖,對于需要定義 selector 的方法,只需要在 SPOC 文件修改相關的類(相關的切面會加入到 `viewDidAppear:` 方法)。如果要同時發送屏幕視圖和時間,一個追蹤的 label 和其他元信息來提供額外數據(取決于統計提供方) 我們可能希望一個 SPOC 文件類似下面的(同樣的一個 .plist 文件會適配) ~~~ NSDictionary *analyticsConfiguration() { return @{ @"trackedScreens" : @[ @{ @"class" : @"ZOCMainViewController", @"label" : @"Main screen" } ], @"trackedEvents" : @[ @{ @"class" : @"ZOCMainViewController", @"selector" : @"loginViewFetchedUserInfo:user:", @"label" : @"Login with Facebook" }, @{ @"class" : @"ZOCMainViewController", @"selector" : @"loginViewShowingLoggedOutUser:", @"label" : @"Logout with Facebook" }, @{ @"class" : @"ZOCMainViewController", @"selector" : @"loginView:handleError:", @"label" : @"Login error with Facebook" }, @{ @"class" : @"ZOCMainViewController", @"selector" : @"shareButtonPressed:", @"label" : @"Share button" } ] }; } ~~~ 這個提及的架構在 Github 的[EF Education First](https://github.com/ef-ctx/JohnnyEnglish/blob/master/CTXUserActivityTrackingManager.m) 中托管 ~~~ - (void)setupWithConfiguration:(NSDictionary *)configuration { // screen views tracking for (NSDictionary *trackedScreen in configuration[@"trackedScreens"]) { Class clazz = NSClassFromString(trackedScreen[@"class"]); [clazz aspect_hookSelector:@selector(viewDidAppear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSString *viewName = trackedScreen[@"label"]; [tracker trackScreenHitWithName:viewName]; }); }]; } // events tracking for (NSDictionary *trackedEvents in configuration[@"trackedEvents"]) { Class clazz = NSClassFromString(trackedEvents[@"class"]); SEL selektor = NSSelectorFromString(trackedEvents[@"selector"]); [clazz aspect_hookSelector:selektor withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ UserActivityButtonPressedEvent *buttonPressEvent = [UserActivityButtonPressedEvent eventWithLabel:trackedEvents[@"label"]]; [tracker trackEvent:buttonPressEvent]; }); }]; } } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看