《Swift进阶》王巍译——内建集合类型

看了下自己的文章记录,距离上次文章已经快两个月,距第一篇文章已经有快5个月了。本以为自己有了写技术文章的这个好习惯,没想到还是因为某些因素没能坚持,比如带项目 =。= ...



本来的开发组长当的好好的,抓壮丁让我去带项目,还没产品经理。我一个人又要出原型,想交互,还要管理团队,真的是mmp哟。幸亏UI说你直接草图给我就好,幸亏Axure简单功能不难,幸亏storyboard和设计工具一样都能出图。要不是想着带项目能让我成长,我才不干咧!

前言说完了,因为项目需要,面试了好多个iOS,发现自身有些不足,并且非科班出身所以基础知识也(ji)不(hu)牢(mei)固(you)。然后网上找了下swift进阶的书,看到了《Swift进阶》这本书,喵神翻译的,而且今年5月才发售,价值连城啊,立马上某东买去。顺便下载了一个《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法》.pdf

项目二期结束了,我决定开始我的Swift进阶之旅。顺便做个记录,监督自己
每次的记录我都会写一些书里的重点内容和相关的文章。

2017.07.31

结构体和枚举是值类型,引用是一种特殊类型的值,==有时候被称为结构相等,而===则被称为指针相等或者引用相等。

Swift3.0 - 类和结构体的区别
Swift 中的枚举,你应该了解的东西

2017.08.01

什么? 朕的大清亡了???



公司解散你敢信?其他部门遭遇严重生产事故,公司整体解散,只留骨干整体进入其他技术公司。我的天,第一次遭遇公司解散,简直就是



无心撸代码,玩炉石去了。

2017.08.02


生活还是要继续啊,很开心我又开始做开发了,项目还是要继续的。只不过不用我带,也不用我想需求了(这一点我还是很开心的)。虽然带项目才两个月的时间,虽然这种短暂的经历不一定会对技能树有(mei)影(bian)响(hua),但是也算一个经历咯。

引用是一种特殊类型的值:它是一个“指向”另一个值的值。对于一个类的实例,我们只能在变量里持有对它的引用,然后使用这个引用来访问它。

class Person {
    
    var name:String!
    
    init(name:String){
        self.name = name
    }
    
}

let person1 = Person.init(name: "Bart")
person1.name
let person2 = Person.init(name: "Lisa")
person2.name

playground截图

代码里person1和person2指向同一个地址,而.name的内容却是不一样的。

两个引用可能会指向同一个值,这引入了一种可能性,那就是这个值可能会被程序的两个不同的部分所改变。

Swift 风格指南

https://swift.org/documentation/api-design-guidelines/
对于代码编写原则,我将简单明了,并且常用的原则整理出来。

  • 务必为函数添加文档注释——特别是泛型函数
  • 类型使用大写字母开头,函数,变量和枚举成员使用小写字母开头,两者都使用驼峰式命名法。
  • 优先选择结构体,只在确实需要使用到类特有的特性或者是引用语义时才使用类。
  • 除非你的设计就是希望某个类被继承使用,否则都应该将它们标记为final。
  • 使用guard来提早退出的方法。
  • 不要写重复的代码。如果你发现你写了好几次类似的代码片段,那么试着将它们提取到一个函数里,并且考虑将这个函数转化为协议扩展的可能性。

内建集合类型

数组

数组是一系列相同类型的元素的有序的容器

var x = [1,2,3]
var y = x
y.append(4)
x
//x不会发生改变

//不想让b发生改变,但是任然被a影响
let a = NSMutableArray.init(array: [1, 2, 3])
let b:NSArray = a
a.insert(4, at: 3)  //[1, 2, 3, 4]
b  //[1, 2, 3, 4]

//不想让d发生改变, 正确方法
let c = NSMutableArray.init(array: [1, 2, 3])
let d = c.copy() as! NSArray
c.insert(4, at: 3)  //[1, 2, 3, 4]
d  //[1, 2, 3]
playground截图

Swift标准库中的所有集合类型都使用了“写时复制”这一技术,它能够保证只在必要的时候对数据进行复制。在我们的例子中,直到y.append被调用之前,x和y都将共享内部的存储。

2017.08.03

数组变形

一些数组的方法

mutabFibs  //[0, 1, 1, 2, 3, 5, 8, 13, 21]
var new = [Int]()
//去掉数组首个元素
for value in mutabFibs.dropFirst(){
    
    new.append(value)
    
}
new  //[1, 1, 2, 3, 5, 8, 13, 21]

var new1 = [Int]()
//去掉数组后6个元素
for value in mutabFibs.dropLast(6){
    new1.append(value)
}
new1  //[0, 1, 1]


var new2 = [Int]()
// 如果越界new2会是空数组
for value in mutabFibs.dropLast(10){
    new2.append(value)
}
new2

//遍历元素和对应的下标
for (index, value) in mutabFibs.enumerated(){
    
    print("index:\(index)  value:\(value)")
    
}

playground截图

数组的map方法

let math = [2,4,6,8]
var squared:[Int] = []
//把数组中的数字平方
for value in math{
    squared.append(value * value)
}
squared  //[4, 16, 36, 64]

let squared1 = math.map({num in num * num}) //不知道为什么会循环5次
squared1  //[4, 16, 36, 64]
//new.map({})

extension Array{
    
    func map<T>(_ transform: (Element)  -> T) -> [T] {
        var result: [T] = []
        result.reserveCapacity(count)
        for x in self{
            
            result.append(transform(x)) 
            
        }
        return result
    }
}

//删选出数组里大于10的元素
let filter = mutabFibs.filter { $0 > 10 }
filter  //[13, 21]

//删选出数组里大于3的元素
let test = math.filter { (tt) -> Bool in
    
   return tt > 3
    
}
test  //[4, 6, 8]

playground截图

上面关于Array的扩展是map函数可能的一种实现方式

Element是数组中包含的元素类型占位符,T是元素转换之后的类型的占位符。

关于.filter,我的理解就是对于你的需要,返回true就保留这个元素,返回false就弃掉这个元素

let names = ["Paula", "Elena", "Zoe"]

var lastNameEndingInA: String?
//反向遍历出名字中带有a的最早的元素(找出就终止循环)
for name in names.reversed() where name.hasSuffix("a") {
    lastNameEndingInA = name
    break
}
lastNameEndingInA // Optional("Elena")

//反向遍历  .reversed()
for na in names.reversed(){
    if na.hasSuffix("a"){
        print(na)   //Elena
                    //Paula
    }
}

extension Sequence{
    
    func last(where predicate: (Iterator.Element) -> Bool) -> Iterator.Element? {
        
        for element in reversed() where predicate(element){
            return element
        }
        return nil
    }
    
}

let match = names.last(where: { $0.hasSuffix("a") })
match

playground截图

哎,今天就到这儿了。大神的高阶函数写法是真的高,小弟受教了啊!


2017.08.04

可变和带有状态的闭包
extension Array {
    
    func accumulate<Result>(_ initialResult: Result,_ nextPartial:(Result, Element) -> Result) -> [Result]{
        
        var running = initialResult
        return map({ (next) -> Result in
            print("before:\(running)")
            print("next:\(next)")
            running = nextPartial(running, next)
            print("after running:\(running)")
            return running
        })
        
        
    }
}

var numArray = [5,16,23,44]
let acc = numArray.accumulate(3, +)
acc  //[8, 24, 47, 91]


let error = numArray.accumulate(3) { (count, num) -> Int in
    return count * num
}
error  //[15, 240, 5520, 242880]



var char = ["boy", "girl", "children"]
let ttt = char.accumulate("bad",  +)
ttt  //["badboy", "badboygirl", "badboygirlchildren"]

let errorStr = char.accumulate("god") { (first, str) -> String in
    return  "\(first) \(str)"
}
errorStr  //["god boy", "god boy girl", "god boy girl children"]

extension String{
    
    func addtest<T>(objc:(String, Int) -> T) -> T{
        
        let tt = objc(self, 4)
        return tt
        
    }
    
}

var four = "four is "
let ff = four.addtest { (str, num) -> String in
    return str + "\(num)"
}
ff

我昨天就开始试图读懂这个了,就是不明白!!尤其是我回车让方法自动展开,完全不知道方法nextPartial:(Result, Element) -> Result是怎么可以放+号的。running = nextPartial(running, next) 更不用说这里为什么会自动根据传过来的符号就开始运算了。let acc = numArray.accumulate(3, +) 这个加号看得我这种初级程序员一脸懵逼,传递(Result,Element)类型并得到Result类型的返回值的函数是怎么简写成+就结束了,+号怎么传递过去让程序知道你想进行相加操作的呢? 我扩展开是需要自己在返回值的时候去定义加减乘除让程序知道的。

哎,最后拓展了个方法试图让自己明白这个+号,发现还是不知道如何简写成那样。望看到的大指点指点我。

filter会创建一个全新的数组

var filterArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let fl = filterArray.filter({ $0 % 2 == 0})
fl  //[2, 4, 6, 8, 10]

let f2 = filterArray.filter { (num) -> Bool in
    return num % 2 == 0
}
f2  //[2, 4, 6, 8, 10]


let sq = (1..<10).map { $0 * $0 }.filter { (num) -> Bool in
    return num % 6 == 0
}
sq  //[2, 4, 6, 8, 10]


extension Array {
    func filter(_ isIncluded: (Element) -> Bool) -> [Element] {
        var result: [Element] = []
        
        for x in self where isIncluded(x) {
            print("==\(x)==")
            print(isIncluded(x))
            result.append(x)
        }
        return result
    }
}

let fibs = [1, 2, 3, 4, 5]
//Reduc
var total = 0
for num in fibs {
    total = total + num
}
total  //15

let sum = fibs.reduce(0, {total, num in total + num})
sum  //15

//我现在理解是消消乐,相同的参数抵消,留下了运算符
let sum1 = fibs.reduce(0, +)
sum1  //15

let sum2 = fibs.reduce(0) { (total, num) -> Int in
    return total + num
}
sum2  //15

//reduc实现
extension Array {
    
    func reduce<Result>(_ initialResult: Result,
                _ nextPartialResult: (Result, Element) -> Result) -> Result
    {
        var result = initialResult
        for x in self {
            result = nextPartialResult(result, x)
        }
        return result
    }
    
}
playground截图

后面看到flatMap举得例子有点绕,待我看懂分析好了再与诸君分享。
看书真的是枯燥啊,共勉之!

2017.08.05

flatMap

有时候我们会想要对一个数组用一个函数进行map,但是这个变形函数返回的是另一个数组,而不是单独的元素。

//内部实现
extension Array {
    func flatMap<T>(_ transform: (Element) -> [T]) -> [T] {
        var result: [T] = []
        for x in self {
            print("objc:\(x)")
            result.append(contentsOf: transform(x))
            print("result:\(result)")
        }
        return result
    }
}

let suits = ["♠", "❤", "♣", "♦"]

let ranks = ["J","Q","K","A"]


let result = suits.flatMap { suit in
    ranks.map { rank in
        (suit, rank)
    }
}
result  //[("♠", "J"), ("♠", "Q"), ("♠", "K"), ("♠", "A"), ("❤", "J"), ("❤", "Q"), ("❤", "K"), ("❤", "A"), ("♣", "J"), ("♣", "Q"), ("♣", "K"), ("♣", "A"), ("♦", "J"), ("♦", "Q"), ("♦", "K"), ("♦", "A")]

//flatMap示例
let test = ranks.flatMap { (str) -> [String] in
    
    return ["test", str]
    
}
test  //["test", "J", "test", "Q", "test", "K", "test", "A"]

//拆解出ranks.map
let test1 = ranks.map { (rank) -> (String, String) in
    return ("test", rank)
}
test1  //[(.0 "test", .1 "J"), (.0 "test", .1 "Q"), (.0 "test", .1 "K"), (.0 "test", .1 "A")]

//组合, 省调返回值声明和return可以由系统自动判断,简化了很多。
let result2 = suits.flatMap { (hua) -> [(String, String)] in
    
    return ranks.map({ (char) -> (String, String) in
        return (hua, char)
    })
}
result2  //[("♠", "J"), ("♠", "Q"), ("♠", "K"), ("♠", "A"), ("❤", "J"), ("❤", "Q"), ("❤", "K"), ("❤", "A"), ("♣", "J"), ("♣", "Q"), ("♣", "K"), ("♣", "A"), ("♦", "J"), ("♦", "Q"), ("♦", "K"), ("♦", "A")]

结果很长,我也有注释在代码里,就不上截图了。

使用forEach进行迭代

var numbers = [1, 2, 3, 4]
for value in numbers{
    print(value)
}

numbers.forEach { (value) in
    print("forEach: \(value)")
}

for循环和forEach在某些情况能达到同样的效果,而且forEach代码更简洁。不过

for 循环和 forEach 有些细微的不同,值得我们注意。比如,当一个 for 循环中有 return 语句时,将它重写为 forEach 会造成代码行为上的极大区别。

再思考一下下面这个简单的例子:

(1..<10).forEach { number in
    print(number)
    if number > 2 { return }
}

你可能一开始还没反应过来,其实这段代码将会把输入的数字全部打印出来。return 语句并不会终止循环,它做的仅仅是从闭包中返回。

书里有个更复杂的例子的对比,我没整理,到是觉得里面这个方法可以仔细研究一下

numbers.indices  //CountableRange(0..<4)
extension Array where Element: Equatable {
    func index(of element: Element) -> Int? {
        print(element)
        for idx in self.indices where self[idx] == element {
            return idx
        }
        return nil
    }
}

numbers.index(of: 3)  //2 下标2
numbers.index(of: 4)  //3 下标3
numbers.index(of: 5)  //nil  找不到这个数字的下标

var strs = ["一","二","三"]
strs.index(of: "三")  //2  下标2
strs.index(of: "四")  //nil  找不到这个字符串的下标

题外话:看到跌代,突然就想了解下这个名词,然后看到递归和迭代,然后看到一个好的例子

//迭代实现斐波那契数列
func fab_iteration(index:Int) -> Int{

    guard index > 0 else {
        return 0
    }
    if index == 1 || index == 2 {
        return 1
    }else{
        
        var f1 = 1
        var f2 = 1
        var f3 = 0
        for num in 0..<index - 2 {
            
            f3 = f1 + f2
            f1 = f2
            f2 = f3
            
        }
        return f3
        
    }
    
}
fab_iteration(index: 0)
fab_iteration(index: 1)
fab_iteration(index: 2)
fab_iteration(index: 3)
fab_iteration(index: 4)
fab_iteration(index: 11)
fab_iteration(index: 12)
fab_iteration(index: 13)


//递归实现斐波那契数列
func fab_recursion(index:Int) -> Int{
    
    guard index > 0 else {
        return 0
    }
    if index == 1 || index == 2{
        return 1
    }else{
        
        return fab_recursion(index: index - 1) + fab_recursion(index: index - 2) //递归求值,自己调用自己
        
    }
}
fab_recursion(index: 0)
fab_recursion(index: 1)
fab_recursion(index: 2)
fab_recursion(index: 3)
fab_recursion(index: 4)
fab_recursion(index: 11)
fab_recursion(index: 12)
fab_recursion(index: 13)

看起来递归更简洁了,但是我上截图你们就知道区别了。

playground截图

迭代运行了33次,递归466次,这个就相差太多了,也就是递归吃了你超级多的内存。
总结就是:能自己内部实现,麻烦一点也要用迭代。实在无法自己内部实现才用递归。

数组类型

切片

var fibs = [0, 1, 1, 2, 3, 5, 8]
type(of: fibs)  //Array<Int>.Type
let slice = fibs[1..<fibs.endIndex]
slice  //[1, 1, 2, 3, 5, 8]
type(of: slice)  //ArraySlice<Int>.Type   返回数组的一个切片(slice)

切片类型只是数组的一种表示方式,它背后的数据仍然是原来的数组

也就是相对于原数组,它只不过是从第一个数据开始展示,本质上任然是之前的数组

image.png

如果要转换为数组,就需要构建成数组

//构成数组
let slicceArray = Array(fibs[1..<fibs.endIndex])
type(of: slicceArray)  //Array<Int>.Type

2017.08.07

字典

在一个字典中,每个键都只能出现一次。通过键来获取值所花费的平均时间是常数量级的 (作为对比,在数组中搜寻一个特定元素所花的时间将与数组尺寸成正比)。和数组有所不同,字典是无序的,使用 for 循环来枚举字典中的键值对时,顺序是不确定的。

enum Setting {
    
    case text(String)
    case int(Int)
    case bool(Bool)
    
}

let defaultSettings: [String:Setting] = ["Airplane Mode": Setting.bool(true), "Name": Setting.text("My iPhone"), "PhoneNumber":Setting.int(110)]

defaultSettings["Name"]  //text("My iPhone")
defaultSettings["test"]  //nil

var defaultSettings2 = defaultSettings
defaultSettings2.removeValue(forKey: "Name")  //text("My iPhone") 返回了被删除的值
defaultSettings2["Name"]  //text("My iPhone")

defaultSettings2.updateValue(Setting.int(12110), forKey: "PhoneNumber")  //int(110)  返回了更新前的值
defaultSettings2["PhoneNumber"] //int(12110)

defaultSettings2.updateValue(.text("new"), forKey: "new value")  //nil 如果之前没值则返回nil
defaultSettings2["new value"]  //text("new") 新的值

有用的字典扩展

//合并两个字典,通过循环添加内容
extension Dictionary {
        mutating func merge<S>(_ other: S) where S: Sequence, S.Iterator.Element == (key: Key, value: Value) {
                for (k, v) in other {
                    self[k] = v
                }
        }
}

defaultSettings2.merge(["1":.text("111")])

var set = ["a":"1","b":"2"]
set.merge(["c":"3", "d":"4"])

//从序列创建数组的方法
extension Dictionary {
    
    init<S:Sequence>(_ sequence: S) where S.Iterator.Element == (key: Key, value: Value){
        self = [:]
        self.merge(sequence)
    }
    
}

let se = Dictionary(set)
se
type(of: se)


//字典的map方法,会返回数组
let seMap = se.map { (key: String, value: String) -> (String, String) in
    
    if key == "a"{
        
        return ("is a :" + key, "is 1 :" + value)
    }else{
        return (key + "lala", value + "map")
    }
    
}
//字典调用map放回会返回数组
type(of: seMap)  //Array<(String, String)>.Type


//返回字典的自定义map函数
extension Dictionary {
    func mapValues<NewValue>(transform: (Value) -> NewValue)
        -> [Key:NewValue] {
            return Dictionary<Key, NewValue>(map { (key, value) in
                print("key:\(key)   value:\(transform(value))")
                return (key, transform(value))
            })
    }
}

let settingsAsStrings = defaultSettings2.mapValues { setting -> String in
    switch setting {
    case .text(let text):
        return text
    case .int(let number):
        return String(number)
    case .bool(let value):
        return String(value)
    }
}
settingsAsStrings  //["PhoneNumber": "12110", "new value": "new", "Airplane Mode": "true", "1": "111"]

//简单示例
let mama = se.mapValues { (str) -> String in
    return str + " mapValues"
}
mama  //["b": "2 mapValues", "a": "1 mapValues", "d": "4 mapValues", "c": "3 mapValues"]

代码注释很详细,而且有之前的数组方法做铺垫,理解起来容易多了。

2017.08.08

Set

集合是一组无序的元素,每个元素只会出现一次。

//集合
let naturals: Set = [1, 2, 3, 2]
naturals  //[2,3,1]
naturals.contains(3)  //true
naturals.contains(2)  //true
naturals.contains(4)  //false

集合代数

//一个集合中求另一个集合的补集:
let iPods: Set = ["iPod touch", "iPod nano", "iPod mini","iPod shuffle", "iPod Classic"]
let discontinuedIPods: Set = ["iPod mini", "iPod Classic"]
let currentIPods = iPods.subtracting(discontinuedIPods)
currentIPods  // ["iPod shuffle", "iPod nano", "iPod touch"]

//求两个集合的交集
let touchscreen: Set = ["iPhone", "iPad", "iPod touch", "iPod nano"]
let iPodsWithTouch = iPods.intersection(touchscreen)
iPodsWithTouch  // ["iPod touch", "iPod nano"]

//求两个集合的并集
var discontinued: Set = ["iBook", "Powerbook", "Power Mac"]
discontinued.formUnion(discontinuedIPods)
discontinued  // ["iBook", "iPod mini", "Powerbook", "Power Mac", "iPod Classic"]

索引集合

var indices = IndexSet()
indices.insert(integersIn: 1..<5)
indices.insert(integersIn: 11..<15)
let indicesNumber = indices.filter{ $0 % 1 == 0 }
indicesNumber  //[1, 2, 3, 4, 11, 12, 13, 14]
let evenIndices = indices.filter { $0 % 2 == 0 }
evenIndices  // [2, 4, 12, 14]

闭包使用集合

extension Sequence where Iterator.Element: Hashable{
    
    func unique() -> [Iterator.Element]{
        var seen: Set<Iterator.Element> = []
        return filter {
            if seen.contains($0){
                return false
            }else{
                seen.insert($0)
                return true
            }
        }
    }
}

let uni = [1,2,3,3,5,5,6,7,7,13,12,0].unique()  //[1, 2, 3, 5, 6, 7, 13, 12, 0]
type(of: uni)  //Array<Int>.Type

//示例
var test:Set<Int> = []
type(of: test)  //Set<Int>.Type
let uni1 = [1,2,3,3,5,5,6,7,7,13,12,0].filter { (num) -> Bool in
    
    if test.contains(num){
        print("false:\(num)")
        return false
    }else{
        print("true:\(num)")
        test.insert(num)
        return true
    }
    
}
uni1  //[1, 2, 3, 5, 6, 7, 13, 12, 0]
type(of: uni1)  //Array<Int>.Type
playground截图

Range

// 0 到 9, 不包含 10
let singleDigitNumbers = 0..<10

// 包含 "z"
let lowercaseLetters = Character("a")...Character("z")

范围看起来很自然地会是一个序列或者集合类型,但是可能出乎你的意料,它并非这两者之一 - 至少不是所有的范围都是序列或者集合类型。

在标准库中,现在有四种范围类型。它们能够被归类到一个 2x2 的矩阵中:

---- 半开范围 闭合范围
元素满足 Comparable Range ClosedRange
元素满足 Strideable (以整数为步长) CountableRange CountableClosedRange
  • 只有半开范围能够表达空区间的概念 (当范围的上下边界相等时,比如 5..<5)。

  • 只有闭合范围能够包含它的元素类型所能表达的最大值 (比如 0...Int.max)。半开范围总是最少会有一个值比范围所表达的只要大。
    Range后续的内容感觉超级底层,我决定以后再看看好了,现在看也看不懂。

发现一个文章写完太长了,分章节记载分享好了,也方便有需要的人根据需求查看
《Swift进阶》王巍译——集合类型协议

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,513评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,312评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,124评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,529评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,937评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,913评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,084评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,816评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,593评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,788评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,267评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,601评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,265评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,158评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,953评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,066评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,852评论 2 277

推荐阅读更多精彩内容

  • 集合类型: Swift,和其他现代编程语言一样,有内置的集合类型数组(Array)和字典(Dictionary),...
    小松树先生阅读 1,042评论 0 2
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,638评论 4 59
  • 前言 3月27号苹果发布了Swift3.1,官方教程也更新到了3.1,查看更新记录发现更新的内容对之前的文章并没有...
    BoomLee阅读 3,055评论 0 4
  • 二阶段,第四次作业。 《活得明白》P31页 R•阅读原文片段 跨越选项看目标。 当我们不知道要去哪的时候,对路径的...
    露苏维阅读 140评论 1 0
  • 1 前阵子在公众号上看到一则新闻,说四川有个80多岁的老太太坐车到成都看病,但她的坐票没有买到终点站所以在途中被主...
    谷棋ss阅读 221评论 2 3