日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

静态类型的 NSUserDefaults

發(fā)布時(shí)間:2023/12/18 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 静态类型的 NSUserDefaults 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一年前,在 Swift 推出不久后,我觀察到許多 iOS 開發(fā)者仍然以 Objective-C 的開發(fā)習(xí)慣來寫 Swift。而在我眼中,Swift 是一門全新的語言,有別于 Objective-C 的語法、設(shè)計(jì)哲學(xué)乃至發(fā)展?jié)摿?#xff0c;因此我們更應(yīng)探索出一條屬于 Swift 獨(dú)有風(fēng)格的發(fā)展道路。我在之前的文章?Swifty methods?中已經(jīng)探討過在 Swift 中如何清晰、明確地對(duì)方法進(jìn)行命名,隨后我開始連載?Swifty API?系列文章,同時(shí)將這一想法付諸實(shí)踐,探索如何設(shè)計(jì)更加簡(jiǎn)單易用的接口 API。

在該系列(Swifty API)第一篇文章中,我們對(duì)?NSUserDefaults?API 進(jìn)行了改造:

NSUserDefaults.standardUserDefaults().stringForKey("color") NSUserDefaults.standardUserDefaults().setObject("red", forKey: "color")

改造之后看上去像這樣:

Defaults["color"].string Defaults["color"] = "red"

相較之前的 get 和 set 方法,改造后的結(jié)果更加簡(jiǎn)單明了,同時(shí)也修正了一致性問題,使其更符合 Swift 的使用風(fēng)格。這看上去是相當(dāng)大的改進(jìn)。

但是,隨著我對(duì) Swift 深入學(xué)習(xí),以及真正在項(xiàng)目中使用這些由我親手締造的 API 后,我才意識(shí)到這些 API 離真正的原生 Swift 風(fēng)格還有相當(dāng)大的差距。在之前的 API 設(shè)計(jì)中,我從 Ruby 和 Swift 的語法中汲取靈感來構(gòu)建自己的 API,這一點(diǎn)雖然值得肯定,但是我們并沒有將其真正提升到語義學(xué)的高度。僅僅是在外表裹了層 Swift 風(fēng)格的外衣,而內(nèi)部機(jī)制仍然是以 Objective-C 的形式在運(yùn)作。

缺點(diǎn)

「API 不是那么 Swift 化」,聽上去并不是一個(gè)讓我們從頭開始的好理由,雖然相似的 API 更容易學(xué)習(xí),但我們不想這么教條。我們不僅僅想要設(shè)計(jì)出來的 API 看上去更加 Swift 化,還希望能在 Swift 的運(yùn)行機(jī)制下更好地工作。這樣看來,我們之前設(shè)計(jì)的?NSUserDefaults?存在一些小問題:

假設(shè)你有一個(gè)關(guān)于用戶喜好顏色的設(shè)置選項(xiàng):

Defaults["color"] = "red" // App 中的其他一處: Defaults["colour"].string // => nil

啊哦,一旦不小心把鍵名(key name)寫錯(cuò)了,就會(huì)出現(xiàn) Bug :(

同理我們放一個(gè)?date?對(duì)象到?defaults?中:

Defaults["deadline"] = NSDate.distantFuture() Defaults["deadline"].data // => nil

這一次在?getter?方法中把?date?拼錯(cuò)成了?data,結(jié)果是?nil,又獲得 bug 一枚。你或許認(rèn)為這種情況并不會(huì)經(jīng)常發(fā)生,但為什么每次我們要對(duì)取回(getter)的對(duì)象指定類型呢?這確實(shí)有點(diǎn)煩人。

再來一個(gè)例子(這個(gè)例子我們?cè)谫x值的時(shí)候就錯(cuò)了,取回的結(jié)果當(dāng)然是?nil):

Defaults["deadline"] = NSData() Defaults["deadline"].date // => nil

顯然我們想要「現(xiàn)在的時(shí)間」的日期而不是一個(gè)「空的data值」!

最后觀察下面的代碼:

Defaults["magic"] = 3.14 Defaults["magic"] += 10 Defaults["magic"] // => 13

在第一篇文章中,我們重新定義了?+=,使其能夠在我的新 API 下正常工作,但這兒有個(gè)缺陷:只能從傳遞進(jìn)來的參數(shù)進(jìn)行類型推斷(Int?or?Double)。也就是說如果你參數(shù)傳一個(gè)整數(shù)(Int)10,運(yùn)算后的結(jié)果是 13.14(Double)類型,但最終返回的結(jié)果還是會(huì)以上一次傳入的參數(shù)類型為基準(zhǔn),決定最終的返回值。這個(gè)例子最后返回值為 13,砍掉了小數(shù)部分,顯然是個(gè) bug。

你又或許認(rèn)為以上都是純理論問題,在真實(shí)世界里并不會(huì)發(fā)生。先別著急下結(jié)論,仔細(xì)想想,這些拼錯(cuò)變量名、方法名和傳遞一個(gè)錯(cuò)誤類型的參數(shù)其實(shí)都可以歸為同一類型的 bug,而這些 bug 在日常開發(fā)中是常有之事。如果你正在使用一門需要編譯的靜態(tài)類型語言,那么你更應(yīng)該依賴編譯器給你的反饋而不是事后去測(cè)試,更重要的是,花費(fèi)精力在編譯期進(jìn)行檢查也會(huì)在將來給你帶來豐厚的紅利,這不僅僅是在首次寫代碼時(shí)才能享受這種編譯器檢查帶來的好處,在之后的重構(gòu)中,你也能減少很多不必要的 bug。這里提供一些小建議,可以讓未來的你免受 bug 之苦。

靜態(tài)類型的力量

導(dǎo)致這些問題的根源在于:沒有定義關(guān)于 user defaults 的靜態(tài)結(jié)構(gòu)。

在早先的設(shè)計(jì)中,我意識(shí)到這個(gè)問題,于是將各種類型封裝在了?NSUserDefaults?內(nèi)部的?Proxy?對(duì)象中。調(diào)用時(shí)你可以通過下標(biāo)(subscript)獲得一個(gè)?Proxy?對(duì)象,然后再通過 Proxy 提供的訪問方法來實(shí)現(xiàn)特定類型的訪問。

Defaults["color"].string Defaults["launchCount"].int

采用上面這種方式,比你自己實(shí)現(xiàn)?getter?方法或手動(dòng)對(duì)?AnyObject?類型轉(zhuǎn)換要好很多。

但這是一個(gè) hack,并不算真正的解決方案。為了對(duì) API 實(shí)現(xiàn)真正意義上的改進(jìn),我們需要收集有關(guān) user default keys 的信息,之后提供給編譯器。

現(xiàn)在回想下那位長(zhǎng)者傳授給我們的人生經(jīng)驗(yàn)。通常不變的常量字符串,為了避免拼寫錯(cuò)誤,會(huì)在一開始就以?string keys?的形式定義,隨后使用時(shí)編譯器也會(huì)自動(dòng)補(bǔ)全:

let colorKey = "color"

讓我們帶上類型信息:

class DefaultsKey<ValueType> { let key: String init(_ key: String) { self.key = key } } let colorKey = DefaultsKey<String?>("color")

我們將 key name 封裝在一個(gè)對(duì)象中,并且將值類型植入到泛型參數(shù)中。現(xiàn)在我們可以定義一個(gè)新的?NSUserDefaults?下標(biāo),用來接收這些 keys:

extension NSUserDefaults { subscript(key: DefaultsKey<String?>) -> String? { get { return stringForKey(key.key) } set { setObject(newValue, forKey: key.key) } } }

這里是結(jié)果:

let key = DefaultsKey<String?>("color") Defaults[key] = "green" Defaults[key] // => "green", typed as String?

沒錯(cuò),就這么簡(jiǎn)單,語法和功能稍后再來完善。我們通過這個(gè)小技巧,修復(fù)了許多問題。比如沒辦法再輕易拼錯(cuò) key name 了,因?yàn)樗荒芏x一次。也不能隨便就賦值一個(gè)不匹配的類型了,因?yàn)槟氵@么做編譯器會(huì)報(bào)錯(cuò)。最后也不必寫?.string,因?yàn)榫幾g器已經(jīng)知道我們想要的類型了。

此外,我們或許應(yīng)該使用泛型來定義?NSUserDefaults?的下標(biāo)(subscripts),而不是手動(dòng)輸入所有需要的類型。不過想法總是美好的,現(xiàn)實(shí)卻是殘酷的,Swift 的編譯器目前還不支持泛型下標(biāo)。(╯‵□′)╯︵┻━┻ 方括號(hào)可能看上去還不錯(cuò),別再糾結(jié)語法了,我們讓 setting 和 getting 方法更加泛型化就好了。

等等,你還沒有見識(shí)過下標(biāo)?subscripts?的能耐!

令人振奮的下標(biāo)

考慮下面這種寫法:

var array = [1, 2, 3] array.first! += 10

完全不能通過編譯!我們嘗試對(duì)數(shù)組內(nèi)部的整數(shù)進(jìn)行加法操作,但這對(duì)于 Swift 來說是做不到的。整數(shù)具有值語義,是不可變的。當(dāng)他們從某些地方返回時(shí),你不能直接去修改他們的值,這是因?yàn)樗麄儾⒉淮嬖谟诒磉_(dá)式之外,僅算是瞬時(shí)狀態(tài)下的一份拷貝罷了。

改換變量來做就沒問題:

var number = 1 number += 10

注意,實(shí)際并沒有真正意義上改變 1 這個(gè)整數(shù),而只是修改了變量,為其分配了一個(gè)新值而已。

再來看看下面這段代碼:

var array = [1, 2, 3] array[0] += 10 array // => [11, 2, 3]

結(jié)果終于如你所愿了,不是嗎?這和你想象中的一樣,可是為什么這么做就可以了呢?

觀察一下,在 Swift 中,下標(biāo)和里面的值類型似乎也合作地非常愉快。我們可以通過下標(biāo)來修改數(shù)組里的值,是因?yàn)樗趦?nèi)部實(shí)現(xiàn)了?getter?和?setter?方法。編譯器層面所做的工作是將?array[0] += 10重寫為?array[0] = array[0] + 10。如果你只實(shí)現(xiàn)了?getter?下標(biāo)?subscript,而沒有實(shí)現(xiàn)?setter,是不會(huì)正常工作的。

這不僅僅是數(shù)組(Array)特有的黑魔法,這是下標(biāo)(subscript)語義精心設(shè)計(jì)后的結(jié)果,我們可以在自己實(shí)現(xiàn)的?subscripts?免費(fèi)獲得這種特性,比如我們還可以這么玩:

Defaults[launchCountKey]++ Defaults[volumeKey] -= 0.1 Defaults[favoriteColorsKey].append("green") Defaults[stringKey] += "… can easily be extended!"

有意思吧,要知道在 API 1.0 版本,我們僅僅模仿字典那樣使用下標(biāo),并沒有利用上面介紹的這種語義。

我們還添加了一些?+=、++?這樣的操作符,但是這種行為比較危險(xiǎn),主要依賴于編譯器的魔法實(shí)現(xiàn)。在這里我們通過將類型信息封裝在 key 中,然后定義了?subscript?的?getter?和?setter?方法,現(xiàn)在整個(gè)世界看上去運(yùn)轉(zhuǎn)正常。

捷徑

在老版本 API 設(shè)計(jì)中,使用字符串 key 的好處在于你可以按需使用,而不用去創(chuàng)建任何中間對(duì)象。

而在目前改進(jìn)的新版本中,每次使用前都要?jiǎng)?chuàng)建鍵對(duì)象(key object)好像沒什么道理,況且這會(huì)帶來可怕的重復(fù)以及抵消掉靜態(tài)類型帶來的好處。所以讓我們?cè)傧胂肴绾文軌蚋玫亟M織?defaults keys:

一種解決方案就是在類層級(jí)(class level)定義這些 keys:

class Foo { struct Keys { static let color = DefaultsKey<String>("color") static let counter = DefaultsKey<Int>("counter") } func fooify() { let color = Defaults[Keys.color] let counter = Defaults[Keys.counter] } }

這似乎已經(jīng)是 Swift 關(guān)于字符型 keys 的標(biāo)準(zhǔn)實(shí)踐了。

另一種解決方案是利用 Swift 的隱式成員表達(dá)式,此功能的最常見用途是枚舉。當(dāng)一個(gè)方法需要一個(gè)枚舉類型?Direction?作為參數(shù),你可以傳遞?.Right。編譯器能夠推斷出真正的參數(shù)類型Direction.Right。這里有個(gè)冷知識(shí):這種特性(隱式成員表達(dá)式)同樣適用于方法參數(shù)是靜態(tài)成員類型的情形,例如你可以在一個(gè)需要?CGRect?類型做參數(shù)的方法中,使用?.zeroRect?來代替?CGRect.zeroRect。

事實(shí)上,我們可以通過把鍵定義為?DefaultsKey?上的靜態(tài)常量來做相同的事情。好啦,差不多了,最后為了消除編譯器上的限制,我們需要一個(gè)稍微不同的定義:

class DefaultsKeys {} class DefaultsKey<ValueType>: DefaultsKeys { ... } extension DefaultsKeys { static let color = DefaultsKey<String>("color") }

試一下效果,哇,不錯(cuò)哦!

Defaults[.color] = "red"

是不是很炫酷?站在調(diào)用者的角度,現(xiàn)在比之前用傳統(tǒng)字符串的方式顯得不再那么冗余,開發(fā)者的代碼量減少了,讀起來也更直觀。有沒有感到很興奮,如果我告訴你這一切都是免費(fèi)獲得的,你會(huì)不會(huì)更開心。

(這項(xiàng)技術(shù)的一個(gè)缺陷就是沒有命名空間機(jī)制,在大工程中還是老實(shí)采用鍵結(jié)構(gòu)體?Keys struct?的方式更好一些。)

可選值難題

在前一版設(shè)計(jì)的 API 中,我們讓所有的 getters 都返回可選值,不過我不大喜歡?NSUserDefaults?處理不同類型時(shí)缺乏一致性,對(duì)于字符串,缺失值將返回?nil,但是對(duì)于數(shù)字和布爾值,你將會(huì)得到?0?和?false。

我很快意識(shí)到這種方式缺點(diǎn)是太冗長(zhǎng)。大多數(shù)時(shí)候我們并不關(guān)心?nil?的情形,只希望在這種情況下得到一個(gè)默認(rèn)值,僅此而已。而每次我們通過下標(biāo)(subscripts)獲得一個(gè)可選值后,都要先解封包做判斷,再?zèng)Q定返回解包值還是預(yù)設(shè)的默認(rèn)值。

Oleg Kokhtenko 針對(duì)這個(gè)問題提出了解決方案,除了標(biāo)準(zhǔn)的可選返回值的?getter?方法,我們還添加了一組?getter?方法,這些方法都以標(biāo)志性的?-Value?結(jié)尾,并且結(jié)果為?nil?時(shí)會(huì)返回默認(rèn)值代替,這樣類型更加明確:

Defaults["color"].stringValue // 默認(rèn)得到"" Defaults["launchCount"].intValue // 默認(rèn)得到0 Defaults["loggingEnabled"].boolValue // 默認(rèn)得到false Defaults["lastPaths"].arrayValue // 默認(rèn)得到[] Defaults["credentials"].dictionaryValue // 默認(rèn)得到[:] Defaults["hotkey"].dataValue // 默認(rèn)得到NSData()

我們可以在靜態(tài)類型體制下做同樣的事情,下面為 optional 和非 optional 類型各提供一個(gè)?subscript?變體。

extension NSUserDefaults { subscript(key: DefaultsKey<NSData?>) -> NSData? { get { return dataForKey(key.key) } set { setObject(newValue, forKey: key.key) } } subscript(key: DefaultsKey<NSData>) -> NSData { get { return dataForKey(key.key) ?? NSData() } set { setObject(newValue, forKey: key.key) } } }

我喜歡這么做,因?yàn)檫@樣就不用依賴協(xié)定約定(type?和?typeValue),將空值轉(zhuǎn)換為各種類型的默認(rèn)值。而是使用已經(jīng)在 user defaults key 中定義好的類型,剩下的工作就交給編譯器吧。

更多的類型

我通過添加這些類型的下標(biāo)來擴(kuò)大支持的類型范圍:String,Int,Double,Bool,NSData,[AnyObject],[String: AnyObject],NSString,NSArray,NSDictionary(還包含他們的可選變體,注意?NSDate?,NSURL?,AnyObject??沒有對(duì)應(yīng)的非可選部分,因?yàn)檫@些類型的默認(rèn)值沒有意義)。

還要注意一點(diǎn),字符串(strings)、字典(dictionaries)和數(shù)組(arrays)同時(shí)存在于 Swift 基本庫(kù)和 Cocoa Foundation 框架中。而我們優(yōu)先考慮 Swift 原生類型,但這些類型并不具備他們?cè)?Cocoa 框架中的一些能力,不過如果真正需要,我會(huì)讓事情簡(jiǎn)單一些。

提到數(shù)組,為什么把我們只限制沒有類型化的數(shù)組?因?yàn)樵诖蠖鄶?shù)情況下,user defaults?中存儲(chǔ)的數(shù)組里面的元素都是同一類型的,比如?String,Int,NSData。

因?yàn)椴荒芏x泛型下標(biāo),我們來創(chuàng)建一對(duì)泛型?helper?方法:

extension NSUserDefaults { func getArray<T>(key: DefaultsKey<[T]>) -> [T] { return arrayForKey(key.key) as? [T] ?? [] } func getArray<T>(key: DefaultsKey<[T]?>) -> [T]? { return arrayForKey(key.key) as? [T] } }

復(fù)制、粘貼,然后參照下面這段代碼改寫所有我們感興趣的類型:

extension NSUserDefaults { subscript(key: DefaultsKey<[String]?>) -> [String]? { get { return getArray(key) } set { set(key, newValue) } } }

現(xiàn)在可以這樣調(diào)用:

let key = DefaultsKey<[String]>("colors") Defaults[key].append("red") let red = Defaults[key][0]

我們通過數(shù)組下標(biāo)返回一個(gè)?String,然后為其添加了一個(gè)字符串,整個(gè)驗(yàn)證過程發(fā)生在了編譯期(編譯器會(huì)對(duì)進(jìn)行的操作進(jìn)行類型檢查),這樣做更加安全便捷。

歸檔

NSUserDefaults?還有一個(gè)缺點(diǎn)是支持的類型并不多,如果我們想存儲(chǔ)自定義的類型,通用的解決辦法是用?NSKeyedArchiver?來序列化你的自定義對(duì)象。

接下來我們努力把世界變得更美好一點(diǎn),類似于?getArray?的 helper 方法,我定義了?archive()?和?unarchive()?的泛型方法,這樣我就能很容易地設(shè)計(jì)一段下標(biāo)代碼來處理各種自定義類型(前提是這些類型遵循 NSCoding 協(xié)議)。

extension NSUserDefaults { subscript(key: DefaultsKey<NSColor?>) -> NSColor? { get { return unarchive(key) } set { archive(key, newValue) } } } extension DefaultsKeys { static let color = DefaultsKey<NSColor?>("color") } Defaults[.color] // => nil Defaults[.color] = NSColor.whiteColor() Defaults[.color] // => w 1.0, a 1.0 Defaults[.color]?.whiteComponent // => 1.0

(譯者注:NSColor?遵循?NSSecureCoding?協(xié)議,而該協(xié)議繼承自?NSCoding)

看上去并不十分完美,但我們僅用了幾行代碼就讓?NSUserDefaults?很好地支持了自定義類型。

結(jié)果和結(jié)論

萬事俱備,下面有請(qǐng)我們新的 API 登場(chǎng):

// 提前定義鍵名 extension DefaultsKeys { static let username = DefaultsKey<String?>("username") static let launchCount = DefaultsKey<Int>("launchCount") static let libraries = DefaultsKey<[String]>("libraries") static let color = DefaultsKey<NSColor?>("color") } // 使用點(diǎn)語法來獲取 user defaults Defaults[.username] // 使用非可選的鍵來獲取默認(rèn)值而非可選值 Defaults[.launchCount] // Int, 默認(rèn)值是0 // 就地更新 value 的值 Defaults[.launchCount]++ Defaults[.volume] += 0.1 Defaults[.strings] += "… can easily be extended!" // 使用和修改數(shù)組類型 Defaults[.libraries].append("SwiftyUserDefaults") Defaults[.libraries][0] += " 2.0" // 方便地使用序列化的自定義類型 Defaults[.color] = NSColor.whiteColor() Defaults[.color]?.whiteComponent // => 1.0

Swift 中使用起來不再痛苦的靜態(tài)類型

希望你已經(jīng)看到這種靜態(tài)類型帶來的好處,我們只付出了很小的代價(jià),包括提前定義?DefaultsKey,遵從 Swift 的類型系統(tǒng)。而作為回報(bào),編譯器向我們獻(xiàn)上一份大禮:

  • 編譯期檢查(鍵名,讀、寫的類型檢查)
  • 鍵名(key names)自動(dòng)補(bǔ)全
  • 類型推斷——不必在末尾輸入?.string?或手動(dòng)對(duì)?AnyObject?進(jìn)行類型轉(zhuǎn)換
  • 我們可以直接操作 user defaults 里面的值,而不需要通過中間步驟或魔法運(yùn)算符
  • 一致性——拋開怪異的 keys,Defaults?看上去更像是一個(gè)定義了類型的字典

這里還有一個(gè)潛在優(yōu)勢(shì):可以自動(dòng)享受到今后 Swift 的發(fā)展紅利。

真正的 Swift 的 API 也利用了靜態(tài)類型特性,這里不是要教條主義,條條大路通羅馬,肯定還有其他的最佳解決方案。但當(dāng)你決定回到 Objective-C 或 JavaScript 的編碼習(xí)慣時(shí),重新考慮一下靜態(tài)類型所帶來的好處,還要明白一點(diǎn),這種靜態(tài)類型不是你前輩所熟悉的靜態(tài)類型,Swift 豐富的類型系統(tǒng)允許你創(chuàng)造出極具表現(xiàn)力和易用的 API,而實(shí)現(xiàn)這一切的開銷卻可以忽略不計(jì)。

試試看

一如既往,我將以上所有的探索整理成了一個(gè)庫(kù),放在?GitHub?上,如果感興趣,可以采取下面的方式引用:

# with CocoaPods: pod 'SwiftyUserDefaults' # with Carthage: github "radex/SwiftyUserDefaults"

同樣也鼓勵(lì)你去試用我改造的另一個(gè) Swifty API(NSTimer),關(guān)于如何清晰命名請(qǐng)看我這篇文章?Swifty methods。

最后如果你對(duì)本文有什么好的想法或建議,請(qǐng)務(wù)必聯(lián)系我?Twitter?或提出?issue

轉(zhuǎn)載于:https://www.cnblogs.com/linganxiong/p/8124782.html

總結(jié)

以上是生活随笔為你收集整理的静态类型的 NSUserDefaults的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日韩成人高清视频在线观看 | 国产毛片91| 亚洲一区二区观看播放 | 天天搞天天干 | 国产男女猛烈无遮挡免费观看网站 | 最新日韩三级 | 国产麻豆成人传媒免费观看 | 一二三四区在线 | 久久国产二区 | 亚洲欧美日韩国产综合 | 亚洲呦呦 | 国产欧美日韩专区发布 | 丰满人妻一区二区三区无码av | 92国产精品 | 亚洲成人偷拍 | 中文字幕十一区 | 干老太太视频 | 午夜影院免费观看 | 人人妻一区二区三区 | 欧美精品日韩在线观看 | 亚洲成人黄色 | 91超级碰| 特黄特色大片免费视频大全 | 国产av剧情一区二区三区 | 爆乳熟妇一区二区三区霸乳 | 成人123 | 亚洲精品成人久久 | 极品av在线| 色欲久久久天天天精品综合网 | 欧美精品一二三四 | 超碰人人超碰 | 国产精品伦理 | 久草黄色 | 色丁香六月 | 国产女人与zoxxxx另类 | 久久撸视频 | 高清av网站| 欧美高清精品一区二区 | wwwxxx在线 | 日韩精品一区二区亚洲av性色 | 日韩网站在线观看 | 国产精品情侣 | 欧美午夜精品久久久久免费视 | 久久99精品久久久久子伦 | 色花堂在线 | 日日干干 | 欧美日韩亚洲视频 | 四虎网站最新网址 | 日韩一级淫片 | 毛片999| 亚洲天堂免费在线 | 免费麻豆国产一区二区三区四区 | 女女h百合无遮羞羞漫画软件 | 国产乱淫av一区二区三区 | 中文字幕大全 | 欧美激情视频一区二区三区 | 亚洲50p| 苍井空亚洲精品aa片在线播放 | 日韩三级成人 | 91九色论坛 | 亚日韩av| 午夜精品在线免费观看 | 欧美乱妇18p | 欧美20p| 天天色天天爽 | 免费观看污网站 | 按摩害羞主妇中文字幕 | 性猛交xxxx乱大交孕妇2十 | 成年人午夜网站 | 国产51页| 日本视频一区二区三区 | 日日夜夜噜 | 亚洲骚图 | 久久精品成人一区二区三区蜜臀 | 日本一区二区三区视频在线播放 | av第一福利大全导航 | 黄页视频在线观看 | av久久久 | 亚洲人体av| 亚洲精品一区在线 | 亚洲AV无码成人精品区在线观 | 久久综合中文字幕 | av色婷婷| 欧美人与野 | 日韩欧美精品在线观看 | 亚洲福利一区二区三区 | 久久成人精品 | 久久综合亚洲 | 秋霞毛片少妇激情免费 | 黄色片网站在线 | 网站在线播放 | 日本精品一区在线观看 | 午夜精品成人毛片非洲 | 以女性视角写的高h爽文 | 亚洲AV无码成人国产精品色 | 国模人体私拍xvideos | 韩国伦理片免费看 | 粉嫩av网址| 好吊视频在线观看 |