iOS开发那些奇技淫巧和工具类收集

iOS开发小技巧和常用工具类(平时收集和整理)

前言

作为一个开发者应该学会去整理收集开发常用的工具类,这些复用的工具可以在项目开发中给你很大程度提高你的工作效率。难道你不想早点完成工作,然后出去撩妹、陪女朋友或者回家陪老婆孩子吗?反正我想早点回家😄。

更新

2017-12-12 PM 重新编辑

  1. 使用Pod管理公共类(常用的工具类和分类)传送门-->
  2. 为后期的组件化学习和项目重构做准备

想学习的小伙伴欢迎一起哈

如果想了解新的内容请关注github

由于工作原因(其实是本人比较懒) 文章更新会很慢或者忘记更新,关于更新的说明: 文章中只提供方法名说明在俺的github上可以找到具体实现

小方法小技巧大用处(我的github没有哦)

建好Base类
BaseViewController

所有的控制器继承于这个base,在此基类你可以对所有控制器共同的属性和方法进行控制。比如设置控制器View的背景色,下面是我的base,只供参考

BaseViewController.h

@interface BaseViewController : UIViewController
@property (nonatomic, assign)VCType vcType;
@property (nonatomic, strong)id vcParam;

- (void)push:(NSString *)vcName;
- (void)push:(NSString *)vcName param:(id)param;
- (void)openWeb:(NSString *)urlStr title:(NSString *)title;

@end

BaseViewController.m

- (void)push:(NSString *)vcName{
    Class classVC = NSClassFromString(vcName);
    UIViewController *vc = [classVC new];
    [self.navigationController pushViewController:vc animated:YES];
}
- (void)push:(NSString *)vcName param:(id)param{
    Class classVC = NSClassFromString(vcName);
    BaseViewController *vc = [classVC new];
    vc.vcParam = param;
    [self.navigationController pushViewController:vc animated:YES];
}
- (void)openWeb:(NSString *)urlStr title:(NSString *)title{
    WebViewController *vc = [[WebViewController alloc]init];
    vc.strUrl = urlStr;
    vc.title = title;
    [self.navigationController pushViewController:vc animated:YES];
}
BaseLabel、BaseTextField、BaseTableViewCell和BaseButton等等我就不一一列举了

在这些基类中可以设置常用的初始化设置,比如我常用的label字体是15号黑色等
分享个亲身经历:有一次项目经理要求把所有输入框的光标颜色改为主题色,当时我用的是扩展替换了初始化方法,如果当时我有这个基类就可以一句代码搞定了ಥ_ಥ

runtime轻松搞定初始化UITabBarController
- (void)initTabBarWithTitles:(NSArray *)titles
                     vcNames:(NSArray *)classes
                      images:(NSArray *)images
              selectedImages:(NSArray *)selectedImages{
    
    NSDictionary *nomalTextDic = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:12.0],
                                   NSForegroundColorAttributeName:UIColorFromRGB(MAIN_GRY_COLOR)};
    
    NSDictionary *higjlightTextDic = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:12.0],
                                       NSForegroundColorAttributeName:UIColorFromRGB(THEME_COLOR)};
    
    NSMutableArray *vcArray = [NSMutableArray array];
    
    for (int i = 0;i < titles.count ; i ++) {
        UITabBarItem *first_item = [[UITabBarItem alloc]initWithTitle:titles[i] image:[UIImage imageWithFileName:images[i]] selectedImage:[[UIImage imageWithFileName:selectedImages[i]]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
        first_item.imageInsets = UIEdgeInsetsMake(0, 0, 0, 0);
        [first_item setTitleTextAttributes:nomalTextDic forState:UIControlStateNormal];
        [first_item setTitleTextAttributes:higjlightTextDic forState:UIControlStateSelected];
        first_item.tag = VCType_First + i;
        Class classVC = NSClassFromString(classes[i]);
        BaseViewController *vc = [classVC new];
        vc.tabBarItem = first_item;
        [vcArray addObject:vc];
    }
    self.viewControllers = vcArray;
    
}
推荐ReactiveCocoa
准备工作
在这里我只介绍一个我经常用到的小方法:由于现在做的项目很多页面需要打开系统相册和相机所以简单封装了一个打开系统相机和相册的方法

VDImagePicker.h

@interface VDImagePicker : UIImagePickerController
+ (void)pickImageWithController:(id)vc sourceType:(UIImagePickerControllerSourceType)sourceType callback:(void(^)(UIImage *image))callback;

@end

VDImagePicker.m

#import "VDImagePicker.h"
#import <ReactiveCocoa/ReactiveCocoa.h>

@interface VDImagePicker ()
@property (nonatomic, copy)void (^callback)(UIImage *image);

@end

@implementation VDImagePicker

+ (void)pickImageWithController:(id)vc sourceType:(UIImagePickerControllerSourceType)sourceType callback:(void (^)(UIImage *))callback{
    if (sourceType == UIImagePickerControllerSourceTypeCamera&&![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
        VDLog(@"该设备不支持相机调用哦!ಥ_ಥ");
        return;
    }
    VDImagePicker *imagePicker = [[VDImagePicker alloc]init];
    imagePicker.callback = callback;
    [[vc rac_signalForSelector:@selector(imagePickerController:didFinishPickingImage:editingInfo:) fromProtocol:@protocol(UIImagePickerControllerDelegate)] subscribeNext:^(id x) {
        if (imagePicker.callback) {
            imagePicker.callback([x objectAtIndex:1]);
        }
        [imagePicker dismissViewControllerAnimated:YES completion:^{
            imagePicker.callback = nil;
            [imagePicker removeFromParentViewController];
        }];
    }];
    imagePicker.allowsEditing = YES;
    imagePicker.delegate = vc;
    imagePicker.sourceType = sourceType;
    [vc presentViewController:imagePicker animated:YES completion:nil];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end

一个方法搞定访问相机和相册是不是很爽O(∩_∩)O~,不过一般是配合acitonSheet使用,自己写个兼容iOS8.0的UIAlertController的扩展方法配合使用吧!


↑↑↑↑↑↑ 上面的内容我的github没有哦
↓↓↓↓↓↓ 下面的内容都在我的github


一、常用的宏定义

善于利用宏在开发中过程中会减少很多工作量比如定义开发过程中的常用尺寸,这样在后续开发中不用为了改一个相同尺寸而满世界的去找这个尺寸在哪用到了。宏定义用的很广泛,例如屏幕的宽高,网络请求的baseUrl等等
下面是自己整理的一些示例:

#if TARGET_IPHONE_SIMULATOR//模拟器
#define PHONE_MARK  0
#elif TARGET_OS_IPHONE//真机
#define PHONE_MARK 1
#endif

//16进制颜色转换
#define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]

//屏幕的宽高
#define SCREEN_WIDTH   [[UIScreen mainScreen] bounds].size.width
#define SCREEN_HEIGHT  [[UIScreen mainScreen] bounds].size.height

//转化为weak对象(block循环引用使用时)
#define WeakObj(o) __weak typeof(o) obj##Weak = o;

自定义log并以一个宏区分是否为debug模式

#define DEBUGGER 1 //上线版本屏蔽此宏

#ifdef DEBUGGER
/* 自定义log 可以输出所在的类名,方法名,位置(行数)*/
#define VDLog(format, ...) NSLog((@"%s [Line %d] " format), __FUNCTION__, __LINE__, ##__VA_ARGS__)

#else

#define VDLog(...)

#endif  

示例在viewDidLoad中

VDLog(@"很好用的");

输出结果为

-[ViewController viewDidLoad] [Line 35] 很好用的

一、UIView的扩展类(category)

1.在开发中会经常获取或者改变控件的位置大小,所以这样的类别就大有用处了,你可以方便的改变任意位置大小属性(这样在做一些控件的位置大小动画也很方便),废话不多说直接上代码。

UIView+tool.h

#import <UIKit/UIKit.h>

@interface UIView (tool)

#pragma mark [frame]

/**
*  view的x(横)坐标
*/
@property (nonatomic, assign)CGFloat v_x;
/**
 *  view的y(纵)坐标
 */
@property (nonatomic, assign)CGFloat v_y;
/**
 *  view的宽度
 */
@property (nonatomic, assign)CGFloat v_w;
/**
 *  view的高度
 */
@property (nonatomic, assign)CGFloat v_h;


#pragma mark [layer]

/**
 *  view的圆角半径
 */
@property (nonatomic, assign)CGFloat v_cornerRadius;


@end

2.此扩展的功能为给一些空的页面添加默认图,比如网页加载失败时或者一些tableView的列表数据为空时给出一个提示页并且增加重新加载机制。这个在大部分项目中必不可少的一部分,所以这个东西就诞生了!

UIView+EmptyShow.h

#import <UIKit/UIKit.h>
typedef void (^ReloadDataBlock)();

typedef NS_ENUM(NSInteger, ViewDataType)
{
    ViewDataTypeMyOrder = 0,//我的订单
    ViewDataTypeLoadFail//web页加载失败
};

@interface CustomerWarnView : UIView
//提示图
@property (nonatomic, strong) UIImageView     *imageView;
//提示文字
@property (nonatomic, strong) UILabel         *tipLabel;
//刷新按钮
@property (nonatomic, strong) UIButton        *loadBtn;
//用于回调
@property (nonatomic, copy) ReloadDataBlock reloadBlock;
//初始化
+ (CustomerWarnView *)initWithFrame:(CGRect)frame andType:(ViewDataType)type;


@end

@interface UIView (EmptyShow)

@property (strong, nonatomic) CustomerWarnView *warningView;
/**
 *  空页面显示提醒图与文字并添加重新刷新
 *
 *  @param emptyType 页面的展示的数据类别(例如:我的订单或者web页)
 *  @param haveData  是否有数据
 *  @param block     重新加载页面(不需要时赋空)
 */
- (void)emptyDataCheckWithType:(ViewDataType)emptyType
                   andHaveData:(BOOL)haveData
                andReloadBlock:(ReloadDataBlock)block;

@end

源码结构分析:源码中使用runtime给类别添加属性并使用纯代码实现一个自定义View,其中布局采用了第三库Masonry(需要的请自行导入),刷新的回调使用的block。

用法:只需要在获取数据后或者网页加载失败的回调中使用tableView或者webView等调用此方法

- (void)emptyDataCheckWithType:(ViewDataType)emptyType
                   andHaveData:(BOOL)haveData
                andReloadBlock:(ReloadDataBlock)block;

示例图


emptyOrder.png

二、NSString的扩展类

在做项目中对字符串的处理是必不可少的,或者要对一些数据进行字符串的转换等等。下面就介绍几个自己在项目中经常使用的方法。下面的category包括:时间戳转化为字符串的各类形式,获取当前设备deviceId和字符串向富文本的转换(哥现在做的项目大部分页面都用到了这东西)。
NSString+tool.h

#import <Foundation/Foundation.h>

static NSString  *const XCColorKey = @"color";
static NSString  *const XCFontKey = @"font";
static NSString  *const XCRangeKey = @"range";
/**
 range的校验结果
 */
typedef enum
{
    RangeCorrect = 0,
    RangeError = 1,
    RangeOut = 2,
    
}RangeFormatType;

@interface NSString (tool)

#pragma mark - 常用工具
/**
 *  获取当前Vindor标示符
 *
 *  @return deviceId
 */
+ (NSString *) getDeviceIdentifierForVendor;


/**
 *  转换为XXXX年XX月XX日
 *
 *  @param time 时间戳
 *
 *  @return 年月日
 */
+ (NSString*) format:(NSTimeInterval) time;

/**
 *  转化为XX时XX分XX秒
 *
 *  @param time 时间戳
 *
 *  @return 时:分:秒
 */
+ (NSString*) formatTime:(NSTimeInterval) time;

/**
 *  转化为XXXX年XX月XX日XX时XX分XX秒
 *
 *  @param time 时间戳
 *
 *  @return 年月日 时:分:秒
 */
+ (NSString *) formatDateAndTime:(NSTimeInterval)time;

#pragma mark - 校验NSRange
/**
 *  校验范围(NSRange)
 *
 *  @param range Range
 *
 *  @return 校验结果:RangeFormatType
 */
- (RangeFormatType)checkRange:(NSRange)range;

#pragma mark - 改变单个范围字体的大小和颜色
/**
 *  改变字体的颜色
 *
 *  @param color 颜色(UIColor)
 *  @param range 范围(NSRange)
 *
 *  @return 转换后的富文本(NSMutableAttributedString)
 */
- (NSMutableAttributedString *)changeColor:(UIColor *)color
                                  andRange:(NSRange)range;


/**
 *  改变字体大小
 *
 *  @param font  字体大小(UIFont)
 *  @param range 范围(NSRange)
 *
 *  @return 转换后的富文本(NSMutableAttributedString)
 */
- (NSMutableAttributedString *)changeFont:(UIFont *)font
                                 andRange:(NSRange)range;


/**
 *   改变字体的颜色和大小
 *
 *  @param colors      字符串的颜色
 *  @param colorRanges 需要改变颜色的字符串范围
 *  @param fonts       字体大小
 *  @param fontRanges  需要改变字体大小的字符串范围
 *
 *  @return 转换后的富文本(NSMutableAttributedString)
 */

- (NSMutableAttributedString *)changeColor:(UIColor *)color
                              andColorRang:(NSRange)colorRange
                                   andFont:(UIFont *)font
                              andFontRange:(NSRange)fontRange;

#pragma mark - 改变多个范围内的字体和颜色

/**
 *  改变多段字符串为一种颜色
 *
 *  @param color  字符串的颜色
 *  @param ranges 范围数组:[NSValue valueWithRange:NSRange]
 *
 *  @return 转换后的富文本(NSMutableAttributedString)
 */
- (NSMutableAttributedString *)changeColor:(UIColor *)color andRanges:(NSArray<NSValue *> *)ranges;

/**
 *  改变多段字符串为同一大小
 *
 *  @param font   字体大小
 *  @param ranges 范围数组:[NSValue valueWithRange:NSRange]
 *
 *  @return 转换后的富文本(NSMutableAttributedString)
 */
- (NSMutableAttributedString *)changeFont:(UIFont *)font andRanges:(NSArray<NSValue *> *)ranges;

@end

下面是转化为富文本的示例代码

UILabel *lable = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, V_SCREEN_WIDTH, 100)];
    lable.center = self.view.center;
    lable.numberOfLines = 0;
    lable.textAlignment = NSTextAlignmentCenter;
    lable.textColor = [UIColor blackColor];
    lable.font = [UIFont systemFontOfSize:15.0];
    [self.view addSubview:lable];
    NSString *str = @"这个是绿色字号是20";
    //富文本
    lable.attributedText = [str changeColor:[UIColor greenColor] andColorRang:NSMakeRange(3, 2) andFont:[UIFont systemFontOfSize:20] andFontRange:NSMakeRange(8, 2)];

效果如图所示


富文本.png

三、UIImage扩展类

下面分享的是对image进行处理的扩展类,主要包含:图片的缩放,剪切和压缩
UIImage+tool.h

#import <UIKit/UIKit.h>

@interface UIImage (tool)

/**
 *  等比缩放
 *
 *  @param size 设置尺寸
 *
 *  @return image
 */
-(UIImage *)scaleImageToSize:(CGSize)size;
/**
 *  自定长宽
 *
 *  @param reSize 设置尺寸
 *
 *  @return image
 */
-(UIImage *)imageReSize:(CGSize)reSize;
/**
 *  剪切
 *
 *  @param cutRect 选取截取部分
 *
 *  @return image
 */
-(UIImage *)cutImageWithRect:(CGRect)cutRect;
/**
 *  压缩
 *
 *  @param image 待压缩的图片
 *
 *  @return image
 */
+ (UIImage *)smallTheImage:(UIImage *)image;
/**
 *  压缩(上传)
 *
 *  @param image 待压缩图片
 *
 *  @return 图片的二进制文件
 */
+ (NSData *)smallTheImageBackData:(UIImage *)image;
/**
 *  view转位图(一般用于截图)
 *
 *  @param view 需要转化的view
 *
 *  @return image
 */
+ (UIImage *)imageFromView:(UIView*)view;

@end

四、UIControl的扩展类

相信大家都遇到过按钮反复点击问题的处理,下面介绍的UIControl+clickRepeatedly扩展类,只需一句代码搞定此问题。不用太感谢我哦!(温馨提示:建议此类别别大范围使用)。

UIControl+clickRepeatedly.h

#import <UIKit/UIKit.h>

@interface UIControl (clickRepeatedly)

/**
 *  设置点击的间隔(防止反复点击)
 */
@property (nonatomic, assign)NSTimeInterval clickInterval;

@property (nonatomic, assign)BOOL ignoreClick;

@end

UIControl+clickRepeatedly.m

#import "UIControl+clickRepeatedly.h"
#import <objc/runtime.h>

static const char *ClickIntervalKey;
static const char *IgnoreClick;
@implementation UIControl (clickRepeatedly)

- (void)setClickInterval:(NSTimeInterval)clickInterval{
    objc_setAssociatedObject(self, &ClickIntervalKey, @(clickInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSTimeInterval)clickInterval{
    
    return [objc_getAssociatedObject(self, &ClickIntervalKey) doubleValue];
}

- (void)setIgnoreClick:(BOOL)ignoreClick{
    objc_setAssociatedObject(self, &IgnoreClick, @(ignoreClick), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (BOOL)ignoreClick{
    return [objc_getAssociatedObject(self, &IgnoreClick) boolValue];
}

+ (void)load
{
    //替换点击事件
    Method a = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
    Method b = class_getInstanceMethod(self, @selector(rc_sendAction:to:forEvent:));
    method_exchangeImplementations(a, b);
}

- (void)rc_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
{
    if (self.ignoreClick) {
        return;
    }
    else{
        [self rc_sendAction:action to:target forEvent:event];
    }
    if (self.clickInterval > 0)
    {
        self.ignoreClick = YES;
        [self performSelector:@selector(setIgnoreClick:) withObject:@(NO) afterDelay:self.clickInterval];
    }
    
}



@end

看上面的代码是不是很简单,其实使用起来更加简单,只需要在你初始化好的btn设置如下代码:

btn.clickInterval = 3;//点击完三秒后才能点哦

五、用户信息(单例模式)

UserInfoModel:实现一些轻量级的用户信息存储和类的归档存入


六、AFNetWorking的二次封装

1.简单的HTTP(POST)请求:其中添加了多种请求错误判断和debug模式下打印响应成功的数据,最后采用block进行响应结果的回调

/**
 *  发送请求
 *
 *  @param requestAPI 请求的API
 *  @param vc         发送请求的视图控制器
 *  @param params     请求参数
 *  @param className  数据模型
 *  @param response   请求的返回结果回调
 */
- (void)sendRequestWithAPI:(NSString *)requestAPI
                    withVC:(UIViewController *)vc
                withParams:(NSDictionary *)params
                 withClass:(Class)className
             responseBlock:(RequestResponse)response;

2.创建下载任务并对下载进度,任务对象和存储路径等进行回调(支持多任务下载),创建的任务会自动加到下载队列中,下载进度的回调自动回到主线程(便于相关UI的操作)

/**
 *  创建下载任务
 *
 *  @param url          下载地址
 *  @param fileName     文件名
 *  @param downloadTask 任务
 *  @param progress     进度
 *  @param result       结果
 */
- (void)createDdownloadTaskWithURL:(NSString *)url
              withFileName:(NSString *)fileName
                       Task:(DownloadTask)downloadTask
                   Progress:(TaskProgress)progress
                     Result:(TaskResult)result;

3.创建上传任务与下载方法回调基本一致

/**
 *  创建上传任务
 *
 *  @param url        上传地址
 *  @param mark       任务标识
 *  @param data       序列化文件
 *  @param uploadTask 任务
 *  @param progress   进度
 *  @param result     结果
 */
- (void)createUploadTaskWithUrl:(NSString *)url
                       WithMark:(NSString *)mark
                       withData:(NSData *)data
                           Task:(UploadTask)uploadTask
                       Progress:(TaskProgress)progress
                         Result:(TaskResult)result;

七、校验工具类

1.手机号校验

+(BOOL) isValidateMobile:(NSString *)mobile

2.邮箱校验

+(BOOL)isValidateEmail:(NSString *)email

3.车牌号校验

+(BOOL) isvalidateCarNo:(NSString*)carNo

4.身份证号验证

+(BOOL) isValidateIDCardNo:(NSString *)idCardNo

待续

本笔记会持续更新。


附上github上源码,工具类全部在tool文件目录下

别着急离开,留点足迹给个喜欢!您的鼓励是我最大的支持↖(ω)↗

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

推荐阅读更多精彩内容