精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

ReactiveCocoa自述:工作原理和應(yīng)用

移動(dòng)開(kāi)發(fā) iOS
如果你已經(jīng)很熟悉函數(shù)式響應(yīng)式編程編程或者了解ReactiveCocoa的一些基本前提,check outDocumentation文件夾作為框架的概述,這里面有一些關(guān)于它怎么工作的深層次的信息.

ReactiveCocoa (RAC)是一個(gè)Objective-C的框架,它的靈感來(lái)自函數(shù)式響應(yīng)式編程.

如果你已經(jīng)很熟悉函數(shù)式響應(yīng)式編程編程或者了解ReactiveCocoa的一些基本前提,check outDocumentation文件夾作為框架的概述,這里面有一些關(guān)于它怎么工作的深層次的信息.

什么是ReactiveCocoa?

ReactiveCocoa文檔寫(xiě)得很厲害,并且詳細(xì)地介紹了RAC是什么以及它是怎么工作的?

如果你多學(xué)一點(diǎn),我們推薦下面這些資源:

Introduction

When to use ReactiveCocoa

Framework Overview

Basic Operators

Header documentation

Previously answered Stack Overflow questions and GitHub issues

The rest of the Documentation folder

Functional Reactive Programming on iOS(eBook)

如果你有任何其他的問(wèn)題,請(qǐng)隨意提交issue,

file an issue.

介紹

ReactiveCocoa的靈感來(lái)自函數(shù)式響應(yīng)式編程.Rather than using mutable variables which are replaced and modified in-place,RAC提供signals(表現(xiàn)為RACSignal)來(lái)捕捉當(dāng)前以及將來(lái)的值.

通過(guò)對(duì)signals進(jìn)行連接,綁定和響應(yīng),不需要連續(xù)地觀察和更新值,軟件就能寫(xiě)了.

舉個(gè)例子,一個(gè)text field能夠綁定到最新?tīng)顟B(tài),即使它在變,而不需要用額外的代碼去更新text field每一秒的狀態(tài).它有點(diǎn)像KVO,但它用blocks代替了重寫(xiě)-observeValueForKeyPath:ofObject:change:context:.

Signals也能夠呈現(xiàn)異步的操作,有點(diǎn)像futures and promises.這極大地簡(jiǎn)化了異步軟件,包括了網(wǎng)絡(luò)處理的代碼.

RAC有一個(gè)主要的優(yōu)點(diǎn),就是提供了一個(gè)單一的,統(tǒng)一的方法去處理異步的行為,包括delegate方法,blocks回調(diào),target-action機(jī)制,notifications和KVO.

這里有一個(gè)簡(jiǎn)單的例子:

  1. // When self.username changes, logs the new name to the console. 
  2. // 
  3. // RACObserve(self, username) creates a new RACSignal that sends the current 
  4. // value of self.username, then the new value whenever it changes. 
  5. // -subscribeNext: will execute the block whenever the signal sends a value. 
  6. [RACObserve(self, username) subscribeNext:^(NSString *newName) { 
  7. NSLog(@"%@", newName); 
  8. }]; 

這不像KVO notifications,signals能夠連接在一起并且能夠同時(shí)進(jìn)行操作:

  1. // Only logs names that starts with "j". 
  2. // 
  3. // -filter returns a new RACSignal that only sends a new value when its block 
  4. // returns YES. 
  5. [[RACObserve(self, username) 
  6. filter:^(NSString *newName) { 
  7. return [newName hasPrefix:@"j"]; 
  8. }] 
  9. subscribeNext:^(NSString *newName) { 
  10. NSLog(@"%@", newName); 
  11. }]; 

Signals也能夠用來(lái)導(dǎo)出狀態(tài).而不是observing properties或者設(shè)置其他的 properties去反應(yīng)新的值,RAC通過(guò)signals and operations讓表示屬性變得有可能:

  1. // Creates a one-way binding so that self.createEnabled will be 
  2. // true whenever self.password and self.passwordConfirmation 
  3. // are equal. 
  4. // 
  5. // RAC() is a macro that makes the binding look nicer. 
  6. // 
  7. // +combineLatest:reduce: takes an array of signals, executes the block with the 
  8. // latest value from each signal whenever any of them changes, and returns a new 
  9. // RACSignal that sends the return value of that block as values. 
  10. RAC(self, createEnabled) = [RACSignal 
  11. combineLatest:@[ RACObserve(self, password), RACObserve(self, passwordConfirmation) ] 
  12. reduce:^(NSString *password, NSString *passwordConfirm) { 
  13. return @([passwordConfirm isEqualToString:password]); 
  14. }]; 

Signals不僅僅能夠用在KVO,還可以用在很多的地方.比如說(shuō),它們也能夠展示button presses:

  1. // Logs a message whenever the button is pressed. 
  2. // 
  3. // RACCommand creates signals to represent UI actions. Each signal can 
  4. // represent a button press, for example, and have additional work associated 
  5. // with it. 
  6. // 
  7. // -rac_command is an addition to NSButton. The button will send itself on that 
  8. // command whenever it's pressed. 
  9. self.button.rac_command = [[RACCommand alloc] initWithSignalBlock:^(id _) { 
  10. NSLog(@"button was pressed!"); 
  11. return [RACSignal empty]; 
  12. }]; 

或者異步的網(wǎng)絡(luò)操作:

  1. // Hooks up a "Log in" button to log in over the network. 
  2. // 
  3. // This block will be run whenever the login command is executed, starting 
  4. // the login process. 
  5. self.loginCommand = [[RACCommand alloc] initWithSignalBlock:^(id sender) { 
  6. // The hypothetical -logIn method returns a signal that sends a value when 
  7. // the network request finishes. 
  8. return [client logIn]; 
  9. }]; 
  10. // -executionSignals returns a signal that includes the signals returned from 
  11. // the above block, one for each time the command is executed. 
  12. [self.loginCommand.executionSignals subscribeNext:^(RACSignal *loginSignal) { 
  13. // Log a message whenever we log in successfully. 
  14. [loginSignal subscribeCompleted:^{ 
  15. NSLog(@"Logged in successfully!"); 
  16. }]; 
  17. }]; 
  18. // Executes the login command when the button is pressed. 
  19. self.loginButton.rac_command = self.loginCommand; 

Signals能夠展示timers,其他的UI事件,或者其他跟時(shí)間改變有關(guān)的東西.

對(duì)于用signals來(lái)進(jìn)行異步操作,通過(guò)連接和改變這些signals能夠進(jìn)行更加復(fù)雜的行為.在一組操作完成時(shí),工作能夠很簡(jiǎn)單觸發(fā):

  1. // Performs 2 network operations and logs a message to the console when they are 
  2. // both completed. 
  3. // 
  4. // +merge: takes an array of signals and returns a new RACSignal that passes 
  5. // through the values of all of the signals and completes when all of the 
  6. // signals complete. 
  7. // 
  8. // -subscribeCompleted: will execute the block when the signal completes. 
  9. [[RACSignal 
  10. merge:@[ [client fetchUserRepos], [client fetchOrgRepos] ]] 
  11. subscribeCompleted:^{ 
  12. NSLog(@"They're both done!"); 
  13. }]; 

Signals能夠順序地執(zhí)行異步操作,而不是嵌套block回調(diào).這個(gè)和futures and promises很相似:

  1. // Logs in the user, then loads any cached messages, then fetches the remaining 
  2. // messages from the server. After that's all done, logs a message to the 
  3. // console. 
  4. // 
  5. // The hypothetical -logInUser methods returns a signal that completes after 
  6. // logging in. 
  7. // 
  8. // -flattenMap: will execute its block whenever the signal sends a value, and 
  9. // returns a new RACSignal that merges all of the signals returned from the block 
  10. // into a single signal. 
  11. [[[[client 
  12. logInUser] 
  13. flattenMap:^(User *user) { 
  14. // Return a signal that loads cached messages for the user. 
  15. return [client loadCachedMessagesForUser:user]; 
  16. }] 
  17. flattenMap:^(NSArray *messages) { 
  18. // Return a signal that fetches any remaining messages. 
  19. return [client fetchMessagesAfterMessage:messages.lastObject]; 
  20. }] 
  21. subscribeNext:^(NSArray *newMessages) { 
  22. NSLog(@"New messages: %@", newMessages); 
  23. } completed:^{ 
  24. NSLog(@"Fetched all messages."); 
  25. }]; 

RAC也能夠簡(jiǎn)單地綁定異步操作的結(jié)果:

  1. // Creates a one-way binding so that self.imageView.image will be set as the user's 
  2. // avatar as soon as it's downloaded. 
  3. // 
  4. // The hypothetical -fetchUserWithUsername: method returns a signal which sends 
  5. // the user. 
  6. // 
  7. // -deliverOn: creates new signals that will do their work on other queues. In 
  8. // this example, it's used to move work to a background queue and then back to the main thread. 
  9. // 
  10. // -map: calls its block with each user that's fetched and returns a new 
  11. // RACSignal that sends values returned from the block. 
  12. RAC(self.imageView, image) = [[[[client 
  13. fetchUserWithUsername:@"joshaber"
  14. deliverOn:[RACScheduler scheduler]] 
  15. map:^(User *user) { 
  16. // Download the avatar (this is done on a background queue). 
  17. return [[NSImage alloc] initWithContentsOfURL:user.avatarURL]; 
  18. }] 
  19. // Now the assignment will be done on the main thread. 
  20. deliverOn:RACScheduler.mainThreadScheduler]; 

這里僅僅說(shuō)了RAC能做什么,但很難說(shuō)清RAC為什么如此強(qiáng)大.雖然通過(guò)這個(gè)README很難說(shuō)清RAC,但我盡可能用更少的代碼,更少的模版,把更好的代碼去表達(dá)清楚.

如果想要更多的示例代碼,可以check outC-41 或者 GroceryList,這些都是真正用ReactiveCocoa寫(xiě)的iOS apps.更多的RAC信息可以看一下Documentation文件夾.

什么時(shí)候用ReactiveCocoa

乍看上去,ReactiveCocoa是很抽象的,它可能很難理解如何將它應(yīng)用到具體的問(wèn)題.

這里有一些RAC常用的地方.

處理異步或者事件驅(qū)動(dòng)數(shù)據(jù)源

很多Cocoa編程集中在響應(yīng)user events或者改變application state.這樣寫(xiě)代碼很快地會(huì)變得很復(fù)雜,就像一個(gè)意大利面,需要處理大量的回調(diào)和狀態(tài)變量的問(wèn)題.

這個(gè)模式表面上看起來(lái)不同,像UI回調(diào),網(wǎng)絡(luò)響應(yīng),和KVO notifications,實(shí)際上有很多的共同之處。RACSignal統(tǒng)一了這些API,這樣他們能夠組裝在一起然后用相同的方式操作.

舉例看一下下面的代碼:

  1. static void *ObservationContext = &ObservationContext; 
  2. - (void)viewDidLoad { 
  3. [super viewDidLoad]; 
  4. [LoginManager.sharedManager addObserver:self forKeyPath:@"loggingIn" options:NSKeyValueObservingOptionInitial context:&ObservationContext]; 
  5. [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(loggedOut:) name:UserDidLogOutNotification object:LoginManager.sharedManager]; 
  6. [self.usernameTextField addTarget:self action:@selector(updateLogInButton) forControlEvents:UIControlEventEditingChanged]; 
  7. [self.passwordTextField addTarget:self action:@selector(updateLogInButton) forControlEvents:UIControlEventEditingChanged]; 
  8. [self.logInButton addTarget:self action:@selector(logInPressed:) forControlEvents:UIControlEventTouchUpInside]; 
  9. - (void)dealloc { 
  10. [LoginManager.sharedManager removeObserver:self forKeyPath:@"loggingIn" context:ObservationContext]; 
  11. [NSNotificationCenter.defaultCenter removeObserver:self]; 
  12. - (void)updateLogInButton { 
  13. BOOL textFieldsNonEmpty = self.usernameTextField.text.length > 0 && self.passwordTextField.text.length > 0
  14. BOOL readyToLogIn = !LoginManager.sharedManager.isLoggingIn && !self.loggedIn; 
  15. self.logInButton.enabled = textFieldsNonEmpty && readyToLogIn; 
  16. - (IBAction)logInPressed:(UIButton *)sender { 
  17. [[LoginManager sharedManager] 
  18. logInWithUsername:self.usernameTextField.text 
  19. password:self.passwordTextField.text 
  20. success:^{ 
  21. self.loggedIn = YES; 
  22. } failure:^(NSError *error) { 
  23. [self presentError:error]; 
  24. }]; 
  25. - (void)loggedOut:(NSNotification *)notification { 
  26. self.loggedIn = NO; 
  27. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 
  28. if (context == ObservationContext) { 
  29. [self updateLogInButton]; 
  30. else { 
  31. [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 

… 用RAC表達(dá)的話就像下面這樣:

  1. - (void)viewDidLoad { 
  2. [super viewDidLoad]; 
  3. @weakify(self); 
  4. RAC(self.logInButton, enabled) = [RACSignal 
  5. combineLatest:@[ 
  6. self.usernameTextField.rac_textSignal, 
  7. self.passwordTextField.rac_textSignal, 
  8. RACObserve(LoginManager.sharedManager, loggingIn), 
  9. RACObserve(self, loggedIn) 
  10. ] reduce:^(NSString *username, NSString *password, NSNumber *loggingIn, NSNumber *loggedIn) { 
  11. return @(username.length > 0 && password.length > 0 && !loggingIn.boolValue && !loggedIn.boolValue); 
  12. }]; 
  13. [[self.logInButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(UIButton *sender) { 
  14. @strongify(self); 
  15. RACSignal *loginSignal = [LoginManager.sharedManager 
  16. logInWithUsername:self.usernameTextField.text 
  17. password:self.passwordTextField.text]; 
  18. [loginSignal subscribeError:^(NSError *error) { 
  19. @strongify(self); 
  20. [self presentError:error]; 
  21. } completed:^{ 
  22. @strongify(self); 
  23. self.loggedIn = YES; 
  24. }]; 
  25. }]; 
  26. RAC(self, loggedIn) = [[NSNotificationCenter.defaultCenter 
  27. rac_addObserverForName:UserDidLogOutNotification object:nil] 
  28. mapReplace:@NO]; 

連接依賴的操作

依賴經(jīng)常用在網(wǎng)絡(luò)請(qǐng)求,當(dāng)下一個(gè)對(duì)服務(wù)器網(wǎng)絡(luò)請(qǐng)求需要構(gòu)建在前一個(gè)完成時(shí),可以看一下下面的代碼:

  1. [client logInWithSuccess:^{ 
  2. [client loadCachedMessagesWithSuccess:^(NSArray *messages) { 
  3. [client fetchMessagesAfterMessage:messages.lastObject success:^(NSArray *nextMessages) { 
  4. NSLog(@"Fetched all messages."); 
  5. } failure:^(NSError *error) { 
  6. [self presentError:error]; 
  7. }]; 
  8. } failure:^(NSError *error) { 
  9. [self presentError:error]; 
  10. }]; 
  11. } failure:^(NSError *error) { 
  12. [self presentError:error]; 
  13. }]; 

ReactiveCocoa 則讓這種模式特別簡(jiǎn)單:

  1. __block NSArray *databaseObjects; 
  2. __block NSArray *fileContents; 
  3. NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init]; 
  4. NSBlockOperation *databaseOperation = [NSBlockOperation blockOperationWithBlock:^{ 
  5. databaseObjects = [databaseClient fetchObjectsMatchingPredicate:predicate]; 
  6. }]; 
  7. NSBlockOperation *filesOperation = [NSBlockOperation blockOperationWithBlock:^{ 
  8. NSMutableArray *filesInProgress = [NSMutableArray array]; 
  9. for (NSString *path in files) { 
  10. [filesInProgress addObject:[NSData dataWithContentsOfFile:path]]; 
  11. fileContents = [filesInProgress copy]; 
  12. }]; 
  13. NSBlockOperation *finishOperation = [NSBlockOperation blockOperationWithBlock:^{ 
  14. [self finishProcessingDatabaseObjects:databaseObjects fileContents:fileContents]; 
  15. NSLog(@"Done processing"); 
  16. }]; 
  17. [finishOperation addDependency:databaseOperation]; 
  18. [finishOperation addDependency:filesOperation]; 
  19. [backgroundQueue addOperation:databaseOperation]; 
  20. [backgroundQueue addOperation:filesOperation]; 
  21. [backgroundQueue addOperation:finishOperation]; 

上面的代碼能夠簡(jiǎn)單地用合成signals來(lái)清理和優(yōu)化:

  1. RACSignal *databaseSignal = [[databaseClient 
  2. fetchObjectsMatchingPredicate:predicate] 
  3. subscribeOn:[RACScheduler scheduler]]; 
  4. RACSignal *fileSignal = [RACSignal startEagerlyWithScheduler:[RACScheduler scheduler] block:^(id subscriber) { 
  5. NSMutableArray *filesInProgress = [NSMutableArray array]; 
  6. for (NSString *path in files) { 
  7. [filesInProgress addObject:[NSData dataWithContentsOfFile:path]]; 
  8. [subscriber sendNext:[filesInProgress copy]]; 
  9. [subscriber sendCompleted]; 
  10. }]; 
  11. [[RACSignal 
  12. combineLatest:@[ databaseSignal, fileSignal ] 
  13. reduce:^ id (NSArray *databaseObjects, NSArray *fileContents) { 
  14. [self finishProcessingDatabaseObjects:databaseObjects fileContents:fileContents]; 
  15. return nil; 
  16. }] 
  17. subscribeCompleted:^{ 
  18. NSLog(@"Done processing"); 
  19. }]; 

簡(jiǎn)化集合轉(zhuǎn)換

像map, filter, fold/reduce 這些高級(jí)功能在Foundation中是極度缺少的m導(dǎo)致了一些像下面這樣循環(huán)集中的代碼:

  1. NSMutableArray *results = [NSMutableArray array]; 
  2. for (NSString *str in strings) { 
  3. if (str.length < 2) { 
  4. continue
  5. NSString *newString = [str stringByAppendingString:@"foobar"]; 
  6. [results addObject:newString]; 

RACSequence能夠允許Cocoa集合用統(tǒng)一的方式操作:

  1. RACSequence *results = [[strings.rac_sequence 
  2. filter:^ BOOL (NSString *str) { 
  3. return str.length >= 2
  4. }] 
  5. map:^(NSString *str) { 
  6. return [str stringByAppendingString:@"foobar"]; 
  7. }]; 

系統(tǒng)要求

ReactiveCocoa 要求 OS X 10.8+ 以及 iOS 8.0+.

引入 ReactiveCocoa

增加 RAC 到你的應(yīng)用中:

1. 增加 ReactiveCocoa 倉(cāng)庫(kù) 作為你應(yīng)用倉(cāng)庫(kù)的一個(gè)子模塊.

2. 從ReactiveCocoa文件夾中運(yùn)行 script/bootstrap .

3. 拖拽 ReactiveCocoa.xcodeproj 到你應(yīng)用的 Xcode project 或者 workspace中.

4. 在你應(yīng)用target的"Build Phases"的選項(xiàng)卡,增加 RAC到 "Link Binary With Libraries"

On iOS, 增加 libReactiveCocoa-iOS.a.

On OS X, 增加 ReactiveCocoa.framework.

RAC 必須選擇"Copy Frameworks" . 假如你沒(méi)有的話, 需要選擇"Copy Files"和"Frameworks" .

5. 增加 "$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/include"

$(inherited)到 "Header Search Paths" (這需要archive builds, 但也沒(méi)什么影響).

6. For iOS targets, 增加 -ObjC 到 "Other Linker Flags" .

7. 假如你增加 RAC到一個(gè)project (不是一個(gè)workspace), 你需要適當(dāng)?shù)奶砑覴AC target到你應(yīng)用的"Target Dependencies".

假如你喜歡用CocoaPods,這里有一些慷慨地第三方貢獻(xiàn)ReactiveCocoa podspecs .

想看一個(gè)用了RAC的工程,check outC-41 或者 GroceryList,這些是真實(shí)的用ReactiveCocoa寫(xiě)的iOS apps.

獨(dú)立開(kāi)發(fā)

假如你的工作用RAC是隔離的而不是將其集成到另一個(gè)項(xiàng)目,你會(huì)想打開(kāi)ReactiveCocoa.xcworkspace 而不是.xcodeproj.

更多信息

ReactiveCocoa靈感來(lái)自.NET的ReactiveExtensions (Rx).Rx的一些原則也能夠很好的用在RAC.這里有些好的Rx資源:

Reactive Extensions MSDN entry

Reactive Extensions for .NET Introduction

Rx - Channel 9 videos

Reactive Extensions wiki

101 Rx Samples

Programming Reactive Extensions and LINQ

RAC和Rx靈感都是來(lái)自函數(shù)式響應(yīng)式編程.這里有些關(guān)于FRP(functional reactive programming)相關(guān)的資源:

What is FRP? - Elm Language

What is Functional Reactive Programming - Stack Overflow

Specification for a Functional Reactive Language - Stack Overflow

Escape from Callback Hell

Principles of Reactive Programming on Coursera

責(zé)任編輯:chenqingxiang
相關(guān)推薦

2025-06-06 08:04:17

2016-03-30 09:34:27

2014-04-02 17:10:00

虛擬應(yīng)用工作原理

2017-09-11 18:24:39

企業(yè)應(yīng)用自述

2010-09-26 08:50:11

JVM工作原理

2009-07-09 14:01:22

JVM工作原理

2023-09-27 12:22:50

Kafka架構(gòu)

2010-09-16 14:42:44

JVM

2011-07-01 11:16:14

Struts

2010-09-08 20:20:39

2010-09-17 15:32:52

JVM工作原理

2025-08-04 02:55:00

AIAgent架構(gòu)

2016-12-13 22:51:08

androidmultidex

2023-06-08 15:27:17

CAN網(wǎng)絡(luò)

2021-03-18 09:07:20

Nginx原理實(shí)踐

2017-05-17 08:51:39

WebView分析應(yīng)用

2009-06-18 13:31:03

Spring工作原理

2009-08-14 13:19:23

2012-03-14 14:40:54

Mac用戶PC用戶

2021-09-28 08:59:40

UPS蓄電池電源
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

粉嫩av四季av绯色av第一区| 日韩av在线看| 97久久国产亚洲精品超碰热| а√中文在线资源库| 99成人免费视频| 国产性色av一区二区| 精品国产午夜福利在线观看| a级片免费在线观看| www.欧美.com| 国产男人精品视频| 亚洲国产精品成人无久久精品| 三级精品视频| 欧美一级艳片视频免费观看| 国产视频一视频二| 国产激情视频在线| 91免费版在线| av色综合网| 小泽玛利亚一区二区三区视频| 最新欧美人z0oozo0| 亚洲欧美中文日韩在线| 日本黄色一级网站| 国产69精品久久久久9999人| 亚洲高清免费观看| 中文字幕一区二区三区最新| 免费a在线观看| 国产98色在线|日韩| 国产精品第8页| 国产精品成人久久| 一区二区三区四区日韩| 亚洲一区二区国产| 噜噜噜在线视频| 亚洲国产aⅴ精品一区二区| 欧美中文一区二区三区| 成人综合视频在线| 久久99亚洲网美利坚合众国| 日本一区二区视频在线观看| 国产综合 伊人色| av网站免费播放| 久久精品国产第一区二区三区| 68精品国产免费久久久久久婷婷| 免费在线观看av网址| 成人在线电影在线观看视频| 亚洲欧美日韩在线一区| 无码成人精品区在线观看| 欧美.com| 欧美一区二区三区系列电影| 中文字幕久久av| 日本一区二区电影| 在线亚洲高清视频| 欧美成人黑人猛交| 欧美男女交配| 色老汉av一区二区三区| 亚洲性生活网站| 亚洲成人看片| 欧美影视一区二区三区| 狠狠热免费视频| www成人在线视频| 日本精品一级二级| 中文字幕在线导航| 成人精品动漫| 在线电影国产精品| 久久久久久久久久一区二区| 亚洲欧美专区| 欧美一区二区三区不卡| 91视频福利网| 伊人久久大香线蕉av超碰| 日韩你懂的电影在线观看| 免费观看一区二区三区| 57pao国产一区二区| 精品免费日韩av| 香港三日本8a三级少妇三级99| 国产精品一区二区三区美女| 日韩成人黄色av| 免费看黄色的视频| 久久久影院免费| 美女少妇精品视频| 精品一区二区三区人妻| 国产精品日本欧美一区二区三区| 日本sm极度另类视频| 亚洲综合成人av| 国产资源在线一区| 国产精品日本一区二区| 日本天堂在线| 国产精品国产三级国产有无不卡| 女同性恋一区二区| 高清在线视频不卡| 欧美在线|欧美| 国产在线视频三区| 天天久久夜夜| 精品国产拍在线观看| 久久婷婷国产麻豆91| 免费在线亚洲| 亚洲一区二区三区视频| 天堂在线视频免费| 国产精品免费视频一区| 毛片在线视频观看| 欧美天堂视频| 欧美一区二视频| 在线免费观看黄色小视频| 日本一二区不卡| 久久久欧美精品| 中文字幕在线观看你懂的| 国产成人a级片| 日本成人看片网址| 丁香花视频在线观看| 欧美亚洲国产一区二区三区| 精品久久久久久无码人妻| 九九在线精品| 欧美日本在线视频中文字字幕| 日批视频免费在线观看| 国产jizzjizz一区二区| 亚洲狠狠婷婷综合久久久| 日韩伦理av| 欧美日韩一区三区四区| 黄色录像a级片| 亚洲激情中文| 国产精品va在线播放我和闺蜜| 午夜精品久久久久久久91蜜桃| 久久久精品黄色| 久久久久久久久影视| 最新日韩一区| 亚洲精选在线观看| 日本一级黄色录像| 国产精品系列在线观看| 亚洲一区二区三区精品在线观看| 2021天堂中文幕一二区在线观| 91麻豆精品国产无毒不卡在线观看| av在线网站观看| 亚洲精选国产| 国产超碰91| 国产婷婷视频在线| 欧美日韩亚洲综合| 欧美色图亚洲激情| 日韩亚洲在线| 国产亚洲二区| heyzo一区| 欧美va亚洲va香蕉在线| 91麻豆免费视频网站| 久久99精品久久久久| 无码免费一区二区三区免费播放 | 久9久9色综合| 97视频在线观看视频免费视频 | 91国拍精品国产粉嫩亚洲一区| 亚洲精品美女在线| 国产情侣在线视频| 99久久国产综合精品色伊| 国产xxxx振车| 91亚洲精品视频在线观看| 久久这里有精品视频| 国产精品探花视频| 亚洲三级免费观看| 国产精品嫩草影视| 九九视频精品全部免费播放| 午夜精品久久久久久久99黑人| 免费国产精品视频| 欧美日韩国产色| 中文字幕高清视频| 日日摸夜夜添夜夜添国产精品 | 91看片在线观看| 欧美日韩五月天| 永久免费看片直接| 国产不卡视频在线播放| 水蜜桃色314在线观看| 噜噜噜天天躁狠狠躁夜夜精品 | 福利一区和二区| www.日韩免费| 国产成人a人亚洲精品无码| 中文字幕一区三区| 国产成人精品一区二区在线小狼| 国内一区二区三区| 精品久久久久久乱码天堂| 美女福利一区二区三区| 中文字幕av一区中文字幕天堂| 一卡二卡三卡在线| 亚洲在线视频网站| 51调教丨国产调教视频| 日韩中文字幕麻豆| 视频一区二区视频| 豆花视频一区二区| 国产91在线高潮白浆在线观看| 在线观看麻豆| 精品久久国产老人久久综合| 亚洲天堂视频网站| 亚洲欧美一区二区三区孕妇| 丰满熟女人妻一区二区三区| 三级影片在线观看欧美日韩一区二区| 日本一区二区三区视频免费看| 亚洲人成777| 97久久久免费福利网址| av网站在线播放| 精品国产乱码久久久久久图片| 成年人视频在线免费看| 成人欧美一区二区三区黑人麻豆| 99riav国产精品视频| 久久久久久穴| 成人国产一区二区三区| 九九视频精品全部免费播放| 91pron在线| 成人日韩在线观看| 久久久久久久久久久91| av福利精品| 精品sm在线观看| 夜夜躁狠狠躁日日躁av| 亚洲 欧美综合在线网络| 国产一二三av| 久久综合成人精品亚洲另类欧美 | www久久久久| 亚洲国产日韩在线一区| 日韩精品电影在线| 欧美人成在线观看| 手机在线一区二区三区| 欧美午夜视频在线| 国产欧美啪啪| 亚洲a成v人在线观看| 成人国产精品一区二区免费麻豆| 午夜精品一区二区三区在线视频| 国产黄a三级三级三级av在线看| 亚洲欧美第一页| 国精产品一品二品国精品69xx| 欧美日韩mp4| 波多野结衣毛片| 黑人精品xxx一区| 久久久精品视频免费| 国产精品久久久久久久第一福利| 熟妇高潮精品一区二区三区| 国产91在线看| 人妻精油按摩bd高清中文字幕| 人人狠狠综合久久亚洲| 日韩少妇内射免费播放18禁裸乳| 精品动漫一区| av网站手机在线观看| 牛牛国产精品| eeuss中文| 91欧美国产| 亚洲一区影院| 日韩电影免费在线观看| 日韩资源av在线| 国内精品久久久久久久影视简单| 久久婷婷国产综合尤物精品| 久久精品色播| 国产精品制服诱惑| xxxxxhd亚洲人hd| 国产伦精品一区二区三区| 亚洲国产视频二区| caoporn国产精品免费公开| 国产精品视频首页| 91精品在线影院| 精品一区二区三区中文字幕 | 亚洲av无码乱码国产精品| 日韩一区二区三区视频在线| 国产探花精品一区二区| 日韩一区二区三区在线观看 | 成人sese在线| 免费日本黄色网址| 91麻豆国产精品久久| 懂色av粉嫩av蜜乳av| 久久久久久久久久美女| 91l九色lporny| 国产精品久久久久久久第一福利 | 特级西西人体4444xxxx| 久久婷婷一区二区三区| 精品一区二区三区蜜桃在线| 国产精品久线在线观看| 老司机成人免费视频| 亚洲免费视频成人| 久久亚洲AV无码| 黑人狂躁日本妞一区二区三区| 日韩 国产 欧美| 在线播放亚洲一区| 狠狠人妻久久久久久综合麻豆| 亚洲国产成人91精品| 精品999视频| 色偷偷噜噜噜亚洲男人的天堂| 中文字幕在线播放网址| 91精品国产91久久久久久| 写真福利精品福利在线观看| 成人在线国产精品| 国产精品视频3p| 日韩av高清在线播放| 婷婷中文字幕一区| 奇米影视亚洲色图| 秋霞午夜av一区二区三区| 一卡二卡三卡四卡五卡| aaa国产一区| 日韩av片在线免费观看| 亚洲图片欧美色图| a片在线免费观看| 日韩精品在线一区二区| 欧美美女搞黄| 久久国产色av| 激情都市亚洲| 99re国产在线播放| 精品国产91乱码一区二区三区四区 | 亚洲精品高清在线观看| 成人午夜淫片100集| 这里只有精品99re| 欧美老女人性开放| 欧美激情精品久久久久久| 日韩久久一区二区三区| wwwxx欧美| 区一区二视频| 日韩精品 欧美| 国产在线观看一区二区| 成人午夜福利一区二区| 一区二区不卡在线视频 午夜欧美不卡在 | 精品福利在线看| 国产又黄又大又粗的视频| 日韩av中文在线| 伊人在我在线看导航| 国产精品老女人视频| 国产精品巨作av| 青青草免费在线视频观看| 日精品一区二区三区| 中文字幕a在线观看| 亚洲九九爱视频| 超碰在线97观看| 日韩高清欧美高清| 免费污视频在线| 亚洲a一级视频| 日韩国产专区| 日本一极黄色片| 91日韩一区二区三区| 麻豆视频在线观看| 91精品国模一区二区三区| jizz日韩| 国产成人精品优优av| 欧美日韩一本| 六月婷婷在线视频| 成人午夜看片网址| 美女福利视频在线观看| 欧美人牲a欧美精品| av在线之家电影网站| 国产精品96久久久久久| 中文字幕精品影院| 国产超级av在线| 91丨porny丨最新| 成年人免费高清视频| 亚洲大胆人体在线| 国产精品69xx| 国产高清自拍99| 影音先锋亚洲精品| 怡红院一区二区| 亚瑟在线精品视频| 手机看片福利在线| 91精品国产91久久| 制服丝袜日韩| 天天操天天爽天天射| 欧美国产日本韩| 91麻豆视频在线观看| 久久精品国产一区二区三区| 国产电影一区| 日韩精品综合在线| 99久久久久久99| 亚洲欧美偷拍视频| 国产一区二区三区在线看| 精品日韩视频| 手机福利在线视频| 国产乱码精品一区二区三区av| 日本老熟俱乐部h0930| 欧美成人三级电影在线| 免费高潮视频95在线观看网站| 久久久久网址| 免播放器亚洲一区| 精品欧美一区二区久久久久| 日韩美女视频在线| 手机在线观看av网站| 日本最新一区二区三区视频观看| 麻豆一区二区99久久久久| 国精产品一区一区二区三区mba| 在线播放91灌醉迷j高跟美女| av网站免费在线观看| 高清视频一区二区三区| 午夜亚洲性色福利视频| 欧美一区二区三区粗大| 日韩一区二区三区视频在线| 国产免费拔擦拔擦8x高清在线人| 欧美性bbwbbwbbwhd| 精久久久久久久久久久| 国产乡下妇女做爰| 一区二区av在线| 久久久国产精品入口麻豆| 黄色成人在线看| 国产精品欧美极品| 亚洲精品一区二区三区蜜桃| 日韩av大片免费看| 亚洲高清影视| 五月婷婷综合在线观看| 欧美日韩国产电影| av资源一区| 在线码字幕一区| 99久久婷婷国产| 一级α片免费看刺激高潮视频| 欧美精品video| 成人羞羞视频播放网站| aaa黄色大片| 欧美精品精品一区| xx欧美视频| 97免费视频观看| 国产精品免费久久久久| 天天躁日日躁狠狠躁伊人|