亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

Objective-C中編程中一些推薦的書寫規范小結

2020-07-26 03:23:25
字體:
來源:轉載
供稿:網友

一、類
1. 類名
類名應該以三個大寫字母作為前綴(雙字母前綴為Apple的類預留)

不僅僅是類,公開的常量、Protocol等的前綴都為相同的三個大寫字母。

當你創建一個子類的時候,你應該把說明性的部分放在前綴和父類名的中間。

例如:

如果你有一個 ZOCNetworkClient 類,子類的名字會是ZOCTwitterNetworkClient (注意 "Twitter" 在 "ZOC" 和 "NetworkClient" 之間); 按照這個約定, 一個UIViewController 的子類會是 ZOCTimelineViewController.

2. Initializer和dealloc
推薦的代碼組織方式是將dealloc方法放在實現文件的最前面(直接在@synthesize以及@dynamic之后),init應該跟在dealloc方法后面。

如果有多個初始化方法,那么指定初始化方法應該放在最前面,間接初始化方法跟在后面。

如今有了ARC,dealloc方法幾乎不需要實現,不過把init和dealloc放在一起,強調它們是一對的。通常在init方法中做的事情需要在dealloc方法中撤銷。

關于指定初始化方法(designated initializer)和間接初始化方法(secondary initializer)

Objective-C 有指定初始化方法(designated initializer)和間接(secondary initializer)初始化方法的觀念。 designated 初始化方法是提供所有的參數,secondary 初始化方法是一個或多個,并且提供一個或者更多的默認參數來調用 designated 初始化的初始化方法。

復制代碼 代碼如下:

@implementation ZOCEvent

- (instancetype)initWithTitle:(NSString *)title
                         date:(NSDate *)date
                     location:(CLLocation *)location
{
    self = [super init];
    if (self) {
        _title    = title;
        _date     = date;
        _location = location;
    }
    return self;
}

- (instancetype)initWithTitle:(NSString *)title
                         date:(NSDate *)date
{
    return [self initWithTitle:title date:date location:nil];
}

- (instancetype)initWithTitle:(NSString *)title
{
    return [self initWithTitle:title date:[NSDate date] location:nil];
}

@end


initWithTitle:date:location: 就是 designated 初始化方法,另外的兩個是 secondary 初始化方法。因為它們僅僅是調用類實現的 designated 初始化方法。

一個類應該有且只有一個 designated 初始化方法,其他的初始化方法應該調用這個 designated 的初始化方法(有例外)。

3. 當定義一個新類的時候有三個不同的方式:
(1)不需要重載任何初始化函數
(2)重載 designated initializer
(3)定義一個新的 designated initializer
第一種方式不需要增加類的任何初始化邏輯,也就是說在類中不必重寫父類的初始化方法也不需要其他操作。

第二種方式要重載父類的指定初始化方法。例子:

復制代碼 代碼如下:

@implementation ZOCViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    // call to the superclass designated initializer
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization (自定義的初始化過程)
    }
    return self;
}

@end


這個例子中,ZOCViewController繼承自UIViewController,這里我們有一些其他的需求(比如希望在初始化的時候給一些成員變量賦值),所以需要重寫父類的指定初始化方法initWithNibName:bundle:方法。

注意,如果在這里并沒有重載這個方法,而是重載了父類的init方法,那么會是一個錯誤。

因為在創建這個類(ZOCViewController)的時候,會調用initWithNib:bundle:這個方法,所以我們重載這個方法,首先保證父類初始化成功,然后在這個方法中進行額外的初始化操作。但是如果重載init方法,在創建這個類的時候,并不會調用init方法(調用的是initWithNib:bundle:這個指定初始化方法)。

第三種方式是希望提供自己的類初始化方法,應該遵守下面三個步驟來保證正確性:

定義你的 designated initializer,確保調用了直接超類的 designated initializer。
重載直接超類的 designated initializer。調用你的新的 designated initializer。
為新的 designated initializer 寫文檔。
很多開發者會忽略后兩步,這不僅僅是一個粗心的問題,而且這樣違反了框架的規則,而且可能導致不確定的行為和bug。

正確的例子:

復制代碼 代碼如下:

@implementation ZOCNewsViewController

- (id)initWithNews:(ZOCNews *)news
{
    // call to the immediate superclass's designated initializer (調用直接超類的 designated initializer)
    self = [super initWithNibName:nil bundle:nil];
    if (self) {
        _news = news;
    }
    return self;
}

// Override the immediate superclass's designated initializer (重載直接父類的  designated initializer)
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    // call the new designated initializer
    return [self initWithNews:nil];
}

@end


​很多開發者只會寫第一個自定義的初始化方法,而不重載父類的指定初始化方法。

在第一個自定義的初始化方法中,因為我們要定義自己的指定初始化方法,所以在最開始的時候首先要調用父類的指定初始化方法以保證父類都初始化成功,這樣ZOCNewsViewController才是可用狀態。(因為父類是通過initWithNibName:bundle:這個指定初始化方法創建的,所以我們要調用父類的這個方法來保證父類初始化成功)。然后在后面給_news賦值。

​如果僅僅是這樣做是存在問題的。調用者如果調用initWithNibName:bundle:來初始化這個類也是完全合法的,如果是這種情況,那么initWithNews:這個方法永遠不會被調用,所以_news = news也不會被執行,這樣導致了不正確的初始化流程。

解決方法就是需要重載父類的指定初始化方法,在這個方法中返回新的指定初始化方法(如例子中做的那樣),這樣無論是調用哪個方法都可以成功初始化。

間接初始化方法是一種提供默認值、行為到初始化方法的方法。

你不應該在間接初始化方法中有初始化實例變量的操作,并且你應該一直假設這個方法不會得到調用。我們保證的是唯一被調用的方法是 designated initializer。

這意味著你的 secondary initializer 總是應該調用 Designated initializer 或者你自定義(上面的第三種情況:自定義Designated initializer)的 self的 designated initializer。有時候,因為錯誤,可能打成了 super,這樣會導致不符合上面提及的初始化順序。

也就是說,你可能看到一個類有多個初始化方法,實際上是一個指定初始化方法(或多個,比如UITableViewController就有好幾個)+多個間接初始化方法。這些簡潔初始化方法可能會根據不同的參數做不同的操作,但是本質上都是調用指定初始化方法。所以說,間接初始化方法是有可能沒有調用到的,但是指定初始化方法是會調用到的(并不是每一個都會調用到,但是最后調用的一定是一個指定初始化方法)。(這里又可以引申到上面提到的問題,我們可以直接重寫父類的指定初始化方法,也可以自定義初始化方法(在這個方法中需要用到self = [super 父類初始化方法]這種形式的代碼),并且如果是自定義初始化方法,還應該重寫從父類繼承的初始化方法來返回我們的自定義初始化方法…)。

總之就是,如果重寫父類的指定初始化方法首先需要調用父類的相應初始化方法;如果增加自定義指定初始化方法,首先在新增的自定義指定初始化方法中調用父類的相應初始化方法,然后需要重寫父類的指定初始化方法,在重寫的方法中調用剛剛添加的自定義指定初始化方法。

4.補充

一個類可能有多個指定初始化方法,也有可能只有一個指定初始化方法。

以UITableViewController為例,我們可以看到:

復制代碼 代碼如下:

- (instancetype)initWithStyle:(UITableViewStyle)style NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;

它有三個指定初始化方法,我們剛才說,當子類從父類繼承并重寫初始化方法,首先需要調用父類的初始化方法,但是如果一個類的初始化方法有多個,那么需要調用哪個呢?

事實上不同的創建方式要調用不同的指定初始化方法。

比如,我們以Nib的形式創建UITableViewController,那么最后調用的就是- (instancetype)initWithNibName:(NSString )nibNameOrNil bundle:(NSBundle )nibBundleOrNil這個指定初始化方法;如果我們以Storyboard的形式創建,那么最后調用的就是- (instancetype)initWithCoder:(NSCoder *)aDecoder這個指定初始化方法。如果以代碼的形式創建,那么最后調用的就是- (instancetype)initWithStyle:(UITableViewStyle)style這個指定初始化方法。所以不同的情況需要重寫不同的指定初始化方法,并且重寫的時候首先要調用父類相應的指定初始化方法(比如重寫initWithCoder:方法,那么首先self = [super initWithCoder:…],都是一一對應的)。

再以UIViewController為例,我們以Nib的形式創建UIViewController,那么最后調用的是- (instancetype)initWithNibName:(NSString )nibNameOrNil bundle:(NSBundle )nibBundleOrNil,這與UITableViewController是一樣的;如果我們以Storyboard的形式創建,那么最后調用的是- (instancetype)initWithCoder:(NSCoder )aDecoder,這與UITableViewController也是一樣的;但是如果我們以代碼的形式創建UIViewController(eg: CYLViewController vc = [[CYLViewController alloc] init]; CYLViewController繼承自UIViewController),那么它最后調用的實際是- (instancetype)initWithNibName:(NSString )nibNameOrNil bundle:(NSBundle )nibBundleOrNil,這與UITableViewController是不一樣的,因為UIViewController并沒有- (instancetype)initWithStyle:(UITableViewStyle)style這個方法,所以當用代碼創建的時候,最后調用的也是initWithNibName:bundle這個指定初始化方法,并且參數自動設置為nil。

所以現在反過頭來再看UITableViewController,當使用代碼的方式創建的時候(eg: CYLTableViewController tvc = [[CYLTableViewController alloc] init]; 或者 CYLTableViewController tvc = [[CYLTableViewController alloc] initWithStyle: UITableViewStylePlain]; ),它會調用initWithStyle:這個方法,但是如果你也實現了initWithNibName:bundle:這個方法,你會發現這個方法也被調用了。因為UITableViewController繼承自UIViewController,所以當用代碼創建的時候,最后也會掉用到initWithNIbName:bundle:(因為UIViewController就是這么干的)。

所以用代碼創建UITableViewController的時候,它會調用initWithNibName:bundle:和initWithStyle:這兩個方法。

二、屬性
屬性要盡可能描述性地命名,并且使用駝峰命名。

關于”*”的位置:

復制代碼 代碼如下:

// 推薦
NSString *text;

// 不推薦
NSString* text;
NSString * text;


注意,這個習慣和常量并不同。

static NSString * const ...
你永遠不能在 init (以及其他初始化函數)里面用 getter 和 setter 方法,你應該直接訪問實例變量。記住一個對象是僅僅在 init 返回的時候,才會被認為是初始化完成到一個狀態了。

當使用 setter/getter 方法的時候盡量使用點符號。

復制代碼 代碼如下:

// 推薦
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;

// 不推薦
[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;


使用點符號會讓表達更加清晰并且幫助區分屬性訪問和方法調用。

屬性定義

復制代碼 代碼如下:

@property (nonatomic, readwrite, copy) NSString *name;

屬性的參數應該按照這個順序排列: 原子性,讀寫和內存管理。

習慣上修改某個屬性的修飾符時,一般從屬性名從右向左搜索需要修動的修飾符。最可能從最右邊開始修改這些屬性的修飾符,根據經驗這些修飾符被修改的可能性從高到底應為:內存管理 > 讀寫權限 >原子操作
你必須使用 nonatomic,除非特別需要的情況。在iOS中,atomic帶來的鎖特別影響性能。

如果想要一個公開的getter和私有的setter,你應該聲明公開的屬性為 readonly 并且在類擴展總重新定義通用的屬性為 readwrite 的。

復制代碼 代碼如下:

//.h文件中
@interface MyClass : NSObject
@property (nonatomic, readonly, strong) NSObject *object;
@end

復制代碼 代碼如下:

//.m文件中
@interface MyClass ()
@property (nonatomic, readwrite, strong) NSObject *object;
@end

復制代碼 代碼如下:

@implementation MyClass
//Do Something cool
@end

描述BOOL屬性的詞如果是形容詞,那么setter不應該帶is前綴,但它對應的 getter 訪問器應該帶上這個前綴。

@property (assign, getter=isEditable) BOOL editable;
任何可以用來用一個可變的對象設置的((比如 NSString,NSArray,NSURLRequest))屬性的的內存管理類型必須是 copy 的。(原文中是這樣說的,但是我理解的話并不是絕對的。如果不想讓原來的可變對象影響到類的這個相應屬性,那么就需要用copy,這樣在賦值的時候可變對象會首先進行copy完成深拷貝,再把拷貝出的值賦給類的屬性,這樣就能保證類屬性和原來的可變對象影響并不影響。但是如果想讓類屬性對原來的可變對象是一個強引用,指向這個可變對象,那么會用strong。)

你應該同時避免暴露在公開的接口中可變的對象,因為這允許你的類的使用者改變類自己的內部表示并且破壞類的封裝。你可以提供可以只讀的屬性來返回你對象的不可變的副本。

復制代碼 代碼如下:

/* .h */
@property (nonatomic, readonly) NSArray *elements

/* .m */
- (NSArray *)elements {
  return [self.mutableElements copy];
}


雖然使用懶加載在某些情況下很不錯,但是使用前應當深思熟慮,因為懶加載通常會產生一些副作用。(但是懶加載還是比較常用的,比如下面的例子)

副作用指當調用函數時,除了返回函數值之外,還對主調用函數產生附加的影響。例如修改全局變量(函數外的變量)或修改參數。函數副作用會給程序設計帶來不必要的麻煩,給程序帶來十分難以查找的錯誤,并且降低程序的可讀性。

復制代碼 代碼如下:

- (NSDateFormatter *)dateFormatter {
  if (!_dateFormatter) {
    _dateFormatter = [[NSDateFormatter alloc] init];
        NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
        [_dateFormatter setLocale:enUSPOSIXLocale];
        [_dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS"];//毫秒是SSS,而非SSSSS
  }
  return _dateFormatter;
}

三、方法
1.參數斷言

你的方法可能要求一些參數來滿足特定的條件(比如不能為nil),在這種情況下啊最好使用 NSParameterAssert() 來斷言條件是否成立或是拋出一個異常。

復制代碼 代碼如下:

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self testMethodWithAParameter:0];
}

- (void)testMethodWithAParameter: (int)value
{
    NSParameterAssert(value != 0);

    NSLog(@"正確執行");
}


在此例中, 如果傳的參數為0,那么程序會拋出異常。

2.私有方法

永遠不要在你的私有方法前加上 _ 前綴。這個前綴是 Apple 保留的。不要冒重載蘋果的私有方法的險。

當你要實現相等性的時候記住這個約定:你需要同時實現isEqual 和 hash方法。如果兩個對象是被isEqual認為相等的,它們的 hash 方法需要返回一樣的值。但是如果 hash 返回一樣的值,并不能確保他們相等。

復制代碼 代碼如下:

@implementation ZOCPerson

- (BOOL)isEqual:(id)object {
    if (self == object) {
        return YES;
    }

    if (![object isKindOfClass:[ZOCPerson class]]) {
        return NO;
    }

    // check objects properties (name and birthday) for equality (檢查對象屬性(名字和生日)的相等性
    ...
    return propertiesMatch;
}

- (NSUInteger)hash {
    return [self.name hash] ^ [self.birthday hash];
}

@end


你總是應該用 isEqualTo<#class-name-without-prefix#>: 這樣的格式實現一個相等性檢查方法。如果你這樣做,會優先調用這個方法來避免上面的類型檢查。

所以一個完整的 isEqual 方法應該是這樣的:

復制代碼 代碼如下:

- (BOOL)isEqual:(id)object {
    if (self == object) {
      return YES;
    }

    if (![object isKindOfClass:[ZOCPerson class]]) {
      return NO;
    }

    return [self isEqualToPerson:(ZOCPerson *)object];
}

- (BOOL)isEqualToPerson:(Person *)person {
    if (!person) {
        return NO;
    }

    BOOL namesMatch = (!self.name && !person.name) ||
                       [self.name isEqualToString:person.name];
    BOOL birthdaysMatch = (!self.birthday && !person.birthday) ||
                           [self.birthday isEqualToDate:person.birthday];

  return haveEqualNames && haveEqualBirthdays;
}


四、Category
category 方法前加上自己的小寫前綴以及下劃線。(真的很丑,但是蘋果也推薦這樣做)
復制代碼 代碼如下:

- (id)zoc_myCategoryMethod

這是非常必要的。因為如果在擴展的 category 或者其他 category 里面已經使用了同樣的方法名,會導致不可預計的后果。(會調用最后一個加載的方法)
復制代碼 代碼如下:

// 推薦
@interface NSDate (ZOCTimeExtensions)
- (NSString *)zoc_timeAgoShort;
@end

復制代碼 代碼如下:

// 不推薦
@interface NSDate (ZOCTimeExtensions)
- (NSString *)timeAgoShort;
@end

推薦使用Category來根據不同功能對方法進行分組。
復制代碼 代碼如下:

@interface NSDate : NSObject <NSCopying, NSSecureCoding>

@property (readonly) NSTimeInterval timeIntervalSinceReferenceDate;

@end


復制代碼 代碼如下:

@interface NSDate (NSDateCreation)

+ (instancetype)date;
+ (instancetype)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs;
+ (instancetype)dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)ti;
+ (instancetype)dateWithTimeIntervalSince1970:(NSTimeInterval)secs;
+ (instancetype)dateWithTimeInterval:(NSTimeInterval)secsToBeAdded sinceDate:(NSDate *)date;
// ...
@end


五、NSNotification
當你定義你自己的 NSNotification 的時候你應該把你的通知的名字定義為一個字符串常量,就像你暴露給其他類的其他字符串常量一樣。你應該在公開的接口文件中將其聲明為 extern 的, 并且在對應的實現文件里面定義。

因為你在頭文件中暴露了符號,所以你應該按照統一的命名空間前綴法則,用類名前綴作為這個通知名字的前綴。(通常在頭文件中對外提供的常量都需要加上前綴,聲明extern + const,并且并不是在頭文件中定義,而是在實現文件中定義。如果不是對外公開的常量,那么通常直接在實現文件里聲明為static + const,并且也要加上前綴,直接在后面進行定義。)

同時,用一個 Did/Will 這樣的動詞以及用 "Notifications" 后綴來命名這個通知也是一個好的實踐。

復制代碼 代碼如下:

// Foo.h
extern NSString * const ZOCFooDidBecomeBarNotification

// Foo.m
NSString * const ZOCFooDidBecomeBarNotification = @"ZOCFooDidBecomeBarNotification";


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲xxxx妇黄裸体| 欧美亚洲第一页| 亚洲国产天堂久久国产91| 一区二区三区美女xx视频| 久久久久99精品久久久久| 精品视频在线观看日韩| 色播久久人人爽人人爽人人片视av| 国产人妖伪娘一区91| 欧美黄色片视频| 懂色av中文一区二区三区天美| 国产成人中文字幕| 欧美老妇交乱视频| 黄色成人在线播放| 久久精品视频一| 亚洲免费福利视频| 日韩av成人在线| 欧美激情精品久久久久久黑人| 欧美尺度大的性做爰视频| 中文字幕精品在线| 欧美国产日本在线| 日韩精品极品视频免费观看| 欧美激情一区二区三区高清视频| 亚洲直播在线一区| 国产精品精品视频一区二区三区| 亚洲精品视频中文字幕| 国语自产精品视频在线看抢先版图片| 久久久久国产精品www| 久久久999国产精品| 欧美孕妇与黑人孕交| 中文字幕日韩在线播放| 亚洲一区二区三区香蕉| 色偷偷av一区二区三区| 国产精品极品美女粉嫩高清在线| 精品magnet| 中文亚洲视频在线| 欧美精品videos另类日本| 国产精品成人av性教育| 这里只有精品丝袜| 亚洲一区二区久久久久久| 日本国产欧美一区二区三区| 91精品久久久久久久久久久久久| 精品美女久久久久久免费| 伊人伊成久久人综合网站| 欧美成人一区在线| 日韩国产精品亚洲а∨天堂免| 久久夜色精品亚洲噜噜国产mv| 国产视频一区在线| 中文字幕在线亚洲| 欧美性69xxxx肥| 亚洲精品mp4| 国产一区二区三区视频免费| 91精品久久久久久久久久| 欧美美最猛性xxxxxx| 日韩精品在线免费观看视频| 国产九九精品视频| 国产精品一区二区3区| 国产精品1区2区在线观看| 久久影视电视剧免费网站| 日日骚久久av| 成人a免费视频| 亚洲精品久久久久中文字幕二区| 成人av电影天堂| 欧美日韩亚洲一区二区| 国产精品久久精品| 欧美高清视频一区二区| 一本大道久久加勒比香蕉| 国产一区二区三区毛片| 亚洲欧美精品在线| 久久久亚洲欧洲日产国码aⅴ| 日韩在线观看免费高清| 日韩av电影手机在线| 9.1国产丝袜在线观看| 午夜精品久久久久久久99热浪潮| 欧美在线视频a| 国产精品久久久久久av下载红粉| 一区二区三区天堂av| 国产97在线视频| 亚洲精品免费一区二区三区| 97国产精品视频人人做人人爱| 精品中文字幕视频| 久久久久日韩精品久久久男男| 高清视频欧美一级| 欧美日韩在线免费| 国产高清在线不卡| 日韩激情第一页| 日韩欧美国产高清91| 98精品国产自产在线观看| 亚洲伊人一本大道中文字幕| 久久久久久久色| 国产亚洲激情视频在线| 欧美电影免费在线观看| 成人福利免费观看| 国产精品久久久久久av福利| 色无极影院亚洲| 日韩电影大片中文字幕| 亚洲最新视频在线| 亚洲黄色av女优在线观看| 另类色图亚洲色图| 亚洲福利视频二区| 另类色图亚洲色图| 国内伊人久久久久久网站视频| 国产在线观看精品一区二区三区| 午夜精品一区二区三区在线播放| 久久999免费视频| 久久九九有精品国产23| 亚洲欧洲一区二区三区久久| 欧美性极品少妇精品网站| 亚洲午夜色婷婷在线| 亚洲一区av在线播放| 国内精品400部情侣激情| 日韩在线中文字| 亚洲国产精品va在线看黑人| 久久国产精品久久久久久| 欧美日韩在线免费| 亚洲精品美女免费| 国产精品露脸自拍| 国产精品久久久久久av福利| 欧美视频国产精品| 国模gogo一区二区大胆私拍| 国产精品第一视频| 久久精品国产清自在天天线| 国产精品最新在线观看| 97色在线视频观看| 欧美激情视频网址| 亚洲男人7777| 日日狠狠久久偷偷四色综合免费| 97国产精品免费视频| 中文日韩在线视频| 亚洲一区二区三区乱码aⅴ| 91色p视频在线| 亚洲裸体xxxx| 亚洲精品欧美极品| 成人在线小视频| 欧美视频一区二区三区…| 亚洲精品ady| 黄色一区二区三区| 欧美成人sm免费视频| 3344国产精品免费看| 2020久久国产精品| 久久成人一区二区| 国产美女直播视频一区| 精品偷拍各种wc美女嘘嘘| 亚洲欧洲自拍偷拍| 欧美日韩一区二区三区| 久久久午夜视频| 欧美性极品xxxx做受| 在线观看欧美www| 国产精品久久久久久久久久三级| 亚洲精品一区久久久久久| 亚洲精品乱码久久久久久金桔影视| 国内精品小视频在线观看| 国产精品国内视频| 欧美激情精品久久久久久久变态| 亚洲四色影视在线观看| 中文在线资源观看视频网站免费不卡| 国产丝袜一区视频在线观看| 一本大道亚洲视频| 美日韩丰满少妇在线观看| 日韩在线中文字| 国产精品成人一区| 秋霞av国产精品一区| 91最新国产视频| 国产成人精品最新| 亚洲综合在线中文字幕|