iOS Apprentice中文版-从0开始学iOS开发-第二课

The Bull's Eye game
在本节课,你将要创建一个名为Bull's Eye的游戏。这是这个游戏完成品的预览。

The Bull's Eye game

这个游戏的目标就是将刻度为0到100之间的滑条上的bull's eye(就是滑条上的浮标)的位置尽可能的拖放在接近等于给出随机数的位置。在上面的屏幕截图上,给出的目标值为84(原文中为22,估计是书的版本更新了,但是截图木有更新),所以我们要将滑条上的bull's eye拖动到尽可能最好是刚好等于84的位置,因为我们无法看到滑条上的当前数值,所以我们需要目测位置。(我猜这就是这个游戏名字Bull's eye的来由了)

当你确实有自信位置已经接近目标值的时候点击‘Hit Me’按钮,然后界面上会弹出一个消息框,上面会显示你的得分,像这个样子:

An alert popup shows the score

你越是接近目标值,你的得分就越高。在你点击‘OK’之后,弹窗会被关闭,新的一局就开始了,同时也会给出一个新的随机数作为新的目标。每次重复游戏都会累加你的得分,直到你点击‘Start Over’按钮,就是左下角的那个U字型箭头,你的得分将会被清零。

这个应用也许不会让你立刻成为百万富翁,但是那些App Store中的百万富翁都是从这一小步开始的。

做一个编程的工作计划
练习:现在,你已经看到了游戏的完整界面以及游戏的规则,试着列一下,为了完成这个游戏开发,你都需要做哪些工作,脑子里一片空白是正常的,但是尽可能的去例举下自己应该做些什么。
我举一个例子:
这个游戏应用需要放置一个名叫‘Hit Me’的按钮到屏幕上,并且当玩家点击这个按钮到时候,需要弹出一个消息框。

试着去想想其他要做的一切工作,至于你是否能完成这些工作目前无关紧要。第一阶段是要整理出需要做的事情,至于具体如何去做,眼下一点都不重要。(想象一下自己是个产品经理,只需要提要求就可以了,具体的事情可以交给开发团队去做)

一旦你知道了自己想要的是什么,你就可以指出如何去做这件事,即使在这个过程中你不得不去问其他人或者查阅一些资料。但是‘想要什么’是最重要的。(你会惊讶于许多人开始写代码前根本根本没有形成一个清晰的目标,难怪他们进行不下去!)

无论何时,我开始着手做一个新的app时,我会首先把我认为这个app需要的各种功能做一个列表。这个列表会成为我的编程清单。用一个列表把构想分解成若干小任务,是处理复杂工程的非常棒的方法。

你也许有一个非常棒的点子,但是当你坐下来开始编程的时候感觉根本无从下手,无法开始。通过把工作分解成若干小的步骤可以使整个事情的难度下降许多。我们总是可以找到简单并且足够简易的一个出发点,并且从这里开始入手。

如果这个练习让你觉得困难也没啥大不了的。毕竟你是该领域的新手,对此一无所知。当你熟悉了软件的运作方式以后,你可以轻易的将一个构想分解为易处理、可管控的若干小模块。

这是我做的清单,我只是简单的将游戏描述切成非常小的块。

1、在屏幕上放置一个按钮,并且标记为‘Hit Me’
2、当玩家点击‘Hit Me’按钮时,app应该弹出一个消息框,并且显示玩家的成绩。计算分值并且将分值显示在消息框上。
3、在屏幕上放置文本,比如“Score:”、“Round:”这类标签。其中一些文本在每一局的值会发生变化,比如score,当玩家得分后,该数字会增加。
4、放置一个滑条在屏幕上,并且设置滑条值的范围为1-100.
5、当玩家点击‘Hit Me’按钮后,需要读取滑条位置的值。
6、在每局的开始生成一个随机数,并且将它显示在屏幕上作为目标值。
7、通过比较滑条上的值和目标值为玩家计分,并且将结果显示在弹出消息框上。
8、在屏幕上放置一个‘Start Over’按钮。用于重制分值并且使游戏回到第一局。
9、固定app在横向上。
10、把app界面做的好看些

也许我漏掉了那么一两项工作,但是看起来像是一个得体的列表了。即使是像一个这样小的游戏,也有如此多的工作需要做。开发app是非常有趣的,但同时也是工作繁重的。

一个按钮的APP
让我们从清单中的第一条开始,做一个关于这个游戏的及其简单的第一个版本,显示一个按钮。当你点击这个按钮的时候,app会弹出一条消息。这就是我们此时要做的全部。一旦这一步成功了,我们将在这个基础上做完这个游戏的其他剩余部分。
这个app会长成下面这个样子:

左边是一个按钮,右边是点击按钮后显示的消息

到了写代码的时候了!我假设你已经下载并且安装了最新版的软件开发工具。

在我们的课程中,我们会使用Xcode 8.0或者更高版本。更新的版本也许也适用于本课程,但是任何低于8.0的版本就不适用了。

因为swift是一种非常新的语言,它经常随着Xcode的版本变化而变化。如果你的Xcode版本过低或者过高!(目前最高就是8.0)那么本书中的代码也许就不能完全运行了。(基于同样的原因,你也不要去用任何beta版本,只用MAC App Store里现有的版本就可以了)

运行Xcode。如果你找不到Xcode应用的图标,你可以从Finder/应用程序/Xcode中找到,或者在触控板上四指合拢从Launchpad中找到。因为我自己经常使用Xcode,所以我把它固定在dock栏中,非常易于运行。

当Xcode运行时,会显示一个‘Welcome to Xcode’的欢迎界面:

Xcode欢迎界面

选择Create a new Xcode project。就可以看到Xcode的主菜单窗口,并且从这里选择一个模版。

为新工程选择一个模版

这里有多种应用样式的模版。Xcode会根据你选择的模版做一些预配置,这样当你新建一个工程的时候就已经生成了许多你需要的源文件。这些模版都非常便利,可以节省你大量的精力。他们是现成的起跑线。

选择Single View Application(但视图应用)并且点击Next按钮。
之后会打开一个界面,可以在这里配置新app的一些选项:

配置新的工程

像这样填写以下项目:
Product Name(工程名称):BullsEye。如果你想使用比较传统的英语,你可以Bull's Eye代替BullsEye,但是最好工程名称中还是避免使用空格和特殊字符。

Team(团队):如果你已经是苹果开发者成员了,那么这里会显示你的团队名称。目前我们最好不要去管它;在本课程的后面我们会回过头来讨论这个事。

Organization Name(组织名称):填写你自己的名字或者公司的名字。

Organization Identifier(组织身份):我的是“com.razeware”。这是我用于自己app的唯一标示码。习惯上,这里是将我的域名倒过来写。你应该在这里填写你自己的标识。选择一个没有重复的,或者把你自己的域名像我一样倒过来写,也可以仅仅是写上自己的名字。你可以随时修改这一项。(国内个人域名并不流行,为了确保唯一性,你可以填邮箱)

Language(语言):Swift

Devices(设备):iPhone

确保底部的三个复选框——Use Core Data,Include Unit Tests,和Include UI Tests不要被选中。在这个工程中你不会用到这些。

点击Next。现在Xcode会让你选择工程文件的存储路径:

选择存储路径

选择一个位置存储,比如桌面或者我的文档。
Xcode会自动创建一个以工程名命名的新文件夹用于存放工程文件,所以你无需自己创建文件夹。
在底部有一个叫做“Create Git repository on My Mac”的复选框。目前你可以忽视它。你将会在下一个课程中学习有关版本控制的内容。

点击Create完成新工程的创建。

这时Xcode已经基于单视图应用的模版在你指定的文件夹中创建好了一个名为BullsEye。
你的屏幕现在看起来应该像这样:

新建工程的主窗口

也许你电脑上的界面会和我的看起来有些不同,不过假如你的Xcode版本是8.0或者更新,那么放心,任何差别都是微不足道的。

注意:如果你看不到一个叫做 ViewController.Swift的文件,在左侧列表中,而是可以看到ViewController.h和ViewController.m,那就是你选择了错误的语言,你没有选择Swift,而是选择了Objective-C。删掉这个工程文件(去存贮目录中删,把整个目录删掉),并且重新创建一遍,确保语言选择为Swift。

点击左上角的Run按钮

点击Run运行app

注意:如果这是你第一次运行Xcode,它也许会要求你打开开发者模式。点击Enable并且输入你的密码,允许Xcode作出这些更改。

Xcode会在模拟器中运行你的app。这个app目前看起来一无是处,并且不具备任何功能,但是这是你旅途中的一个重要的里程碑。

基于单视图模版的App

当你点击run按钮时如果Xcode报错“Build Failed”或者“Xcode cannot run using the selected device”,确定下图中的这个选项是BullsEye>iPhone SE(或者其他任何型号),而不是Generic iOS Device

确定app是在模拟器上运行

如果你的iPhone手机此时正好通过USB连接在你的MAC电脑上,那么Xcode也许会试图直接在你的手机上运行这个app,但是没有一些额外设置,是运行不起来的。在本节课快结束的时候,我会给你们展示如何在你的iPhone上运行你的app,这样你就可以拿去给朋友们看了,但是目前我们还是在模拟器中进行教学。

在Run旁边的是Stop按钮(方块的那个),点击它退出app。

在我们的手机中你需要按一下home键退出app(在模拟器中需要选择顶部菜单中的Hardware->Home选项),但是这样并没有实际的中断app。它会在模拟器的屏幕上消失,但是实际上仍然驻留在模拟器的内存中,就和真实的手机上是一致的。

在你点击Stop之前,Xcode的顶部活动指示器会始终显示“Running BullsEye on iPhone SE”

Xcode的活动指示器

你可以在app保持运行时回到Xcode进行代码的变更,并不是非要把它停止掉。但是这些改变并不会被启用,直到你停止并且重新启动app它们才会生效。点击停止再点击运行后,会中断该app任何运行中的版本,之后生成一个新的版本,并且重新在模拟器中运行。

当你点击Run后发生了什么?
首先Xcode会编译你的源代码-就是把Swift语言翻译为iPhone或者模拟器能够识别的机器语言。因为即使用Swift或者Objective-C写成的iPhone app,iPhone也不认识它们。所以翻译的工作是必须的。

编译器是Xcode的一部分,它会将你的Swift源代码转换为可执行的二进制代码。它同时也收集所有用于组装app的组件-比如源文件、图像、故事模版文件(storyboard files)等等,并且将它们打包为所谓的应用包(application bundle)

这整个进程称之为创建app。如果这中间有什么错误(比如关键字拼写错误),创建会失败。如果所有事情都按部就班的进行,Xcode会复制应用包到模拟器或者手机中,并且运行它。所有这些事情仅仅点一下Run就完成了。

添加按钮
我敢肯定你和我一样有点惊讶于一个app仅仅展现一个白色的界面,所以,我们加一个按钮上去吧。

Xcode窗口的左手边部分叫做导航器区域(Navigator area)。顶部的一行图标决定目前显示的是哪个导航器。目前显示的是工程导航器,用于展示工程中的文件列表。

这些文件的组织方式和你硬盘中的工程文件夹中的大致一致,但并不是非得这样。你可以按照你想的把这些文件拖拽到新的分组中去。我们稍后会讨论工程中的不同文件。

在工程导航器中,找到名为Main.storyboard并且单击选择它:

工程导航器列出了工程中的文件

选中以后,像超人在电话亭里变装一样,Xcode的主编辑面板就切换到了界面建造器(Interface Builder)。这个工具使你可以通过拖拽的方式将界面组件放置到app上,比如一个按钮。(好吧,虽然类比有些不恰当,但是界面建造器对我而言是个超级工具)

如果你看不到界面建造器,点击Xcode工具栏右上角中的‘隐藏或显示实用工具(Hide or show utilities)’按钮

点击这个按钮显示或隐藏实用工具面板

这几个工具栏按钮可以改变Xcode的界面。这一个负责打开一个新的面板位于Xcode窗口的右侧。

现在你的Xcode应该看起来像是这个样子了:

在界面建造器上编辑故事面板(Main.storyboard)

这就是属于你app的故事面板(storyboard),你的app中的全部界面设计都会体现在这个故事面板中,并且以一个大箭头显示app如何从一个界面切换到另一个界面。

目前这个故事面板仅包含一个界面(或场景),就是界面建造器画布(真的是这样翻译,屏幕中间的一大块白色区域称之为画布)中的那个长方形。

注意:如果你看不到一个长方形,上面标有“View Controller”,而仅仅是一大片白色画布,那么用你的鼠标或触控板向四周滚动一下看看。相信我,它就在某个地方!并且保证你的Xcode窗口足够大(13寸屏估计会很杯具)。界面建造器会占用很大一块地方。

这个场景目前的大小应该是iPhone6或者iPhoen7的大小。为了使事情简单点,刚开始,我们会在iPhone SE的大小上进行设计,这样占用的屏幕会稍微小一些。之后我们会使这个app同样适应于iPhone6s,7和plus。

在界面建造器窗口的底部,点击“View as:iphone 6s”也许你的显示为“View as:iphone 7”会弹出一个面板(再次点击就可以关闭它):

选择设备类型

选择iPhone SE,第二小的那个iPhoen图标。选择之后代表场景的长方形会变小一些。该场景适用于iPhone 5,5s和SE的大小。

在Xcode的工具栏中,确保Stop按钮旁边显示为BullsEye>iPhone SE。如果不是的话则点击它并且在弹出列表中选择iPhone SE:

确认模拟器设备类型
选择模拟器设备类型

现在你运行app 的话,就会在iPhone SE的模拟器上运行了(试试看!)

回到故事面板

在实用工具面板的底部你会找到对象库(Object Library),确保被选中的是第三个看起来像是一个圆形的那个按钮:

对象库

在对象库中用鼠标滚动,查找到“Button”。

点击Button并且将它拖拽到工作区域,场景长方形的上面。

拖拽button到场景上

添加一个新按钮就是如此简单,仅仅是拖拽就可以了。其他的全部用户界面元素也都是这样处理。你会大量做这种工作,所以我们来花点时间熟悉下这个过程。

拖拽一些其他的控件,比如labels(标签),sliders(滑条),switches(开关),找找感觉。

这会给你在如何在iOS中使用UI控件带来一些灵感。注意一下,界面建造器可以通过吸附这些控件到屏幕边缘或者其他对象上来帮助你进行布局。这非常便利!

双击button来编辑标题。将它命名为“Hit Me!”

新的button标题

也许你的button会被一个边界包围着:

有一个矩形的边界包围着button

这个边界并不是按钮的一部分,仅仅是为了方便你查看这个button有多大。你可以在菜单Editor->Canvas->Show Bounds Rectangles中关闭显示这个边界。(为了不给自己找麻烦,我建议大家还是选择显示边界)

当你大概熟悉了界面建造器后,在Xcode的工具栏中点击Run按钮。这个app就应该在模拟器中运行了,这时你可以看到你的“Hit Me!”
按钮。然而,当你点击这个按钮时,什么都不会发生。为此,你不得不写点Swift代码了。

源码编辑器

一个点击后什么都不做的按钮对谁而言都是无用的,所以我们让它来弹出一个提醒窗口。在游戏结束的时候,这个提醒窗口会显示玩家的分数,但是现在我们仅仅是给自己展示一条简短的消息。(根据传统,这条消息应该是“Hello World”)

在工程导航器里点击ViewController.swift。
点击后界面建造器就会消失了,取而代之显示的是一个显示许多高亮色字体的编辑区域。这就是你的app的swift源代码。

代码编辑器

在最后一个大括号‘}’前添加如下代码:

@IBAction func showAlert() {
        
    }

现在ViewController.swift的代码应该是这样子的(简书中的代码框如果显示不全,尤其是在手机上看的时候,可以左右拖拽代码框):

//
//  ViewController.swift
//  BullsEye
//
//  Created by on 2017/1/11.
//  Copyright © 2017年 . All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func showAlert() {
        
    }
}


对你自己的第一行代码感觉如何?在我告诉你这些代码是作什么用的之前,我先要介绍一些关于view controller的概念。

Xcode会自动保存
你不需要在每次改动后去手动保存你的代码文件,因为当你点击Run按钮的时候Xcode会自动的保存所有被修改的文件。虽然如此,但是Xcode并不是世界上最稳定的软件,偶尔它也会崩溃并且没有来及保存你的修改,所以我仍然喜欢用command+S来自己保存文件。

视图控制器(view controllers)
你已经通过对Main.storyboard文件编辑建造了这个app的用户界面。尽管上面只有一个按钮和一个纯白色的背景。你同时也在VIewController.swift文件中添加了源代码。

这两个文件——storyboard和swift文件,一起实现了一个视图控制器(view controller)。做一个iOS app的大量工作就是制作视图控制器。一个视图控制器的作用就是管理你app上的一个界面。

以一个简单的食谱类app为例子。当你运行这个食谱app的时候,它的主界面列出了许多食谱。点击一下其中一个食谱就会弹出一个新的界面,显示关于这个食谱的烹饪方法、细节以及照片。每一个界面都被属于自己的视图控制器管理着。

食谱列表与食谱细节界面

这两个界面的作用是有很大不同的,一个是若干项目的列表;另一个是展示某条项目的详细细节。

这就是为什么此时同时需要两个视图控制器:一个知道如何处理列表,另一个可以处理图像和烹饪方法介绍的文本。这种视图控制器(view controller)被简单的命名为“VIewController”,由storyboard和swift文件共同实现它。

简而言之,Main.storyboard文件包含视图控制器的用户界面设计部分,而ViewController.swift包含它的功能部分——用swift语言写的逻辑使得用户界面可以正常工作。

因为你使用的是单视图应用模版(Single View Application template),所以Xcode会自动为你创建一个视图控制器。稍后,你将会添加第二个界面到这个游戏中,你将为这个界面手动创建一个视图控制器。

形成链接
你在ViewController.swift文件中添加的几行源代码使得界面建造器(Interface Builder)知道了这个控制器有一个叫做“showAlert”的动作,就是会弹出一个提示窗口的动作。你将要把按钮和这个动作链接起来。

点击Main.storyboard 回到界面建造器。

界面建造器的左边应该会有一个面板,纲要面板,这里列出了storyboard中的所有项目。如果你看不到这个面板,点击界面建造器左下角的一个小开关来显示它。

用于显示大纲面板的开关

单击“Hit Me”按钮来选中它

在Hit Me按钮被选中的同时,按住ctrl键,在按钮上点击一下,并且将它拖向略缩面板中的View Controller项目。你应该可以看到一条蓝色的线将按钮和View Controller链接了起来。(除了按住ctrl键,你也可以用鼠标右键进行这一拖拽)

拖拽按钮到视图控制器

当完成拖拽,放开鼠标时,你将会看到出现一个小菜单。它包含两个部分,“Action Segue”和“Sent Events”,在每个部分的下面都有一个或多个选项。你要选择的是“Sent Events”下面的“showAlert”选项。这是你之前在ViewController.swift文件中写源代码时,为这个动作所取的名称。

带有showAlert选项的弹出菜单

从现在开始,不管什么时候点击按钮都会触发showAlert这个动作。这就是你做按钮或者其他控件时要做的事情:你在ViewController对应的Swift文件中定义动作,然后把它和界面链接起来。

你可以在链接指示器中查看你创建的链接,就是实用工具面板中的最右面一个选项。

点击这个右箭头符号的按钮,切换到链接指示器:

链接指示器中可以查看按钮和对象之间的链接

选择ViewController.swift来编辑它。

注意@IBAction fund showAlert的左边,这里有一个实心圆点。点击它也可以展示链接的内容。

这个实心圆点意味着这里存在一个链接,如果没有链接则是空心的

让按钮表演一下它的功能

你现在有了一个界面和一个按钮。这个按钮链接着一个叫showAlert的动作,当你点击这个按钮时,将触发这个动作。

目前,无论你如何点击这个按钮,还是什么都不会发生,因为毕竟这个动作是空的,里面什么都没有,让我们来给它一点指令。

在ViewController.swift中,添加以下代码到showAlert中(再次提示代码框可以左右滑动):

@IBAction func showAlert() {
        let alert = UIAlertController(title: "Hello World", message: "This is my first app!", preferredStyle: .alert)
        let action = UIAlertAction(title: "Awesome", style: .default, handler: nil)
        alert.addAction(action)
        present(alert,animated: true,completion: nil)
    }

这些新的代码给这个动作提供了实际的功能。
{}花括号中间的代码告诉iPhone在点击按钮后去做什么。
showAlert后面跟的花括号中的代码创建了一个提醒窗口,标题为“Hello World”,内容为“This is my first app!”,以及一个新的按钮,叫做“Awesome”。

如果你分不清楚标题和内容的区别,你就记住,它们都是文本,并且标题的字体会比内容的要大。

点击位于Xocde工具栏上的Run按钮。如果你没有在代码里有拼写错误,那么你的app将在模拟器中如期运行,并且当你点击Hit Me按钮时,你会看到一个提醒窗口。

弹出的提醒窗口

恭喜,你已经完成了你的第一个iOS app!你刚才做的事情也许让你混乱不堪,但是没有关系。我们会穿插的讲解每一个小步骤。

你可以轻易的重复之前你做过的两个步骤:放一个button到界面上并且当点击按钮时展现一个提醒窗口。

稍微中断一下,让刚才的内容沉淀一下,当你准备好接受更多内容时再回来。你仅仅是踏出了第一个小步。。。

⚠️:为了防止你卡住做不下去,在随书附带的源代码文件夹中我提供了每一小节的完整代码。(想到得到代码的同学请支持正版_)。这样你就可以用自己的代码和我提供的代码做对比学习,或者你弄糟了一些事情,也可以用我的版本继续往下学习。
截止目前为止你做的一切,都可以在01-one button app文件夹中找到完整的project文件。

问题?
如果你点击运行的时候,你的Xcode给你一个‘Build Failed’的报错,这时你需要确认你是否存在拼写错误,有没有敲错字符。即使最小的错误也会完全使Xcode无法理解你的意图而报错。一个小的拼写错误,也许会在不同文件中造成多个错误。

典型的错误是大小写不分,Swift编程语言有大小写之分的,这意味这alert和Alert是两个不同的名字。如果将alert错写为Alert的话,Xcode编译器会给出“<something> undeclared”或者“Use of undeclared identifier”的报错。

当Xcode告诉你类似于“Parse Issue”或者“Expected<something>”时,你多半是漏掉了某个花括号"{"或者圆括号“)”。没有相匹配的前后括号(Not matching up opening and closing brackets)是一种常见的错误。

(小贴士:如果你将光标移动到某个括号上双击一下,Xcode会高亮显示出对应的括号在哪里)

当你编程时像这样的小细节非常重要。即使敲错一个字符都可以使Xcode无法编译你的app。

幸运的是,像这样的错误是可以轻易发现的。


Xcode会给出清晰的报错提示

当Xcode查到有错误时,就会切换之前的左半部分的面板,切到到问题导航器上去。这里的列表显示了所有Xcode发现的的错误和警告。(你可以通过点击顶部的小按钮(文件夹图标的那个)回到project files面板中去)

在上图的报错中,显然我时忘掉了某个逗号。

点击错误信息后Xcode会告诉你时在哪一行发生的错误。并且会显示一个建议的解决方案:

Xcode会给出建议的解决方案

有时是很难定位到底那里出了问题,幸运的是,Xcode提供了有力的帮助。

Errors(错误) and warnings(警告)
Xcode对errors(红色的)和warnings(黄色的)做了区分。Errors是致命的。如果存在一个error,app将无法运行。warnings是警告性质的。Xcode仅仅是说:“也许不能这样做,但是管他呢,继续往下吧”
但是我认为,最好是将warnings和errors以同等重视程度对待。在运行程序前处理掉每一个warning和error。即使这样也不能保证app不存在bug,但是至少不会是低级错误。

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

推荐阅读更多精彩内容