CocoaPods對(duì)三方庫的管理探究

使用pod安裝三方庫

我們新建一個(gè)不帶測(cè)試模塊的名為FFDemo的Swift項(xiàng)目胳搞,它的目錄結(jié)構(gòu)是這樣的

├── FFDemo

│?? ├── AppDelegate.swift

│?? ├── Assets.xcassets

│?? ├── Base.lproj

│?? ├── Info.plist

│?? ├── SceneDelegate.swift

│?? └── ViewController.swift

└── FFDemo.xcodeproj

? ? ├── project.pbxproj

? ? ├── project.xcworkspace

? ? └── xcuserdata


然后我們執(zhí)行pod init創(chuàng)建一個(gè)Podfile模板尖飞,在里面引入這兩個(gè)三方庫:

target 'FFDemo' do

? # Comment the next line if you don't want to use dynamic frameworks

? use_frameworks!

? # Pods for FFDemo

? pod 'MJRefresh', '~> 3.5.0'

? pod 'Moya'

end

成功執(zhí)行pod install之后我們就將這兩個(gè)庫引入到了項(xiàng)目绿贞,這時(shí)項(xiàng)目目錄變成了這樣:

├── FFDemo

│?? ├── AppDelegate.swift

│?? ├── Assets.xcassets

│?? ├── Base.lproj

│?? ├── Info.plist

│?? ├── SceneDelegate.swift

│?? └── ViewController.swift

├── FFDemo.xcodeproj

│?? ├── project.pbxproj

│?? ├── project.xcworkspace

│?? └── xcuserdata

├── FFDemo.xcworkspace

│?? └── contents.xcworkspacedata

├── Podfile

├── Podfile.lock

└── Pods

? ? ├── Alamofire

? ? ├── Headers

? ? ├── Local\ Podspecs

? ? ├── MJRefresh

? ? ├── Manifest.lock

? ? ├── Moya

? ? ├── Pods.xcodeproj

? ? └── Target\ Support\ Files

從目錄看,除了pod init引入了Podfile檀蹋,其余三部分內(nèi)容:FFDemo.xcworkspace绿饵、Podfile.lock、Pods目錄都是由pod install之后生成的忱详。我們下面重點(diǎn)講下這三部分內(nèi)容。

CocoaPods安裝的內(nèi)容

xcworkspace文件

該文件下包含一個(gè)叫contents.xcworkspacedata的文件跺涤,它的內(nèi)容是這樣的:

<?xml version="1.0" encoding="UTF-8"?>

<Workspace

? version = "1.0">

? <FileRef

? ? ? location = "group:FFDemo.xcodeproj">

? </FileRef>

? <FileRef

? ? ? location = "group:Pods/Pods.xcodeproj">

? </FileRef>

</Workspace>

使用xml格式將依賴包含在標(biāo)簽內(nèi)匈睁。

xcworkspace是一個(gè)項(xiàng)目容器,當(dāng)有多個(gè)project需要相互依賴時(shí)可以用xcworkspace將它們組織起來钦铁。pod在首次安裝三方庫時(shí)會(huì)生成一個(gè)叫Pods.xcodeproj的project管理三方庫软舌,然后將該project和主項(xiàng)目的project通過workspace進(jìn)行關(guān)聯(lián)才漆。這樣我們就可以在主工程里引入三方庫了牛曹,而且三方庫由Pods.xcodeproj統(tǒng)一管理,不會(huì)對(duì)我們?cè)?xiàng)目產(chǎn)生任何干擾醇滥。

Podfile.lock

Podfile.lock文件的內(nèi)容是這樣的:

PODS:

? - Alamofire (5.3.0)

? - MJRefresh (3.5.0)

? - Moya (14.0.0):

? ? - Moya/Core (= 14.0.0)

? - Moya/Core (14.0.0):

? ? - Alamofire (~> 5.0)

DEPENDENCIES:

? - MJRefresh (~> 3.5.0)

? - Moya

SPEC REPOS:

? trunk:

? ? - Alamofire

? ? - MJRefresh

? ? - Moya

SPEC CHECKSUMS:

? Alamofire: 2c792affbdc2f18016e08fdbcacd60aebe1ba593

? MJRefresh: 6afc955813966afb08305477dd7a0d9ad5e79a16

? Moya: 5b45dacb75adb009f97fde91c204c1e565d31916

PODFILE CHECKSUM: 073f3d6d9f03e6a76838ca3719df48ae6cc01450

COCOAPODS: 1.9.3

因?yàn)镻odfile文件里可以不指定版本號(hào)黎比,而版本信息又很重要,于是就有了Podfile.lock鸳玩,它里面記錄完整的版本信息和依賴關(guān)系阅虫。它的內(nèi)容包含以下幾大塊

PODS

PODS是指當(dāng)前引用庫的具體版本號(hào),可以發(fā)現(xiàn)我們并沒有引入Alamofire不跟,但在PODS里確有它颓帝。這是因?yàn)镸oya中依賴了它,Moya里定義了一個(gè)subspec叫Core窝革,這是Moya/Core寫法的由來购城。

DEPENDENCIES

DEPENDENCIES為pod庫的描述信息,這里內(nèi)容是同Podfile里的寫法虐译。因?yàn)槲覀冎付薓JRefresh的版本號(hào)瘪板,并沒有指定Moya的版本號(hào),所以這里內(nèi)容也是一樣的漆诽。

SPEC REPOS

這里描述的是倉庫信息侮攀,即安裝了哪些三方庫锣枝,他們來自于哪個(gè)倉庫。

trunk是共有倉庫的名稱兰英,它的地址是https://github.com/CocoaPods/Specs.git撇叁,外部使用的三方庫大都來自于這里。通常我們還會(huì)依賴一些公司內(nèi)部的私有庫畦贸,私有庫的信息也會(huì)顯示在這里菇肃。

SPEC CHECKSUM

這里描述的是各個(gè)三方庫的校驗(yàn)和,校驗(yàn)和的算法是對(duì)當(dāng)前安裝版本的三方庫的podspec文件求SHA1轧粟。比如MJRefresh的校驗(yàn)和:6afc955813966afb08305477dd7a0d9ad5e79a16不同。我們安裝的MJRefresh的版本為3.5.0,它在本地的podspec文件路徑為:~/.cocoapods/repos/trunk/Specs/0/f/b/MJRefresh/3.5.0/MJRefresh.podspec.json颤殴。

這個(gè)路徑可以通過在安裝庫時(shí)增加--verbose參數(shù)在輸出日志里查看觅廓。我們對(duì)該文件內(nèi)容通過openssl求sha1摘要:

$ pod ipc spec ~/.cocoapods/repos/trunk/Specs/0/f/b/MJRefresh/3.5.0/MJRefresh.podspec.json | openssl sha1

$ 6afc955813966afb08305477dd7a0d9ad5e79a16

因?yàn)槭菍?duì)podspec.json內(nèi)容求sha1,所以只要內(nèi)容發(fā)生一點(diǎn)變化涵但,得出的校驗(yàn)和就將大不相同杈绸,而這也是校驗(yàn)和設(shè)計(jì)的目的:podspec文件發(fā)生變化意味著版本信息發(fā)生了變化,就需要重新同步代碼矮瘟。

大家可能注意到了瞳脓,我們通常制作私有pod,控制配置信息的文件是podspec格式的澈侠,為什么本地文件變成了json格式劫侧?

這是因?yàn)閖son格式兼容性更高也更容易批量處理,官方Spec倉庫的所有庫配置文件都是被轉(zhuǎn)成json格式的哨啃。在我們制作私有庫的時(shí)候是可以直接以podspec的格式推到遠(yuǎn)程倉庫的烧栋,但后續(xù)解析文件時(shí)pod內(nèi)部檢索還是會(huì)把它轉(zhuǎn)成json格式。上面的命令是包含了podsepc轉(zhuǎn)json的命令的拳球,轉(zhuǎn)json命令如下:

$ pod ipc spec ModuleName.podspec

PODFILE CHECKSUM

這個(gè)校驗(yàn)和是針對(duì)Podfile內(nèi)容的校驗(yàn)和审姓,如果Podfile內(nèi)容改變了,該值也會(huì)跟著改變祝峻。計(jì)算方法為:

$ openssl sha1 filePath/Podfile復(fù)制代碼

COCOAPODS: 1.9.3

這個(gè)代表當(dāng)前使用的CocoaPod版本號(hào)魔吐,遠(yuǎn)程版本管理應(yīng)該要保證大家使用的pod版本號(hào)一致。

Pods

Manifest.lock

Manifest.lock是Podfile.lock的副本莱找,它是在Pods目錄里面酬姆。它的作用是這樣的,我們通常是不把Pods文件放到版本管理里面宋距,而把Podfile.lock放到版本管理里面轴踱。這時(shí)對(duì)于拉取代碼之后是否需要更新pod,就可以通過對(duì)比本地的Manifest.lock和遠(yuǎn)程Podfile.lock是否相同即可谚赎。

一個(gè)Pods的Project下面有三個(gè)Targets淫僻,其中三個(gè)是安裝的依賴庫诱篷,最后一個(gè)Pods-FFDemo是關(guān)聯(lián)三個(gè)庫的Framework,也即是Pods這個(gè)Project的Targets雳灵。

Pods-Demo Framework

先看這個(gè)Demo的Framework棕所,它會(huì)被用于工程項(xiàng)目的引用依賴

這個(gè)庫不會(huì)被打進(jìn)包里,因?yàn)镈o Not Embed代表并不是包含的關(guān)系悯辙。

許可協(xié)議文件?兩個(gè)以acknowledgements命名的文件是用于管理pod庫的許可協(xié)議琳省,即三方庫必須帶有的LICENSE文件,這也是為什么我們?cè)谥谱鱬od時(shí)會(huì)要求我們指定軟件協(xié)議躲撰。

Framework文件?這里還包含了用于管理Module的modulemap和umbrella.h文件针贬。modulemap是對(duì)Module的聲明文件,制作Framework我們總是需要該文件拢蛋,它的內(nèi)容如下:

framework module Pods_FFDemo {

? umbrella header "Pods-FFDemo-umbrella.h"

? export *

? module * { export * }

}復(fù)制代碼

其指向了一個(gè)umbrella的頭文件桦他,這是制作Framework必須的頭文件,modulemap和umbrella.h會(huì)在創(chuàng)建Module時(shí)自動(dòng)生成谆棱,不建議手動(dòng)修改其關(guān)系快压。

dummy.m文件

這其實(shí)是一個(gè)空的.m文件

#import <Foundation/Foundation.h>

@interface PodsDummy_Pods_FFDemo : NSObject

@end

@implementation PodsDummy_Pods_FFDemo

@end復(fù)制代碼

那為什么要有這個(gè)東西呢,包括所有的三方庫的包里也會(huì)包含一個(gè)dummy文件垃瞧。我在stackoverflow找到了一個(gè)解釋:Xcode的編譯是依賴.m文件的蔫劣,如果一個(gè)庫里沒有.m文件,將不會(huì)被編譯个从,為了防止這種情況就會(huì)在每個(gè)庫里增加一個(gè)空的.m文件脉幢。

xcconfig文件

xcconfig文件是Build Setting配置項(xiàng)的文件形式,它的優(yōu)先級(jí)大于Xcode內(nèi)的Build Setting信姓⊥宜恚看一個(gè)pod生成的debug模式下的xcconfig文件。

ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES

FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/Moya"

GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1

HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Moya/Moya.framework/Headers"

LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'

OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "CFNetwork" -framework "Foundation" -framework "MJRefresh" -framework "Moya"

OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS

PODS_BUILD_DIR = ${BUILD_DIR}

PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

PODS_PODFILE_DIR_PATH = ${SRCROOT}/.

PODS_ROOT = ${SRCROOT}/Pods

USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES復(fù)制代碼

xcconfig還有個(gè)作用是設(shè)置參數(shù)意推,比如我們比較熟悉的PODS_ROOT=${SRCROOT}/PODS,它代表項(xiàng)目根目錄下的PODS文件目錄珊蟀。另外兩項(xiàng)用于幫助我們?cè)陧?xiàng)目中查找三方庫的FRAMEWORK_SEARCH_PATHS和HEADER_SEARCH_PATHS也是在改文件內(nèi)部定義的菊值,這些配置會(huì)體現(xiàn)到Build Settings里面

各個(gè)三方庫也都有一些配置文件,他們文件格式基本一致育灸,上圖是Moya的配置文件腻窒。Moya的xcconfig文件里有一行這個(gè):

FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire"復(fù)制代碼

用于告訴Moya在引用Alamofire時(shí)應(yīng)該去哪里找這個(gè)依賴。

這里是設(shè)置編譯階段配置的地方磅崭,當(dāng)首次pod install成功之后儿子,這里會(huì)多幾個(gè)[CP]開頭的配置項(xiàng)(CP即CocoaPods縮寫),它們都是由CocoPods添加的腳本內(nèi)容砸喻,執(zhí)行順序從上到下柔逼。

New System Build

在講編譯腳本之前簡單說下New Build System蒋譬。

New Build System是Xcode10之后蘋果推出的新的構(gòu)建系統(tǒng),新的構(gòu)建系統(tǒng)對(duì)編譯流程的優(yōu)化做了很多工作愉适,雖然到Xcode12仍兼容舊版的Legacy Build System犯助,但其已經(jīng)被標(biāo)記為移除,我們的項(xiàng)目和庫都應(yīng)該使用新版的構(gòu)建系統(tǒng)進(jìn)行構(gòu)建维咸。和新的構(gòu)建系統(tǒng)隨之而來的是在運(yùn)行腳本時(shí)增加的輸入輸出列表剂买。

這是為了控制是否每次編譯都需要執(zhí)行對(duì)應(yīng)腳本,input和output文件可以是單個(gè)文件形式癌蓖,如果文件過多可以放到格式為xcfilelist的文件列表里瞬哼。

如果沒有提供input和output,則每次構(gòu)建都會(huì)運(yùn)行該腳本租副。如果提供了倒槐,則會(huì)在以前從未運(yùn)行過、某個(gè)輸入文件被更改或某個(gè)輸出文件丟失的情況下再次運(yùn)行附井。

注意這些是構(gòu)建腳本的默認(rèn)邏輯讨越,Xcode還提供了Run Scripts的自定義行為,默認(rèn)勾選項(xiàng):Based on dependency analysis永毅,即代表上述邏輯把跨。如果提供了輸入輸出還需要每次運(yùn)行,關(guān)閉該選項(xiàng)即可沼死。

[CP] Check Pods Manifest.lock

該腳本位于較上方着逐,如果沒有Dependencies,開始編譯就會(huì)執(zhí)行該腳本意蛀,它的內(nèi)容如下:

diff "${PODS_PODFILE_DIR_PATH}/Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null

if [ $? != 0 ] ; then

? ? # print error to STDERR

? ? echo "error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation." >&2

? ? exit 1

fi

# This output is used by Xcode 'outputs' to avoid re-running this script phase.

echo "SUCCESS" > "${SCRIPT_OUTPUT_FILE_0}"復(fù)制代碼

作用是比較Podfile.lock和Manifest.lock文件是否相同耸别,如果不同就輸出錯(cuò)誤信息:error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.,并執(zhí)行退出县钥,這會(huì)導(dǎo)致后續(xù)項(xiàng)目報(bào)錯(cuò)秀姐,無法繼續(xù)編譯。

該錯(cuò)誤較常見若贮,出現(xiàn)于拉取遠(yuǎn)端代碼省有,遠(yuǎn)端pod依賴于本地不一致的情況。這時(shí)我們可以根據(jù)提示谴麦,執(zhí)行pod install命令蠢沿,根據(jù)Podfile及遠(yuǎn)端Podfile.lock生成新的Manifest.lock文件。

[CP] Copy Pods Resources

這個(gè)一般在以靜態(tài)庫引入的三方庫切里面包含資源的話會(huì)添加該腳本匾效,其作用是將三方庫的資源文件拷貝至項(xiàng)目中舷蟀。

它的完成是通過運(yùn)行以下腳本進(jìn)行的:

"${PODS_ROOT}/Target Support Files/Pods-FFDemo/Pods-FFDemo-resources.sh"復(fù)制代碼

Pods-FFDemo-resources.sh文件在Pods目錄內(nèi),該腳本內(nèi)有個(gè)關(guān)鍵函數(shù)install_resource:

install_resource()

{

? if [[ "$1" = /* ]] ; then

? ? RESOURCE_PATH="$1"

? else

? ? RESOURCE_PATH="${PODS_ROOT}/$1"

? fi

? if [[ ! -e "$RESOURCE_PATH" ]] ; then

? ? cat << EOM

error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.

EOM

? ? exit 1

? fi

? case $RESOURCE_PATH in

? ? *.storyboard)

? ? ? ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}

? ? ? ;;

? ? *.xib)

? ? ? ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}

? ? ? ;;

? ? *.framework)

? ? ? echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true

? ? ? mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"

? ? ? echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true

? ? ? rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"

? ? ? ;;

? ? *.xcassets)

? ? ? ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"

? ? ? XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")

? ? ? ;;

? ? *)

? ? ? echo "$RESOURCE_PATH" || true

? ? ? echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"

? ? ? ;;

? esac

}復(fù)制代碼

刪除了一部分日志內(nèi)容,其內(nèi)部主要是一個(gè)switch語句野宜,根據(jù)資源文件的類型進(jìn)行不同的同步操作扫步。這里重點(diǎn)說下幾種重要格式文件的處理方式。

storyboard和xib格式

這兩項(xiàng)資源文件是需要編譯處理的速缨,利用ibtool命令分別轉(zhuǎn)成sotryboardc和nib格式锌妻。

xcassets格式

這里的圖片最終會(huì)被打包到Assets.car供程序使用,需要使用actool旬牲。

Bundle仿粹、plist、png等資源

其他類的資源是會(huì)走到switch語句最后出口原茅,進(jìn)行資源路徑賦值給$RESOURCES_TO_COPY吭历,在后面的代碼中通過rsync命令,將資源同步到構(gòu)建包的目錄擂橘。

該腳本會(huì)打印很多日志晌区,在使用CocoaPods時(shí)如果遇到資源相關(guān)的問題都可以遵循錯(cuò)誤日志來這里推測(cè)定位錯(cuò)誤原因。

[CP] Embed Pods Frameworks

該處腳本是直接運(yùn)行Pods-FFDemo-frameworks.sh通贞。

"${PODS_ROOT}/Target Support Files/Pods-FFDemo/Pods-FFDemo-frameworks.sh"復(fù)制代碼

可能你還記得上面說的pod會(huì)把多個(gè)庫的依賴做成一個(gè)合并的庫朗若,但該庫是以依賴的形式引入主工程,但是程序的運(yùn)行時(shí)需要這些庫昌罩,我們打包時(shí)就需要將各個(gè)庫Embed到項(xiàng)目里哭懈,而做這個(gè)工作的就是該腳本。

# Copies and strips a vendored framework

install_framework()

{

? rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"

? # other code...

? # Strip invalid architectures so "fat" simulator / device frameworks work on device

? if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then

? ? strip_invalid_archs "$binary"

? fi

? # Resign the code if required by the build settings to avoid unstable apps

? code_sign_if_enabled "${destination}/$(basename "$1")"

}復(fù)制代碼

腳本內(nèi)容主要是調(diào)用install_framework函數(shù)茎用,將framework內(nèi)容同步到構(gòu)建包里遣总。在該函數(shù)里還有幾個(gè)關(guān)鍵方法,strip_invalid_archs用于去除無用架構(gòu)轨功,code_sign_if_enabled用于framwork簽名旭斥。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市古涧,隨后出現(xiàn)的幾起案子垂券,更是在濱河造成了極大的恐慌,老刑警劉巖蒿褂,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件圆米,死亡現(xiàn)場離奇詭異,居然都是意外死亡啄栓,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門也祠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昙楚,“玉大人,你說我怎么就攤上這事诈嘿】熬桑” “怎么了削葱?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長淳梦。 經(jīng)常有香客問我析砸,道長,這世上最難降的妖魔是什么爆袍? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任首繁,我火速辦了婚禮,結(jié)果婚禮上陨囊,老公的妹妹穿的比我還像新娘弦疮。我一直安慰自己,他們只是感情好蜘醋,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布胁塞。 她就那樣靜靜地躺著,像睡著了一般压语。 火紅的嫁衣襯著肌膚如雪啸罢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天胎食,我揣著相機(jī)與錄音扰才,去河邊找鬼。 笑死斥季,一個(gè)胖子當(dāng)著我的面吹牛训桶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播酣倾,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼舵揭,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了躁锡?” 一聲冷哼從身側(cè)響起午绳,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎映之,沒想到半個(gè)月后拦焚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡杠输,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年赎败,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蠢甲。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡僵刮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情搞糕,我是刑警寧澤勇吊,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站窍仰,受9級(jí)特大地震影響汉规,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜驹吮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一针史、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧钥屈,春花似錦悟民、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至竭业,卻和暖如春智润,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背未辆。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工窟绷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人咐柜。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓兼蜈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拙友。 傳聞我的和親對(duì)象是個(gè)殘疾皇子为狸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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

  • 原文地址 前言一般可以將編程語言分為兩種,編譯語言和直譯式語言遗契。像C++,Objective C都是編譯語言辐棒。編譯...
    一片楓葉隨風(fēng)舞閱讀 352評(píng)論 0 0
  • 本文主要采取二進(jìn)制方式部署k8s集群,二進(jìn)制部署可以幫助我們了解其組件間的調(diào)用關(guān)系牍蜂,也利于我們后期維護(hù) 主機(jī)環(huán)境 ...
    孫峰_f21d閱讀 438評(píng)論 0 0
  • [更新日志][1] [1]: https://blog.growingio.com/posts/iOS_chan...
    bmm_yj閱讀 679評(píng)論 0 0
  • iOS CocoaPods組件平滑二進(jìn)制化解決方案 曹俊_413f關(guān)注 2.62017.05.19 11:19*字...
    小小小Lucky閱讀 648評(píng)論 0 1
  • 久違的晴天漾根,家長會(huì)。 家長大會(huì)開好到教室時(shí)鲫竞,離放學(xué)已經(jīng)沒多少時(shí)間了辐怕。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,493評(píng)論 16 22