1. 程式人生 > >猿題庫 iOS 客戶端架構設計

猿題庫 iOS 客戶端架構設計

推薦序

我幾周前寫過一篇文章,叫 《被誤解的 MVC 和被神化的 MVVM》,其中的很多思想是和本文的作者 Lancy 交流獲得的。當時很多人回覆問:能直接上猿題庫的程式碼嗎?這次 Lancy 的這篇文章就直接上程式碼了。

這篇文章詳細介紹了猿題庫客戶端架構的設計和思考,當然,也有大量的程式碼示例。Lancy 引入了一個名為 Data Controller 的層級為 View Controller 瘦身,並且借鑑了 MVVM 的思想來將介面與底層解耦。

這套架構幫助猿題庫徹底解耦了UI和邏輯層的開發工作,並且使 View Controller 的程式碼極為精簡,由於 Data Controller 與介面無關,它甚至使單元測試和 TDD 成為可能。

但是,好的架構都與具體的業務場景相關,希望大家在學習的時候也能充分理解它的試用場景,最終能夠改造自己APP的架構。

希望能給大家幫助。

作者介紹

藍晨鈺(@晨鈺lancy),iOS 開發者,現居北京,就職於猿題庫,關注程式碼質量,團隊效率和產品體驗,部落格: http://gracelancy.com

感謝藍晨鈺授權發表,本文的所有打賞歸藍晨鈺所有。

猿題庫是一個擁有數千萬使用者的創業公司,從20013年題庫專案起步到2015年,團隊保持了極高的生產效率,使我們的產品完成了五個大版本和數十個小版本的高速迭代。

在如此快速的開發過程中,如何保證程式碼的質量,降低後期維護的成本,以及為專案越來越快的版本迭代速度提供支援,成為了我們關注的重要問題。這篇文章將闡明我們在猿題庫 iOS 客戶端的架構設計。

MVC

MVC,Model-View-Controller,我們從這個古老而經典的設計模式入手。採用 MVC 這個架構的最大的優點在於其概念簡單,易於理解,幾乎任何一個程式設計師都會有所瞭解,幾乎每一所計算機院校都教過相關的知識。而在 iOS 客戶端開發中,MVC 作為官方推薦的主流架構,不但 SDK 已經為我們實現好了 UIView、UIViewController 等相關的元件,更是有大量的文件和範例供我們參考學習,可以說是一種非常通用而成熟的架構設計。

但 MVC 也有他的壞處。由於 MVC 的概念過於簡單樸素,已經越來越難以適應如今客戶端的需求,大量的程式碼邏輯在 MVC 中並沒有定義得很清楚究竟應該放在什麼地方,導致他們很容易就會堆積在 Controller 裡,成為了人們所說的 Massive View Controller。

MVVM

MVVM,Model-View-ViewModel,一個從 MVC 模式中進化而來的設計模式,最早於2005年被微軟的 WPF 和 Silverlight 的架構師 John Gossman 提出。在 iOS 開發中實踐 MVVM 的話,通常會把大量原來放在 ViewController 裡的檢視邏輯和資料邏輯移到 ViewModel 裡,從而有效的減輕了 ViewController 的負擔。

另外通過分離出來的 ViewModel 獲得了更好的測試性,我們可以針對 ViewModel 來測試,解決了介面元素難於測試的問題。MVVM 通常還會和一個強大的繫結機制一同工作,一旦 ViewModel 所對應的 Model 發生變化時,ViewModel 的屬性也會發生變化,而相對應的 View 也隨即產生變化。

同樣的,MVVM 也有他的缺點:

一個首要的缺點是,MVVM 的學習成本和開發成本都很高。MVVM 是一個年輕的設計模式,大多數人對他的瞭解都不如 MVC 熟悉,基於繫結機制來進行程式設計需要一定的學習才能較好的上手。同時在 iOS 客戶端開發中,並沒有現成的繫結機制可以使用,要麼使用 KVO,要麼引入類似 ReactiveCocoa 這樣的第三方庫,使得學習成本和開發成本進一步提高。

另一個缺點是,資料繫結使 Debug 變得更難了。資料繫結使程式異常能快速的傳遞到其他位置,在介面上發現的 Bug 有可能是由 ViewModel 造成的,也有可能是由 Model 層造成的,傳遞鏈越長,對 Bug 的定位就越困難。

同時還必須指出的是,在傳統的 MVVM 架構中,ViewModel 依然承載的大量的邏輯,包括業務邏輯,介面邏輯,資料儲存和網路相關,使得 ViewModel 仍然有可能變得和 MVC 中 ViewController 一樣臃腫。

在兩種架構中權衡而產生的架構

兩種架構的優點都想要,缺點又都想避開,我們在兩種架構中權衡了他們的優缺點,設計出了一個新的架構,起了一個名字叫:MVVM without Binding with DataController,架構圖如下:


ViewModel

先來看右邊檢視相關的部分,傳統的 MVC 當中 ViewController 中有大量的資料展示和樣式定製的邏輯,我們引入 MVVM 中 ViewModel 的概念,將這部分檢視邏輯移到了 ViewModel 當中。

在這個設計中,每一個 View 都會有一個對應的 ViewModel,其包含了這個 View 資料展示和樣式定製所需要的所有資料。同時,我們不引入雙向繫結機制或者觀察機制,而是通過傳統的代理回撥或是通知來將 UI 事件傳遞給外界。而 ViewController 只需要生成一個 ViewModel 並把這個裝配給對應的 View,並接受相應的 UI 事件即可。

這樣做有幾個好處:首先是 View 的完全解耦合,對於 View 來說,只需要確定好相應的 ViewModel 和 UI 事件的回撥介面即可與 Model 層完全隔離;而 ViewController 可以避免與 View 的具體表現打交道,這部分職責被轉交給了 ViewModel,有效的減輕了 ViewController 的負擔;同時我們棄用了傳統繫結機制,使用了傳統的易於理解的回撥機制來傳遞 UI 事件,降低了學習成本,同時使得資料的流入和流出變得易於觀察和控制,降低了維護了調適的成本。

DataController

接下來我們關注 Model 和 VC 之間的關係。如之前提到,在傳統的 MVVM 中,ViewModel 接管了 ViewController 的大部分職責,包括資料獲取,處理,加工等等,導致其很有可能變得臃腫。我們將這部分邏輯抽離出來,引入一個新的部件,DataController。

ViewController 可以向 DataController 請求獲取或是操作資料,也可以將一些事件傳遞給 DataController,這些事件可以是 UI 事件觸發的。DataController 在收到這些請求後,再向 Model 層獲取或是更新資料,最後再將得到的資料加工成 ViewController 最終需要的資料返回。

這樣做之後,使得資料相關的邏輯解耦合,資料的獲取、修改、加工都放在 Data Controller 中處理,View Controller 不關心資料如何獲得,如何處理,Data Controller 也不關心介面如何展示,如何互動。同時 Data Controller 因為完全和介面無關,所以可以有更好的測試性和複用性。

DataController 層和 Model 層之間的界限並不是僵硬的,但需要保證每一個 ViewController 都有一個對應的 DataController。Data Controller 更強調的是其作為業務邏輯對外的介面。而在 DataController 中呼叫更底層的 Model 層邏輯是我們推薦的程式設計正規化,例如資料加工層,網路層,持久層等。

在後面的例子中,我們會更詳細的講解 DataController 的實現細節。

Show me the code

我們以猿題庫主頁為例,展示我們是如何使用應用這個架構的。


主頁有幾個部分組成,最上面的小猴子 Banner 頁,用於滾動展示一些活動資訊;中間有一個使用者名稱字的頁面,用於展示使用者資訊和答題情況以及一些心靈雞湯;最底下的這部分是一個課目選擇頁面,展示了使用者開啟的科目入口,在更多選項裡面可以進一步配置這些科目入口。接下來我們會以科目頁面(SubjectView)為例展示一些細節。

ViewController

我們會給每一個 ViewController 都建立一個對應的 DataController。
例如我們給主頁建一個類起名叫APEHomePraticeViewController,同時他會有一個對應的 DataController 起名叫 APEHomePraticeDataController。同時我們把頁面拆分為幾個部分,每個部分有一個相對應的 SubView。程式碼如下:

@interface APEHomePracticeViewController () <APEHomePracticeSubjectsViewDelegate>

@property (nonatomic, strong, nullable) UIScrollView *contentView;
@property (nonatomic, strong, nullable) APEHomePracticeBannerView *bannerView;
@property (nonatomic, strong, nullable) APEHomePracticeActivityView *activityView;
@property (nonatomic, strong, nullable) APEHomePracticeSubjectsView *subjectsView;

@property (nonatomic, strong, nullable) APEHomePracticeDataController *dataController;

@end

viewDidLoad 的時候,初始化好各個 SubView,並設定好佈局:

- (void)setupContentView {
    self.contentView = [[UIScrollView alloc] init];
    [self.view addSubview:self.contentView];
    self.bannerView = [[APEHomePracticeBannerView alloc] init];
    self.activityView = [[APEHomePracticeActivityView alloc] init];
    self.subjectsView = [[APEHomePracticeSubjectsView alloc] init];
    self.subjectsView.delegate = self;
    [self.contentView addSubview:self.bannerView];
    [self.contentView addSubview:self.activityView];
    [self.contentView addSubview:self.subjectsView];
    // Layout Views ...
}

接下來,ViewController 會向 DataController 請求 Subject 相關的資料,並在請求完成後,用獲得的資料生成 ViewModel,將其裝配給 SubjectView,完成介面渲染,程式碼如下:

- (void)fetchSubjectData {
    [self.dataController requestSubjectDataWithCallback:^(NSError *error) {
        if (error == nil) {
            [self renderSubjectView];
        }
    }];
}
- (void)renderSubjectView {
    APEHomePracticeSubjectsViewModel *viewModel =
        [APEHomePracticeSubjectsViewModel viewModelWithSubjects:self.dataController.openSubjects];
    [self.subjectsView bindDataWithViewModel:viewModel];
}

資料結構

為了更好的演示,我們接下來要介紹一下 Subject 相關的資料結構:
APESubject 是科目的資源結構,包含了 Subject 的 id 和 name 等資源屬性,這部分屬性是使用者無關的;APEUserSubject 是使用者的科目資訊,包含了使用者是否開啟某個學科的屬性。

@interface APESubject : NSObject
@property (nonatomic, strong, nullable) NSNumber *id;
@property (nonatomic, strong, nullable) NSString *name;
@end
@interface APEUserSubject : NSObject
@property (nonatomic, strong, nullable) NSNumber *id;
@property (nonatomic, strong, nullable) NSNumber *updatedTime;
///  On or Off
@property (nonatomic) APEUserSubjectStatus status;
@end

DataController

如我們之前所說,每一個 ViewController 都會有一個對應的 DataController,這一類 DataController 的主要職責是處理這個頁面上的所有資料相關的邏輯,我們稱其為 View Related Data Controller。

// APEHomePracticeDataController.h
@interface APEHomePracticeDataController : APEBaseDataController
// 1
@property (nonatomic, strong, nonnull, readonly) NSArray<APESubject *> *openSubjects;
// 2
- (void)requestSubjectDataWithCallback:(nonnull APECompletionCallback)callback;
@end

上面的這個程式碼

  1. 我們定義了一個介面最終需要的資料的 property,這裡是 openSubjects,這個 property 會儲存使用者開啟的科目列表,他的型別是APESubject
  2. 我們還會定義一個介面來請求 openSubject 資料。
    DataController 這一層是一個靈活性很高的部件,一個 DataController 可以複用更小的 DataController,這一類更小的 DataController 通常只會包含純粹的或是更抽象的 Model 相關的邏輯,例如網路請求,資料庫請求,或是資料加工等。我們稱這一類 DataController 為 Model Related Data Controller。
    Model Related Data Controller 通常會為上層提供正交的資料:
// APEHomePracticeDataController.m
@interface APEHomePracticeDataController ()
@property (nonatomic, strong, nonnull) APESubjectDataController *subjectDataController;
@end
@implementation APEHomePracticeDataController
- (void)requestSubjectDataWithCallback:(nonnull APECompletionCallback)callback {
    APEDataCallback dataCallback = ^(NSError *error, id data) {
        callback(error);
    };
    [self.subjectDataController requestAllSubjectsWithCallback:dataCallback];
    [self.subjectDataController requestUserSubjectsWithCallback:dataCallback];
}
- (nonnull NSArray<APESubject *> *)openSubjects {
    return self.subjectDataController.openSubjectsWithCurrentPhase ?: @[];
}
@end

在我們的 APEHomePraticeDataController 的實現中,就包含了一個 APESubjectDataController,這個 subjectDataController 會負責請求 All Subjects 和 User Subjects,並將其加工成上層所最終需要的 Open Subjects。(備註:這個例子裡面的 callback 會回撥多次是猿題庫產品的需求,如有需要,可在這一層控制請求都完成後再呼叫上層回撥)
事實上,Model Related Data Controller 可以一般性的認為就是大家經常在寫的 Model 層程式碼,例如 UserAgent,UserService,PostService 之類的服務。之後讀者若想重構就專案成這個架構,大可以不必糾結於形式,直接在 DataController 裡呼叫舊有程式碼的邏輯即可,如圖下面這樣的行為都是允許的:


ViewModel

每一個 View 都會有一個對應的 ViewModel,這個 ViewModel 會包含展示這個 View 所需要的所有資料。
我們會使用工廠方法來建立 View Model,例如這個例子裡,Subject View Model 不需要關心傳遞給他是什麼樣的 Subject,所有的課目或者只是使用者開啟的科目。

@interface APEHomePracticeSubjectsViewModel : NSObject
@property (nonatomic, strong, nonnull) NSArray<APEHomePracticeSubjectsCollectionCellViewModel *>
*cellViewModels;
@property (nonatomic, strong, nonnull) UIColor *backgroundColor;
+ (nonnull APEHomePracticeSubjectsViewModel *)viewModelWithSubjects:(nonnull NSArray<APESubject *>
 *)subjects;

@end

ViewModel 可以包含更小的 ViewModel,就像 View 可以有 SubView 一樣。SubjectView 的內部是由一個UICollectionView實現的,所以我們也給了對應的 Cell 設計了一個 ViewModel。
需要額外注意的是,ViewModel 一般來說會包含的顯示介面所需要的所有元素,但粒度是可以控制。一般來說,我們只把會因為業務變化而變化的部分設為 ViewModel 的一部分,例如這裡的 titleColor 和 backgroundColor 會因為主題不同而變化,但字型的大小(titleFont)卻是不會變的,所以不需要事無鉅細的都加到 ViewModel 裡。

@interface APEHomePracticeSubjectsCollectionCellViewModel : NSObject
@property (nonatomic, strong, nonnull) UIImage *image;
@property (nonatomic, strong, nonnull) UIImage *highlightedImage;
@property (nonatomic, strong, nonnull) NSString *title;
@property (nonatomic, strong, nonnull) UIColor *titleColor;
@property (nonatomic, strong, nonnull) UIColor *backgroundColor;
+ (nonnull APEHomePracticeSubjectsCollectionCellViewModel *)viewModelWithSubject:(nonnull
APESubject *)subject;
+ (nonnull APEHomePracticeSubjectsCollectionCellViewModel *)viewModelForMore;

@end

View

View 只需要定義好裝配 ViewModel 的介面和定義好 UI 回撥事件即可:

@protocol APEHomePracticeSubjectsViewDelegate <NSObject>
- (void)homePracticeSubjectsView:(nonnull APEHomePracticeSubjectsView *)subjectView
             didPressItemAtIndex:(NSInteger)index;
@end
@interface APEHomePracticeSubjectsView : UIView
@property (nonatomic, strong, nullable, readonly) APEHomePracticeSubjectsViewModel *viewModel;
@property (nonatomic, weak, nullable) id<APEHomePracticeSubjectsViewDelegate> delegate;
- (void)bindDataWithViewModel:(nonnull APEHomePracticeSubjectsViewModel *)viewModel;
@end

渲染介面的時候,完全依靠 ViewModel 進行,包括 View 的 SubView 也會使用 ViewModel 裡面的子 ViewModel 渲染。

- (void)bindDataWithViewModel:(nonnull APEHomePracticeSubjectsViewModel *)viewModel {
    self.viewModel = viewModel;
    self.backgroundColor = viewModel.backgroundColor;
    [self.collectionView reloadData];
    [self setNeedsUpdateConstraints];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:
(NSIndexPath *)indexPath {
    APEHomePracticeSubjectsCollectionViewCell *cell = [collectionView
dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
    if (0 <= indexPath.row && indexPath.row < self.viewModel.cellViewModels.count) {
        APEHomePracticeSubjectsCollectionCellViewModel *vm =
self.viewModel.cellViewModels[indexPath.row];
        [cell bindDataWithViewModel:vm];
}
    return cell;
}

至此,我們就完成了所有的步驟。我們回過頭再看一下 ViewController 的職責就回變的非常簡單,裝配好 View,向 DataController 請求資料,裝配 ViewModel,配置給 View,接收 View 的UI事,一切複雜的操作都能夠的代理出去。

總結

優點

通過上面的例子我們可以看到,這個架構有幾個優點:

層次清晰,職責明確:和介面有關的邏輯完全劃到 ViewModel 和 View 一遍,其中 ViewModel 負責介面相關邏輯,View 負責繪製;Data Controller 負責頁面相關的資料邏輯,而 Model 還是負責純粹的資料層邏輯。 ViewController 僅僅只是充當簡單的膠水作用。

耦合度低,測試性高:除開 ViewController 外,各個部件可以說是完全解耦合的,各個部分也是可以完全獨立測試的。同一個功能,可以分別由不同的開發人員分別進行開發介面和邏輯,只需要確立好介面即可。

複用性高:解耦合帶來的額外好處就是複用性高,例如同一個View,只需要多一個工廠方法生成 ViewModel,就可以直接服用。資料邏輯程式碼不放在 ViewController 層也可以更方便的服用。

學習成本低: 本質上來說,這個架構屬於對 MVC 的優化,主要在於解決 Massive View Controller 問題,把原本屬於 View Controller 的職責根據介面和邏輯部分相應的拆到 ViewModel 和 DataController 當中,所以是一個非常易於理解的架構設計,即使是新手也可以很快上手。

開發成本低: 完全不需要引入任何第三方庫就可以進行開發,也避免了因為 MVVM 維護成本高的問題。

實施性高,重構成本低:可以在 MVC 架構上逐步重構的架構,不需要整體重寫,是一種和 MVC 相容的設計。

缺點

不可否認的是,這個設計也有其相應的缺點,由於其把傳統 MVVM 裡面的 VM 拆成兩部分,會照成下面的一些情況:

  1. 當頁面的互動邏輯非常多時,需要頻繁的在 DC-VC-VM 裡來回傳遞資訊,造成了大量膠水程式碼。
  2. 另外,由於在傳統的 MVVM 中 VM 原本是一體的,一些複雜的互動本來可以在 VM 中直接完成測試,如今卻需要同時使用 DC 和 VM 並附上一些膠水程式碼才能進行測試。
  3. 沒有了 Binding,程式碼寫起來會更費勁一點(仁者見仁,智者見智)。

後記

MVVM 是一個很棒的架構,私底下我也會用其來做一些個人專案,但在公司專案裡,我會更慎重的考慮箇中利弊。我做這個設計的時候,心儀 MVVM 的種種好處,又忌憚於它的種種壞處,再考慮到團隊的開發和維護成本,所以最終設計成了如今這樣。

個人認為,好的架構設計的都是和團隊以及業務場景息息相關的。我們這套架構幫助我們解決了 ViewController 程式碼堆積的問題,也帶來了更清晰明瞭的程式碼層級和模組職責,同時沒有引入過多的複雜性。希望大家也能充分理解這套架構的適用場景,在自己的 APP 架構設計中有所借鑑。

https://github.com/gonefish/GQDataController

相關推薦

iOS 客戶架構設計

推薦序 我幾周前寫過一篇文章,叫 《被誤解的 MVC 和被神化的 MVVM》,其中的很多思想是和本文的作者 Lancy 交流獲得的。當時很多人回覆問:能直接上猿題庫的程式碼嗎?這次 Lancy 的這篇文章就直接上程式碼了。 這篇文章詳細介紹了猿題庫客戶端架構的設計和思考,當然,也有大量的程式碼示例。

iOS客戶的技術細節(三):基於CoreText的排版引擎

來自:http://blog.devtang.com/blog/2013/10/21/the-tech-detail-of-ape-client-3/ 前言 本人今年主要在負責猿題庫iOS客戶端的開發,本文旨在通過分享猿題庫iOS客戶端開發過程中的技術細節

支付寶客戶架構解析:iOS 容器化框架初探

1. 前言 由本章節開始,我們將從支付寶客戶端的架構設計方案入手,細分拆解客戶端在“容器化框架設計”、“網路優化”、“效能啟動優化”、“自動化日誌收集”、“RPC 元件設計”、“移動應用監控、診斷、定位”等具體實現,帶領大家進一步瞭解支付寶在客戶端架構上的迭代與優化歷程。 本節將介紹支付寶 iOS 容器化

支付寶客戶架構解析:iOS 客戶啟動效能優化初探

前言 《支付寶客戶端架構解析》系列將從支付寶客戶端的架構設計方案入手,細分拆解客戶端在“容器化框架設計”、“網路優化”、“效能啟動優化”、“自動化日誌收集”、“RPC 元件設計”、“移動應用監控、診斷、定位”等具體實現,帶領大家進一步瞭解支付寶在客戶端架構上的迭代與優化歷程。 啟動應用是使用者使用任何一款

筆記|滴滴iOS客戶架構,元件化,技術選型

筆記來源infoq:滴滴iOS客戶端的架構演變之路 1,狀態機,把訂單中的階段,例如:計程車的等待搶單、計程車的等待接駕、專車的等待搶單、專車的等待接駕,都當成一種獨立的狀態,每 個狀態機只需要知道可能要導向的狀態機,從而做到了相對獨立,狀態機滿足了計程車、專

MMORGP大型遊戲設計與開發(客戶架構 part16 of vegine)

由於近來比較忙碌和有些睏倦的原因,所以關於這部分的文章沒有及時更新,一句話:讓朋友們久等了!今天所講的是客戶端vengine(微引擎)中最後一個部分,就像上節所說,這一部分的內容比較多。可能有些朋友看了程式碼以及註釋後,仍有不少疑惑的地方,歡迎評論留言相互討論,如

[IOS]網路json資料快取

使用JSON 資料快取的初衷 是提高使用者體驗,用資料快取代替loading動畫。 整個一個流程是  進入檢視控制器 載入快取—向伺服器傳送資料請求——更新資料  首先  pods 安裝猿題庫 或者從外部直接新增到工程 yrk是基於afnworking的一個封裝庫,也就是說

iOS 客戶獲取七牛上傳token

生成 edi signed 解析 ring request self 在線 err 一、官方參考文檔: 1.上傳策略http://developer.qiniu.com/article/developer/security/put-policy.html 2.上傳憑證(即u

Zookeeper之Zookeeper底層客戶架構實現原理(轉載)

一次 描述 綁定 機制 一個 ini fin 源碼 receive Zookeeper的Client直接與用戶打交道,是我們使用Zookeeper的interface。了解ZK Client的結構和工作原理有利於我們合理的使用ZK,並能在使用中更早的發現問題。本文將在研究源

tcp 服務客戶程序設計

cti ida ons uint8_t 文件 數據 開頭 ews 信息 一、實驗目的 學習和掌握Linux下的TCP服務器基本原理和基本編程方法,體會TCP與UDP編程的不同,UDP編程:http://blog.csdn.net/yueguanghaidao/articl

隨機獲得MySQL數據中100條數據方法 駕照項目 MVC架構 biz業務層的實現類 根據考試類型rand或order通過dao數據訪問層接口得到數據中100或全部數據

mysql數據庫 imp swift mvc架構 als new util pack gson package com.swift.jztk.biz; import java.util.Collections; import java.util.Comparator;

js判斷安卓客戶或者是ios客戶

終端 use navigator 判斷 com oca topic fun and 代碼:   function xaizai() {   var u = navigator.userAgent, app = navigator.appVersion;   var isA

iOS客戶節日換膚方案探究

named 普通模式 ani chang theme 1.5 static 解析 .json 轉自:https://www.ianisme.com的博客 一、前言: tip: 本來這篇文章在聖誕節就已經準備好了,但是由於種種原因一直沒有寫完,今天將它寫出來,也算是2018

要開始做博客園iOS客戶

2個 wid 原始的 註冊 網易 博客 可能 技術 內容 去年心血來潮做了一個dribbble客戶端,但是因為太忙又沒有發布,直到今年這時候準備回頭去整理一下然後上架,居然發現dribbble官方早在今年3月就把API權限收緊了,現在仍然開放的API和沒有差不多,真是欲

iOS客戶的微信支付接入

對於一個iOS的APP,如果有一些虛擬的商品或者服務需要通過線上支付來收費的話,一般有幾種主流的選擇。 如果是通過APP呼叫支付平臺APP的思路的話,一個是調起支付寶客戶端,一個則是調起微信支付。 實際上,從程式碼的角度,調起支付APP就是把一些關鍵的引數通過一定方式打包成為一個訂單,

支付寶客戶架構解析:Android 客戶啟動速度優化之「垃圾回收」

前言 《支付寶客戶端架構解析》系列將從支付寶客戶端的架構設計方案入手,細分拆解客戶端在“容器化框架設計”、“網路優化”、“效能啟動優化”、“自動化日誌收集”、“RPC 元件設計”、“移動應用監控、診斷、定位”等具體實現,帶領大家進一步瞭解支付寶在客戶端架構上的迭代與優化歷程。 本節將介紹支付寶 Andro

支付寶客戶架構分析:自動化日誌收集及分析

前言 《支付寶客戶端架構解析》系列將從支付寶客戶端的架構設計方案入手,細分拆解客戶端在“容器化框架設計”、“網路優化”、“效能啟動優化”、“自動化日誌收集”、“RPC 元件設計”、“移動應用監控、診斷、定位”等具體實現,帶領大家進一步瞭解支付寶在客戶端架構上的迭代與優化歷程。 本節將結合禾兮

基於滴滴雲的棋牌遊戲服務架構設計

現在小團隊開發的棋牌遊戲有很多,棋牌行業的相互攻擊是非常普遍的現象,同行之間往往會採取 DDOS、CC 等攻擊的手段來打擊對手,這是目前棋牌運營商們面臨的比較嚴峻的一個問題,那麼在設計棋牌遊戲服務端架構時就需要考慮高可用和抗攻擊這兩個特性,本文詳細介紹瞭如何基於滴滴雲現有的產品組合來設計一套

一個簡單的腳手架drop-cli、vue的元件、移動架構和pc管理後臺模版

鑑於自己的經驗和以往做過的專案,為了提高工作效率,特意整理了一下專案模版、vue元件庫等模版並新增到一個自己封裝的腳手架drop-cli中。不喜勿噴! drop-cli 一個簡單的腳手架,可新增不同的模版/框架 $ npm inst

網狐棋牌遊戲服務架構設計原理

基本設計概念和處理流程 呼叫模型 模仿COM元件介面模式,利用面向物件思想多型性polymorphism,呼叫方儲存著被呼叫方的基礎介面指標(interface or sink鉤子)(Pure Virtual Function),呼叫方直接呼叫介面指標內宣告的純虛方法