跟著Alamofire(4.0.0)學(xué)Swift3(二)

建議先看跟著Alamofire(4.0.0)學(xué)Swift3(一)仁锯。再看本文。

跟著Alamofire(4.0.0)學(xué)Swift3(一)中翔悠,分析到了類(lèi)Request(請(qǐng)求)业崖。今天主要分析下面幾個(gè):

  • 1.Response
  • 2.SessionDelegate
  • 3.SessionManager

Response

類(lèi)和結(jié)構(gòu)體的使用

這個(gè)類(lèi)給自己最大的啟發(fā)就是在Swift中類(lèi)和結(jié)構(gòu)體的使用。大家對(duì)結(jié)構(gòu)體和類(lèi)應(yīng)該并不陌生蓄愁,但是在OC中双炕,我們?cè)趯?xiě)代碼的時(shí)候很少用到結(jié)構(gòu)體±缘牵或許是個(gè)人的習(xí)慣雄家,就我身邊的同事大部分是這樣的效诅。但是在Swift的中胀滚,結(jié)構(gòu)體出現(xiàn)的頻率相當(dāng)高。在文件Response.swift中沒(méi)有定義一個(gè)類(lèi)乱投,全是結(jié)構(gòu)體咽笼。

先來(lái)回顧一下Swift中結(jié)構(gòu)體和類(lèi)的關(guān)系:

  • 1.都可以有屬性和方法;
  • 2.都有構(gòu)造器戚炫;
  • 3.都支持附屬腳本剑刑;
  • 4.都支持?jǐn)U展;
  • 5.都支持協(xié)議双肤。

然后我們來(lái)看看他們的不同之處:

  • 1.類(lèi)有繼承施掏;
  • 2.結(jié)構(gòu)體有一個(gè)自動(dòng)生成的逐一初始化構(gòu)造器;
  • 3.在做賦值操作時(shí)茅糜,結(jié)構(gòu)體總是被拷貝(Array有特殊處理)七芭;
  • 4.結(jié)構(gòu)體可以聲明靜態(tài)的屬性和方法;
  • 5.從設(shè)計(jì)模式的角度來(lái)分析蔑赘,類(lèi)的設(shè)計(jì)更側(cè)重于對(duì)功能的封裝狸驳,而結(jié)構(gòu)體的設(shè)計(jì)更側(cè)重于對(duì)數(shù)據(jù)的封裝预明。

關(guān)于屬性的對(duì)比可以參考下面這張圖。


說(shuō)明:類(lèi)的靜態(tài)屬性表示用class修飾的變量耙箍,別和用static修飾的搞混了撰糠。用static是沒(méi)問(wèn)題的

結(jié)構(gòu)體上場(chǎng)

很多同學(xué)可能很疑惑,什么時(shí)候用結(jié)構(gòu)體辩昆,什么時(shí)候用類(lèi)阅酪。這點(diǎn)上可以根據(jù)類(lèi)的設(shè)計(jì)更側(cè)重于對(duì)功能的封裝,而結(jié)構(gòu)體的設(shè)計(jì)更側(cè)重于對(duì)數(shù)據(jù)的封裝卤材。為了便于代碼組織遮斥,一般在結(jié)構(gòu)體的擴(kuò)展里面添加方法比如在Response.swift中:

public struct DefaultDataResponse {
    public let request: URLRequest?
    public let response: HTTPURLResponse?
    public let data: Data?
    public let error: Error?

    var _metrics: AnyObject?

    init(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) {
        self.request = request
        self.response = response
        self.data = data
        self.error = error
    }
}

結(jié)構(gòu)體DefaultDataResponse完全滿(mǎn)足對(duì)數(shù)據(jù)的封裝,當(dāng)然這里用類(lèi)來(lái)封裝這些數(shù)據(jù)其實(shí)也可以扇丛,但是就感覺(jué)沒(méi)有那么完美术吗。
同樣在文件中出現(xiàn)的。DataResponse也是結(jié)構(gòu)體帆精。然后通過(guò)擴(kuò)展給結(jié)構(gòu)體添加方法较屿,或者應(yīng)該算是屬性

extension DataResponse: CustomStringConvertible, CustomDebugStringConvertible {
    /// The textual representation used when written to an output stream, which includes whether the result was a
    /// success or failure.
    public var description: String {
        return result.debugDescription
    }
    /// The debug textual representation used when written to an output stream, which includes the URL request, the URL
    /// response, the server data, the response serialization result and the timeline.
    public var debugDescription: String {
        var output: [String] = []

        output.append(request != nil ? "[Request]: \(request!)" : "[Request]: nil")
        output.append(response != nil ? "[Response]: \(response!)" : "[Response]: nil")
        output.append("[Data]: \(data?.count ?? 0) bytes")
        output.append("[Result]: \(result.debugDescription)")
        output.append("[Timeline]: \(timeline.debugDescription)")

        return output.joined(separator: "\n")
    }
}

注意一下這兩個(gè)協(xié)議CustomStringConvertible, CustomDebugStringConvertible

DefaultDownloadResponse卓练,DownloadResponseDownloadResponse和上面講的一樣隘蝎。

Response協(xié)議

這個(gè)協(xié)議里面其實(shí)沒(méi)什么,特別點(diǎn)的就是學(xué)學(xué)協(xié)議里面怎么規(guī)定要實(shí)現(xiàn)的屬性襟企。
這里有個(gè)關(guān)鍵字mutating似乎不是很熟悉嘱么,來(lái)看看他的作用:

  • mutating:修飾方法是為了能在該方法中修改 struct 或是 enum 的變量,在設(shè)計(jì)接口的時(shí)候顽悼,也要考慮到使用者程序的擴(kuò)展性曼振。所以要多考慮使用mutating來(lái)修飾方法。如果將Response中修飾方法的mutating去掉蔚龙,編譯器會(huì)報(bào)錯(cuò)說(shuō)沒(méi)有實(shí)現(xiàn)protocol冰评。如果將struct中的mutating去掉,則會(huì)報(bào)錯(cuò)不能改變結(jié)構(gòu)體的成員木羹。
protocol Response {
    /// The task metrics containing the request / response statistics.
    var _metrics: AnyObject? { get set }
    mutating func add(_ metrics: AnyObject?)
}

通過(guò)這樣定義之后甲雅,就可以讓結(jié)構(gòu)體實(shí)現(xiàn)這個(gè)協(xié)議,然后修改結(jié)構(gòu)體里面的變量了坑填。

讓我們倆一步一步看看抛人。
通過(guò)擴(kuò)展協(xié)議,在擴(kuò)展里面判斷當(dāng)前系統(tǒng)版本環(huán)境脐瑰。代碼如下:

extension Response {
    mutating func add(_ metrics: AnyObject?) {
        #if !os(watchOS)
            guard #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) else { return }
            guard let metrics = metrics as? URLSessionTaskMetrics else { return }

            _metrics = metrics
        #endif
    }
}

在結(jié)構(gòu)體的擴(kuò)展里面實(shí)現(xiàn)協(xié)議妖枚。

@available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
extension DefaultDataResponse: Response {
#if !os(watchOS)
    /// The task metrics containing the request / response statistics.
    public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }
#endif
}

這里需要注意一下@available關(guān)鍵字。不用我講蚪黑,也知道他的作用吧盅惜。

Summary

  • 結(jié)構(gòu)體和類(lèi)的區(qū)別
  • 結(jié)構(gòu)體中剩、類(lèi)使用場(chǎng)景
  • 擴(kuò)展是個(gè)好東西,在Alamofire中抒寂,很多地方都用到結(jié)構(gòu)體里面定義數(shù)據(jù)結(jié)構(gòu)结啼,在結(jié)構(gòu)體的擴(kuò)展里面定義方法。各司其責(zé)屈芜,優(yōu)化代碼組織郊愧。非常值得學(xué)習(xí)。
  • 關(guān)鍵字mutatingavailable的作用井佑。

SessionDelegate

看名字剛開(kāi)始還以為這是一個(gè)代理属铁。結(jié)果這是一個(gè)類(lèi)。前面說(shuō)到類(lèi)一般是對(duì)功能的封裝」蹋現(xiàn)在就來(lái)看看什么是對(duì)功能的封裝焦蘑。

這個(gè)類(lèi)的作用是用閉包(也就是OC中的block)來(lái)替代系統(tǒng)中的代理回調(diào)。大致分三個(gè)部分:

  • 1.聲明替代系統(tǒng)代理回調(diào)方法的閉包
  • 2.定義需要的屬性及方法盒发。比如lock,sessionManager.
  • 3.在類(lèi)的擴(kuò)展里面實(shí)現(xiàn)系統(tǒng)代理例嘱,實(shí)現(xiàn)自定義閉包代替系統(tǒng)回調(diào)代理。

聲明替代系統(tǒng)代理回調(diào)方法的閉包

// MARK: URLSessionDelegate Overrides

    /// Overrides default behavior for URLSessionDelegate method `urlSession(_:didBecomeInvalidWithError:)`.
    open var sessionDidBecomeInvalidWithError: ((URLSession, Error?) -> Void)?

    /// Overrides default behavior for URLSessionDelegate method `urlSession(_:didReceive:completionHandler:)`.
    open var sessionDidReceiveChallenge: ((URLSession, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))?
    
    ...
    
    /// Overrides default behavior for URLSessionStreamDelegate method `urlSession(_:streamTask:didBecome:outputStream:)`.
    open var streamTaskDidBecomeInputAndOutputStreams: ((URLSession, URLSessionStreamTask, InputStream, OutputStream) -> Void)?

注意這里定的閉包在下面的擴(kuò)展里面講對(duì)系統(tǒng)的代理進(jìn)行包裝一次宁舰,然后外面通過(guò)定義的閉包使用拼卵。

這一部分能學(xué)到的差不多就是如果對(duì)閉包進(jìn)行聲明吧。順便注意下關(guān)鍵字open

定義需要的屬性及方法

這部分不算多蛮艰,關(guān)鍵是定義了一個(gè)sessionManager關(guān)于這個(gè)類(lèi)后面會(huì)說(shuō)到腋腮。有一點(diǎn)需要注意就是subscript的使用方式。這里定義了一個(gè)requests字典壤蚜。通過(guò)subscript來(lái)返回指定keyRequest即寡。注意一下用法。關(guān)鍵字defer的作用上一篇已經(jīng)提到過(guò)這里不再重復(fù)了仍律。

    var retrier: RequestRetrier?
    weak var sessionManager: SessionManager?

    private var requests: [Int: Request] = [:]
    private let lock = NSLock()

    /// Access the task delegate for the specified task in a thread-safe manner.
    open subscript(task: URLSessionTask) -> Request? {
        get {
            lock.lock() ; defer { lock.unlock() }
            return requests[task.taskIdentifier]
        }
        set {
            lock.lock() ; defer { lock.unlock() }
            requests[task.taskIdentifier] = newValue
        }
    }

在類(lèi)的擴(kuò)展里面實(shí)現(xiàn)系統(tǒng)代理

這部分比較簡(jiǎn)單嘿悬,格式就是实柠,實(shí)現(xiàn)代理水泉,在代理方法中調(diào)用定義好的閉包,傳遞參數(shù)窒盐。通過(guò)對(duì)系統(tǒng)的代理方法包裝一層草则,然后外部通過(guò)定義的閉包來(lái)調(diào)用。這樣我想到了OC中的一個(gè)牛逼的第三方BlockKit蟹漓。原理和這里有些類(lèi)似

extension SessionDelegate: URLSessionDelegate {
    /// Tells the delegate that the session has been invalidated.
    ///
    /// - parameter session: The session object that was invalidated.
    /// - parameter error:   The error that caused invalidation, or nil if the invalidation was explicit.
    open func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
         // 調(diào)用自己的閉包
        sessionDidBecomeInvalidWithError?(session, error)
    }
    
    ...
    
    open func urlSession(
        _ session: URLSession,
        streamTask: URLSessionStreamTask,
        didBecome inputStream: InputStream,
        outputStream: OutputStream)
    {
        streamTaskDidBecomeInputAndOutputStreams?(session, streamTask, inputStream, outputStream)
    }
}

SessionManager

這個(gè)類(lèi)就比較重要了炕横,算是包含了上面介紹的大部分東西。

一共分為如下幾個(gè)部分:

  • 1.調(diào)用結(jié)果枚舉定義葡粒。Helper
  • 2.屬性定義份殿。Properties
  • 3.生命周期膜钓。Lifecycle
  • 4.數(shù)據(jù)請(qǐng)求。Data Request
  • 5.下載請(qǐng)求卿嘲。Download Request
  • 6.上傳請(qǐng)求颂斜。Upload Request
  • 7.流式請(qǐng)求拾枣。Stream Request
  • 8.重試司蔬。Retry Request

有點(diǎn)多吨些,沒(méi)關(guān)系一個(gè)一個(gè)的來(lái)黔寇。

調(diào)用結(jié)果枚舉定義

這個(gè)類(lèi)似于在OC中定義成功回調(diào)和失敗回調(diào)。知識(shí)現(xiàn)在把回調(diào)放到了枚舉里面,這樣更加合理检眯。這種方式得益于case可以傳遞參數(shù)避凝。

public enum MultipartFormDataEncodingResult {
        case success(request: UploadRequest, streamingFromDisk: Bool, streamFileURL: URL?)
        case failure(Error)
    }

那后面怎么使用這種回調(diào)的方式呢。

 let encodingResult = MultipartFormDataEncodingResult.success(
                        request: self.upload(data, with: urlRequestWithContentType),
                        streamingFromDisk: false,
                        streamFileURL: nil
                    )

 DispatchQueue.main.async { encodingCompletion?(encodingResult) }

具體會(huì)在后面用到安皱。

屬性定義

這里需要弄明白有哪幾種屬性。計(jì)算屬性和存儲(chǔ)屬性缀踪,然后靜態(tài)屬性和實(shí)力屬性居砖。最開(kāi)始定義的就是所謂的靜態(tài)計(jì)算屬性。如下:

open static let `default`: SessionManager = {
        let configuration = URLSessionConfiguration.default
        configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders

        return SessionManager(configuration: configuration)
    }()

類(lèi)似的還有defaultHTTPHeaders也是這樣定義的驴娃。不僅只有屬性才能用這種形式奏候,局部變量也可以通過(guò)這種中括號(hào)方式定義。比如:

let osNameVersion: String = {
                    let version = ProcessInfo.processInfo.operatingSystemVersion
                    let versionString = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)"

                    let osName: String = {
                        #if os(iOS)
                            return "iOS"
                        #elseif os(watchOS)
                            return "watchOS"
                        #elseif os(tvOS)
                            return "tvOS"
                        #elseif os(macOS)
                            return "OS X"
                        #elseif os(Linux)
                            return "Linux"
                        #else
                            return "Unknown"
                        #endif
                    }()

屬性這部分新的知識(shí)點(diǎn)不多唇敞。個(gè)人覺(jué)得可以看看屬性的get/set方法

open var retrier: RequestRetrier? {
        get { return delegate.retrier }
        set { delegate.retrier = newValue }
    }

這種方式類(lèi)似于OC中重寫(xiě)屬性的get/set方法蔗草。最常見(jiàn)的將model改變和UI綁定在一起。

生命周期

差點(diǎn)忘了一個(gè)非常重要的知識(shí)點(diǎn)就疆柔,Swift中屬性在初始化之后必須有值咒精。這點(diǎn)和OC不一樣。所以在init方法中做了如下事情:

public init(
        configuration: URLSessionConfiguration = URLSessionConfiguration.default,
        delegate: SessionDelegate = SessionDelegate(),
        serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
    {
        self.delegate = delegate
        self.session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)

        commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
    }

關(guān)于初始方法旷档,Swift3中有init 和 init?模叙,前者代碼一定會(huì)走的,后者代表可能會(huì)走的初始化方法鞋屈。除了這兩個(gè)之外范咨,還需要注意一個(gè)deinit

  • 關(guān)于閉包的實(shí)現(xiàn):為了防止循環(huán)引用用了weak谐区。具體實(shí)現(xiàn)可以仿照下面的寫(xiě)法

    delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
            guard let strongSelf = self else { return }
            DispatchQueue.main.async { strongSelf.backgroundCompletionHandler?() }
        }
    

數(shù)據(jù)請(qǐng)求

關(guān)鍵字@discardableResult的作用湖蜕,在上一篇提到過(guò)逻卖。表示這個(gè)方法可以不用接受返回值宋列。那就是說(shuō)如果沒(méi)有這個(gè)修飾,如果方法有返回值則必須接收哦评也。??

這部分在定義方法上可以學(xué)習(xí)一下炼杖,具體的內(nèi)容就是先定義一個(gè)最為基礎(chǔ)的方法灭返,參數(shù)比較多但是一定要有默認(rèn)值,然后后續(xù)的方法在參數(shù)上做減法坤邪,最終都是調(diào)用最為基本的方法熙含。具體的例子如:

基本的方法定義

open func request(
        _ url: URLConvertible,
        method: HTTPMethod = .get,
        parameters: Parameters? = nil,
        encoding: ParameterEncoding = URLEncoding.default,
        headers: HTTPHeaders? = nil)
        -> DataRequest {
    ...        
}

省略了部分參數(shù)的方法。

 open func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
 ...
 
  let request = DataRequest(session: session, requestTask: .data(originalTask, task))
  
 ...
 }

在實(shí)際開(kāi)發(fā)中這樣的方式還是比較常用的艇纺。那具體來(lái)看看代碼中可以學(xué)到的知識(shí)點(diǎn)怎静。

  • 1.省略外部參數(shù)用_

  • 2.在方法中定義默認(rèn)參數(shù)的方式

  • 3.異常捕獲,注意這里的do catch黔衡。try放在你覺(jué)得可以會(huì)拋出異常的地方蚓聘。比如:

     do {
            let originalRequest = try urlRequest.asURLRequest()
            
           ...
           
            return request
        } catch {
            return request(failedWith: error)
        }
    
    
  • 4.方法第一的層次關(guān)系,一個(gè)基本方法參數(shù)帶有默認(rèn)值盟劫,同類(lèi)型的在此基礎(chǔ)上減少參數(shù)夜牡。

下載請(qǐng)求、上傳請(qǐng)求侣签、流式請(qǐng)求塘装。

這部分代碼和上面的數(shù)據(jù)請(qǐng)求方式及代碼組織方式一樣,所以沒(méi)必要在說(shuō)一次了影所。

重試

重試的部分比較簡(jiǎn)單蹦肴,將請(qǐng)求(request)傳進(jìn)來(lái)。然后取出任務(wù)猴娩,重新給任務(wù)傳遞所需要的參數(shù)冗尤,拼裝好之后開(kāi)始任務(wù)。具體代碼如下:

func retry(_ request: Request) -> Bool {
        guard let originalTask = request.originalTask else { return false }

        do {
            let task = try originalTask.task(session: session, adapter: adapter, queue: queue)

            request.delegate.task = task // resets all task delegate data

            request.startTime = CFAbsoluteTimeGetCurrent()
            request.endTime = nil

            task.resume()

            return true
        } catch {
            request.delegate.error = error
            return false
        }
    }

Suammary

這部分比較多胀溺,簡(jiǎn)單總結(jié)下裂七,大致可以學(xué)到如下知識(shí)點(diǎn)。

  • 1.枚舉傳遞參數(shù)仓坞,如果在代碼中調(diào)用背零。網(wǎng)絡(luò)請(qǐng)求中,以后就可以直接傳遞枚舉作為返回結(jié)果无埃,并且包含了請(qǐng)求結(jié)果
  • 2.屬性定義及相關(guān)概念徙瓶,靜態(tài)屬性,實(shí)例屬性嫉称,計(jì)算屬性侦镇,存儲(chǔ)屬性等,及快速返回值的寫(xiě)法织阅。
  • 3.初始化方法幾種形式壳繁,注意走完初始化方法之后所有屬性必須有值
  • 4.方法的參數(shù)形式,什么內(nèi)部外部參數(shù),參數(shù)默認(rèn)值闹炉。
  • 5.閉包使用方式蒿赢,如何防止循環(huán)引用。
  • 6.如何進(jìn)行異常捕獲渣触。

參考

站在OC的基礎(chǔ)上快速理解Swift的類(lèi)與結(jié)構(gòu)體

Swift靜態(tài)屬性

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末羡棵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嗅钻,更是在濱河造成了極大的恐慌皂冰,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件养篓,死亡現(xiàn)場(chǎng)離奇詭異灼擂,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)觉至,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)剔应,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人语御,你說(shuō)我怎么就攤上這事峻贮。” “怎么了应闯?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵纤控,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我碉纺,道長(zhǎng)船万,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任骨田,我火速辦了婚禮耿导,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘态贤。我一直安慰自己舱呻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布悠汽。 她就那樣靜靜地躺著箱吕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪柿冲。 梳的紋絲不亂的頭發(fā)上茬高,一...
    開(kāi)封第一講書(shū)人閱讀 49,842評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音假抄,去河邊找鬼怎栽。 笑死丽猬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的婚瓜。 我是一名探鬼主播宝鼓,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼刑棵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼巴刻!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蛉签,我...
    開(kāi)封第一講書(shū)人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤胡陪,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后碍舍,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體柠座,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年片橡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妈经。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捧书,死狀恐怖吹泡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情经瓷,我是刑警寧澤爆哑,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站舆吮,受9級(jí)特大地震影響揭朝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜色冀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一潭袱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锋恬,春花似錦敌卓、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至癣防,卻和暖如春蜗巧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蕾盯。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工幕屹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓望拖,卻偏偏與公主長(zhǎng)得像渺尘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子说敏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容