前言

刚接手电子书项目时,和安卓开发者pt Cai老师【aipiti Cai,一个我很敬佩很资深的开发工程师,设计领域:c++、Java、安卓、QT等】共同商议了一下,因为项目要做要同步,移动端【手机端】和PC【电脑端】的同步问题,让我们无法决定该用那种方式去呈现电子书,因为PC要展示的电子书有网络图片,有HTML标签,主要功能是能做标记(涂色、划线、书签等),而且后台数据源返回的只有这一种格式:HTML;所以我们第一时间想到了可以用加载网页的Webview来做;pt Cai老师做了一些基于JS的分页及手势操作,然后对图片进行了适配,但是当我在测试Webview时,效果并不尽人意:

  • Webview渲染比较慢,加载需要一定的等待时间,体验不是很好;
  • Webview内存泄漏比较严重;
  • Webview的与本地的交互,交互是有一定的延时,而且对于不断地传递参数不好控制操作;

引入Coretext

通过上面的测试,我决定放弃了Webview,用Coretext来尝试做这些排版和操作;我在网上查了很多资料,从对Coretext的基本开始了解,然后查看了猿题库开发者的博客,在其中学到了不少东西,然后就开始试着慢慢的用Coretext来尝试;

demo

1.主框架

做电子书阅读,首先要有一个翻滚阅读页的一个框架,我并没有选择用苹果自带的 UIPageViewController 因为控制效果不是很好,我再Git上找了一个不错的 DZMCoverAnimation,因为是做demo测试,就先选择一个翻滚阅读页做效果,这个覆盖翻页的效果如下:

2.解析数据源

首先看一下数据源demo,我要求json数据最外层必须是P标签,P标签不能嵌套P标签,但可以包含Img和Br标签,Img标签内必须含有宽高属性,以便做排版时适配,最终的数据源为:

然后我在项目中用CocoaPods引入解析HTML文件的 hpple 三方库,在解析工具类CoreTextSource中添加解析数据模型和方法,假如上面的这个数据源是一章的内容,我把这一章内容最外层的每个P标签当做一个段落,遍历每个段落,然后在遍历每个段落里面的内容和其他标签;

CoreTextSource.h

#import <Foundation/Foundation.h>
#import <hpple/TFHpple.h> #import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger,CoreTextSourceType){
///文本
CoreTextSourceTypeTxt = ,
///图片
CoreTextSourceTypeImage
}; /**
文本
*/
@interface CoreTextTxtSource : NSObject
@property (nonatomic,strong) NSString *content;
@end /**
图片
*/
@interface CoreTextImgSource : NSObject
@property (nonatomic,strong) NSString *name;
@property (nonatomic,assign) CGFloat width;
@property (nonatomic,assign) CGFloat height;
@property (nonatomic,strong) NSString *url;
// 此坐标是 CoreText 的坐标系,而不是UIKit的坐标系
@property (nonatomic,assign) NSInteger position;
@property (nonatomic,assign) CGRect imagePosition;
@end /**
段落内容
*/
@interface CoreTextParagraphSource : NSObject
@property (nonatomic,assign) CoreTextSourceType type;
@property (nonatomic,strong) CoreTextImgSource *imgData;
@property (nonatomic,strong) CoreTextTxtSource *txtData;
@end
///电子书数据源
@interface CoreTextSource : NSObject
///解析HTML格式
+ (NSArray *)arrayReaolveChapterHtmlDataWithFilePath:(NSString *)filePath;
@end

CoreTextSource.m

#import "CoreTextSource.h"

@implementation CoreTextImgSource

@end
@implementation CoreTextParagraphSource @end
@implementation CoreTextTxtSource @end @implementation CoreTextSource + (NSArray *)arrayReaolveChapterHtmlDataWithFilePath:(NSString *)filePath{
NSData * data = [NSData dataWithContentsOfFile:filePath]; TFHpple * dataSource = [[TFHpple alloc] initWithHTMLData:data];
NSArray * elements = [dataSource searchWithXPathQuery:@"//p"]; NSMutableArray *arrayData = [NSMutableArray array]; for (TFHppleElement *element in elements) {
NSArray *arrrayChild = [element children];
for (TFHppleElement *elementChild in arrrayChild) {
CoreTextParagraphSource *paragraphSource = [[CoreTextParagraphSource alloc]init];
NSString *type = [elementChild tagName];
if ([type isEqualToString:@"text"]) {
CoreTextTxtSource *text = [[CoreTextTxtSource alloc]init];
text.content = elementChild.content;
paragraphSource.txtData = text;
paragraphSource.type = CoreTextSourceTypeTxt;
}
else if ([type isEqualToString:@"img"]){
CoreTextImgSource *image = [[CoreTextImgSource alloc]init];
NSDictionary *dicAttributes = [elementChild attributes];
image.name = [dicAttributes[@"src"] lastPathComponent];
image.url = dicAttributes[@"src"];
image.width = [dicAttributes[@"width"] floatValue];
image.height = [dicAttributes[@"height"] floatValue];
paragraphSource.imgData = image;
paragraphSource.type = CoreTextSourceTypeImage; if (image.width >= (Scr_Width - )) {
CGFloat ratioHW = image.height/image.width;
image.width = Scr_Width - ;
image.height = image.width * ratioHW;
}
}
else if ([type isEqualToString:@"br"]){
CoreTextTxtSource *text = [[CoreTextTxtSource alloc]init];
text.content = @"\n";
paragraphSource.txtData = text;
paragraphSource.type = CoreTextSourceTypeTxt;
} [arrayData addObject:paragraphSource];
} ///每个个<P>后加换行
CoreTextParagraphSource *paragraphNewline = [[CoreTextParagraphSource alloc]init];
CoreTextTxtSource *textNewline = [[CoreTextTxtSource alloc]init];
textNewline.content = @"\n";
paragraphNewline.txtData = textNewline;
paragraphNewline.type = CoreTextSourceTypeTxt;
[arrayData addObject:paragraphNewline];
} return arrayData;
}
@end

3.图片处理和分页

添加好CoreTextSource类之后,就可以通过 arrayReaolveChapterHtmlDataWithFilePath 方法获取这一章的所有段落内容;但是还有一个问题,既然用Coretext来渲染,那图片要在渲染之前下载好,从本地获取下载好的图片进行渲染,具体什么时候下载,视项目而定;我在CoreTextDataTools类中添加了图片下载方法,该类主要用于分页;在分页之前,添加每个阅读页的model -> CoreTextDataModel,具体图片的渲染,先详看CoreTextDataTools分页类中 wkj_coreTextPaging 方法和其中引用到的方法;

CoreTextDataModel.h

#import <Foundation/Foundation.h>

///标记显示模型
@interface CoreTextMarkModel : NSObject
@property (nonatomic,assign) BookMarkType type;
@property (nonatomic,assign) NSRange range;
@property (nonatomic,strong) NSString *content;
@property (nonatomic,strong) UIColor *color;
@end @interface CoreTextDataModel : NSObject
///
@property (nonatomic,assign) CTFrameRef ctFrame;
@property (nonatomic,strong) NSAttributedString *content;
@property (nonatomic,assign) NSRange range;
///图片数据模型数组 CoreTextImgSource
@property (nonatomic,strong) NSArray *arrayImage;
///标记数组
@property (nonatomic,copy) NSArray *arrayMark;
@end

CoreTextDataModel.m

#import "CoreTextDataModel.h"
@implementation CoreTextMarkModel @end @implementation CoreTextDataModel
- (void)setCtFrame:(CTFrameRef)ctFrame{
if (_ctFrame != ctFrame) {
if (_ctFrame != nil) {
CFRelease(_ctFrame);
}
CFRetain(ctFrame);
_ctFrame = ctFrame;
}
}
@end

CoreTextDataTools.h

///图片下载
+ (void)wkj_downloadBookImage:(NSArray *)arrayParagraph;
///分页
+ (NSArray *)wkj_coreTextPaging:(NSAttributedString *)str
textArea:(CGRect)textFrame
arrayParagraphSource:(NSArray *)arrayParagraph;
///根据一个章节的所有段落内容,来生成 AttributedString 包括图片
+ (NSAttributedString *)wkj_loadChapterParagraphArray:(NSArray *)arrayArray;

CoreTextDataTools.m

#import "CoreTextDataTools.h"
#import <SDWebImage/UIImage+MultiFormat.h> @implementation CoreTextDataTools
+ (void)wkj_downloadBookImage:(NSArray *)arrayParagraph{
dispatch_group_t group = dispatch_group_create();
// 有多张图片URL的数组
for (CoreTextParagraphSource *paragraph in arrayParagraph) {
if (paragraph.type == CoreTextSourceTypeTxt) {
continue;
} dispatch_group_enter(group);
// 需要加载图片的控件(UIImageView, UIButton等)
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:paragraph.imgData.url]];
UIImage *image = [UIImage sd_imageWithData:data];
// 本地沙盒目录
NSString *path = wkj_documentPath;
///创建文件夹
NSString *folderName = [path stringByAppendingPathComponent:@"wkjimage"]; if (![[NSFileManager defaultManager]fileExistsAtPath:folderName]) { [[NSFileManager defaultManager] createDirectoryAtPath:folderName withIntermediateDirectories:YES attributes:nil error:nil]; }else{
NSLog(@"有这个文件了");
} // 得到本地沙盒中名为"MyImage"的路径,"MyImage"是保存的图片名
// NSString *imageFilePath = [path stringByAppendingPathComponent:@"MyImage"]; // 将取得的图片写入本地的沙盒中,其中0.5表示压缩比例,1表示不压缩,数值越小压缩比例越大 folderName = [folderName stringByAppendingPathComponent:[paragraph.imgData.url lastPathComponent]]; BOOL success = [UIImageJPEGRepresentation(image, 0.1) writeToFile:folderName atomically:YES];
if (success){
NSLog(@"写入本地成功");
} dispatch_group_leave(group); }
// 下载图片完成后, 回到主线
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 刷新UI });
}
/**
CoreText 分页
str: NSAttributedString属性字符串
textFrame: 绘制区域
*/
+ (NSArray *)wkj_coreTextPaging:(NSAttributedString *)str
textArea:(CGRect)textFrame
arrayParagraphSource:(NSArray *)arrayParagraph{
NSMutableArray *arrayCoretext = [NSMutableArray array]; CFAttributedStringRef cfStrRef = (__bridge CFAttributedStringRef)str;
CTFramesetterRef framesetterRef = CTFramesetterCreateWithAttributedString(cfStrRef);
CGPathRef path = CGPathCreateWithRect(textFrame, NULL); int textPos = ;
NSUInteger strLength = [str length];
while (textPos < strLength) {
//设置路径
CTFrameRef frame = CTFramesetterCreateFrame(framesetterRef, CFRangeMake(textPos, ), path, NULL);
CFRange frameRange = CTFrameGetVisibleStringRange(frame);
NSRange range = NSMakeRange(frameRange.location, frameRange.length); // [arrayPagingRange addObject:[NSValue valueWithRange:range]];
// [arrayPagingStr addObject:[str attributedSubstringFromRange:range]]; CoreTextDataModel *model = [[CoreTextDataModel alloc]init];
model.ctFrame = frame;
model.range = range;
model.content = [str attributedSubstringFromRange:range];
model.arrayImage = [self wkj_arrayCoreTextImgRect:[self wkj_arrayCoreTextImg:arrayParagraph range:range] cfFrame:frame]; [arrayCoretext addObject:model];
//移动
textPos += frameRange.length;
CFRelease(frame);
}
CGPathRelease(path);
CFRelease(framesetterRef);
// return arrayPagingStr;
return arrayCoretext;
}
///获取每页区域内存在的图片
+ (NSArray *)wkj_arrayCoreTextImg:(NSArray *)arrayParagraph
range:(NSRange)range{
NSMutableArray *array = [NSMutableArray array]; for (CoreTextParagraphSource *paragraph in arrayParagraph) {
if (paragraph.type == CoreTextSourceTypeTxt) {
continue;
} if (paragraph.imgData.position >= range.location &&
paragraph.imgData.position < (range.location + range.length)) {
[array addObject:paragraph.imgData];
}
} return array;
}
///获取每个区域内存在的图片位置
+ (NSArray *)wkj_arrayCoreTextImgRect:(NSArray *)arrayCoreTextImg cfFrame:(CTFrameRef)frameRef{
NSMutableArray *arrayImgData = [NSMutableArray array]; if (arrayCoreTextImg.count == ) {
return arrayCoreTextImg;
}
NSArray *lines = (NSArray *)CTFrameGetLines(frameRef);
NSUInteger lineCount = [lines count];
CGPoint lineOrigins[lineCount];
CTFrameGetLineOrigins(frameRef, CFRangeMake(, ), lineOrigins);
int imgIndex = ;
CoreTextImgSource * imageData = arrayCoreTextImg[];
for (int i = ; i < lineCount; ++i) { CTLineRef line = (__bridge CTLineRef)lines[i];
NSArray * runObjArray = (NSArray *)CTLineGetGlyphRuns(line);
for (id runObj in runObjArray) {
CTRunRef run = (__bridge CTRunRef)runObj;
NSDictionary *runAttributes = (NSDictionary *)CTRunGetAttributes(run);
CTRunDelegateRef delegate = (__bridge CTRunDelegateRef)[runAttributes valueForKey:(id)kCTRunDelegateAttributeName];
if (delegate == nil) {///如果代理为空,则未找到设置的空白字符代理
continue;
} CoreTextImgSource * metaImgSource = CTRunDelegateGetRefCon(delegate);
if (![metaImgSource isKindOfClass:[CoreTextImgSource class]]) {
continue;
} CGRect runBounds;
CGFloat ascent;
CGFloat descent;
runBounds.size.width = CTRunGetTypographicBounds(run, CFRangeMake(, ), &ascent, &descent, NULL);
runBounds.size.height = ascent + descent; CGFloat xOffset = CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).location, NULL);
runBounds.origin.x = lineOrigins[i].x + xOffset;
runBounds.origin.y = lineOrigins[i].y;
runBounds.origin.y -= descent; CGPathRef pathRef = CTFrameGetPath(frameRef);
CGRect colRect = CGPathGetBoundingBox(pathRef); CGRect delegateBounds = CGRectOffset(runBounds, colRect.origin.x, colRect.origin.y); imageData.imagePosition = delegateBounds;
CoreTextImgSource *img = imageData;
[arrayImgData addObject:img];
imgIndex++;
if (imgIndex == arrayCoreTextImg.count) {
imageData = nil;
break;
} else {
imageData = arrayCoreTextImg[imgIndex];
}
} if (imgIndex == arrayCoreTextImg.count) {
break;
} } return arrayImgData; } ///获取属性字符串字典
+ (NSMutableDictionary *)wkj_attributes{
CGFloat fontSize = [BookThemeManager sharedManager].fontSize;
CTFontRef fontRef = CTFontCreateWithName((CFStringRef)@"ArialMT", fontSize, NULL);
///行间距
CGFloat lineSpacing = [BookThemeManager sharedManager].lineSpace;
///首行缩进
CGFloat firstLineHeadIndent = [BookThemeManager sharedManager].firstLineHeadIndent;
///段落间距
CGFloat paragraphSpacing = [BookThemeManager sharedManager].ParagraphSpacing;
//换行模式
CTLineBreakMode lineBreak = kCTLineBreakByCharWrapping;
const CFIndex kNumberOfSettings = ;
CTParagraphStyleSetting theSettings[kNumberOfSettings] = {
///行间距
{ kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof(CGFloat), &lineSpacing },
{ kCTParagraphStyleSpecifierMaximumLineSpacing, sizeof(CGFloat), &lineSpacing },
{ kCTParagraphStyleSpecifierMinimumLineSpacing, sizeof(CGFloat), &lineSpacing },
///首行缩进
{ kCTParagraphStyleSpecifierFirstLineHeadIndent, sizeof(CGFloat), &firstLineHeadIndent },
///换行模式
{ kCTParagraphStyleSpecifierLineBreakMode, sizeof(CTLineBreakMode), &lineBreak },
///段落间距
{ kCTParagraphStyleSpecifierParagraphSpacing, sizeof(CGFloat), &paragraphSpacing }
}; CTParagraphStyleRef theParagraphRef = CTParagraphStyleCreate(theSettings, kNumberOfSettings); UIColor * textColor = [BookThemeManager sharedManager].textColor; NSMutableDictionary * dict = [NSMutableDictionary dictionary];
dict[(id)kCTForegroundColorAttributeName] = (id)textColor.CGColor;
dict[(id)kCTFontAttributeName] = (__bridge id)fontRef;
dict[(id)kCTParagraphStyleAttributeName] = (__bridge id)theParagraphRef;
CFRelease(theParagraphRef);
CFRelease(fontRef);
return dict;
} ///根据一个章节的所有段落内容,来生成 AttributedString 包括图片
+ (NSAttributedString *)wkj_loadChapterParagraphArray:(NSArray *)arrayArray{ NSMutableAttributedString *resultAtt = [[NSMutableAttributedString alloc] init]; for (CoreTextParagraphSource *paragraph in arrayArray) {
if (paragraph.type == CoreTextSourceTypeTxt) {///文本
NSAttributedString *txtAtt = [self wkj_parseContentFromCoreTextParagraph:paragraph];
[resultAtt appendAttributedString:txtAtt];
}
else if (paragraph.type == CoreTextSourceTypeImage){///图片
paragraph.imgData.position = resultAtt.length;
NSAttributedString *imageAtt = [self wkj_parseImageFromCoreTextParagraph:paragraph];
[resultAtt appendAttributedString:imageAtt];
}
} return resultAtt;
} ///根据段落文本内容获取 AttributedString
+ (NSAttributedString *)wkj_parseContentFromCoreTextParagraph:(CoreTextParagraphSource *)paragraph{
NSMutableDictionary *attributes = [self wkj_attributes];
return [[NSAttributedString alloc] initWithString:paragraph.txtData.content attributes:attributes];
} /////根据段落图片内容获取 AttributedString 空白占位符
+ (NSAttributedString *)wkj_parseImageFromCoreTextParagraph:(CoreTextParagraphSource *)paragraph{ CTRunDelegateCallbacks callbacks;
memset(&callbacks, , sizeof(CTRunDelegateCallbacks));
callbacks.version = kCTRunDelegateVersion1;
callbacks.getAscent = ascentCallback;
callbacks.getDescent = descentCallback;
callbacks.getWidth = widthCallback;
CTRunDelegateRef delegate = CTRunDelegateCreate(&callbacks, (__bridge void *)(paragraph.imgData)); // 使用0xFFFC作为空白的占位符
unichar objectReplacementChar = 0xFFFC;
NSString * content = [NSString stringWithCharacters:&objectReplacementChar length:];
NSMutableDictionary * attributes = [self wkj_attributes];
// attributes[(id)kCTBackgroundColorAttributeName] = (id)[UIColor yellowColor].CGColor;
NSMutableAttributedString * space = [[NSMutableAttributedString alloc] initWithString:content attributes:attributes];
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)space, CFRangeMake(, ),
kCTRunDelegateAttributeName, delegate);
CFRelease(delegate);
return space;
} //+ (NSAttributedString *)wkj_NewlineAttributes{
// CTRunDelegateCallbacks callbacks;
// memset(&callbacks, 0, sizeof(CTRunDelegateCallbacks));
// callbacks.version = kCTRunDelegateVersion1;
// callbacks.getAscent = ascentCallback;
// callbacks.getDescent = descentCallback;
// callbacks.getWidth = widthCallback;
// CTRunDelegateRef delegate = CTRunDelegateCreate(&callbacks, (__bridge void *)(paragraph));
//
// // 使用0xFFFC作为空白的占位符
// unichar objectReplacementChar = 0xFFFC;
// NSString * content = [NSString stringWithCharacters:&objectReplacementChar length:1];
// NSMutableDictionary * attributes = [self wkj_attributes];
// // attributes[(id)kCTBackgroundColorAttributeName] = (id)[UIColor yellowColor].CGColor;
// NSMutableAttributedString * space = [[NSMutableAttributedString alloc] initWithString:content attributes:attributes];
// CFAttributedStringSetAttribute((CFMutableAttributedStringRef)space, CFRangeMake(0, 1),
// kCTRunDelegateAttributeName, delegate);
// CFRelease(delegate);
// return space;
//} static CGFloat ascentCallback(void *ref){
// return [(NSNumber*)[(__bridge NSDictionary*)ref objectForKey:@"height"] floatValue];
CoreTextImgSource *refP = (__bridge CoreTextImgSource *)ref;
return refP.height;
} static CGFloat descentCallback(void *ref){
return ;
} static CGFloat widthCallback(void* ref){
// return [(NSNumber*)[(__bridge NSDictionary*)ref objectForKey:@"width"] floatValue]; CoreTextImgSource *refP = (__bridge CoreTextImgSource *)ref;
return refP.width;
} @end

添加好CoreTextDataTools类之后,就可以通过 wkj_downloadBookImage 方法来下载图片;图片下载完之后,就可以对每页显示的内容区域进行分页;划线和涂色的一些方法在上一篇中已提到;

    ///获取测试数据源文件
NSString *path = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];
///获取该章所有段落内容
NSArray *arrayParagraphSource = [CoreTextSource arrayReaolveChapterHtmlDataWithFilePath:path];
///下载该章中的所有图片
[CoreTextDataTools wkj_downloadBookImage:arrayParagraphSource];
///根据一个章节的所有段落内容,来生成 AttributedString 包括图片
NSAttributedString *att = [CoreTextDataTools wkj_loadChapterParagraphArray:arrayParagraphSource];
///给章所有内容分页 返回 CoreTextDataModel 数组
NSArray *array = [CoreTextDataTools wkj_coreTextPaging:att textArea:CGRectMake(, , self.view.bounds.size.width - , self.view.bounds.size.heigh t- ) arrayParagraphSource:arrayParagraphSource];

4.效果

iOS-电子书开发 笔记的更多相关文章

  1. iOS开发笔记7:Text、UI交互细节、两个动画效果等

    Text主要总结UILabel.UITextField.UITextView.UIMenuController以及UIWebView/WKWebView相关的一些问题. UI细节主要总结界面交互开发中 ...

  2. 2011斯坦福大学iOS应用开发教程学习笔记(第一课)MVC.and.Introduction.to.Objective-C

    blog.csdn.net/totogo2010/article/details/8205810  目录(?)[-] 第一课名称 MVC and Introduction to Objective-C ...

  3. iOS开发笔记-两种单例模式的写法

    iOS开发笔记-两种单例模式的写法   单例模式是开发中最常用的写法之一,iOS的单例模式有两种官方写法,如下: 不使用GCD #import "ServiceManager.h" ...

  4. iOS开发笔记--什么时候调用layoutSubviews

    iOS开发笔记--什么时候调用layoutSubviews 分类: iOS2014-04-22 16:15 610人阅读 评论(0) 收藏 举报 今天在写程序时候遇见layoutSubviews触发时 ...

  5. IOS开发笔记(4)数据离线缓存与读取

    IOS开发笔记(4)数据离线缓存与读取 分类: IOS学习2012-12-06 16:30 7082人阅读 评论(0) 收藏 举报 iosiOSIOS 方法一:一般将服务器第一次返回的数据保存在沙盒里 ...

  6. IOS开发笔记 IOS如何访问通讯录

    IOS开发笔记  IOS如何访问通讯录 其实我是反对这类的需求,你说你读我的隐私,我肯定不愿意的. 幸好ios6.0 以后给了个权限控制.当打开app的时候你可以选择拒绝. 实现方法: [plain] ...

  7. 张高兴的 Xamarin.Forms 开发笔记:为 Android 与 iOS 引入 UWP 风格的汉堡菜单 ( MasterDetailPage )

    所谓 UWP 样式的汉堡菜单,我曾在"张高兴的 UWP 开发笔记:汉堡菜单进阶"里说过,也就是使用 Segoe MDL2 Assets 字体作为左侧 Icon,并且左侧使用填充颜色 ...

  8. 【Swift】iOS开发笔记(二)

    前言 这个系列主要是一些开发中遇到的坑记录分享,有助于初学者跨过这些坑,攒够 7 条发一篇. 声明  欢迎转载,但请保留文章原始出处:)  博客园:http://www.cnblogs.com 农民伯 ...

  9. 菜鸟手下的iOS开发笔记(swift)

    在阳春4月的一天晨会上,有一个老板和蔼的对他的一个菜鸟手下说:“你既然会Android,那你能不能开发iOS?” 不是说好的要外包的吗?内心跌宕,但是表面淡定的菜鸟手下弱弱的回道:“可以试试”. 第二 ...

  10. WWDC 2014 Session笔记 - iOS界面开发的大一统

    本文是我的 WWDC 2014 笔记 中的一篇,涉及的 Session 有 What's New in Cocoa Touch Building Adaptive Apps with UIKit Wh ...

随机推荐

  1. 51Nod 1004 n^n的末位数字(日常复习快速幂,莫名的有毒,卡mod值)

    1004 n^n的末位数字 题目来源: Author Ignatius.L (Hdu 1061) 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 给出一个整数N,输出 ...

  2. [bzoj3048] [Usaco2013 Jan]Cow Lineup

    一开始一脸懵逼.. 后来才想到维护一左一右俩指针l和r..表示[l,r]这段内不同种类的数字<=k+1种. 显然最左的.合法的l随着r的增加而不减. 顺便离散化,记一下各个种类数字出现的次数就可 ...

  3. [bzoj3203][Sdoi2013]保护出题人

    人生第一道三分?... 把进攻序列里的前i只僵尸看成一个点,横坐标是第i只僵尸到达的时间,纵坐标是这i只僵尸的血量总和..就是说植物必须在这段时间内输出这些伤害..那么单位时间的输出伤害就是斜率了. ...

  4. [bzoj1774] [Usaco2009 Dec]Toll 过路费

    Floyd神用法...设dis[i][j]表示i点到j点的最短路(只算边权),map[i][j]表示i到j最小费用 将n个点先按照点权排一下序...这样就可以比较方便的求出路径上最大点权了... 因为 ...

  5. ubuntu下使用nginx搭建流媒体服务器,实现视频点播

    首先我们看如何实现视频点播,视频点播支持flv文件及H264编码视频,ACC编码音频的mp4文件: 第一步,创建单独的目录(因为软件较多,容易混乱),下载需要的软件: 我们需要下载nginx,pcre ...

  6. [国嵌攻略][103][Linux内核模块基础]

    什么是内核模块 Linux内核的整体结构非常庞大,其中包含的组件也非常多,如何使用这些组件.一种方式是把所有的组件都编译进内核文件,即zImage或bzImage,但这样会导致一个问题,占用内存过多. ...

  7. light oj 1184 Marriage Media

    题目: You run a marriage media. You take some profiles for men and women, and your task is to arrange ...

  8. mybatis sql循环的使用

    foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有 item,index,collection,open,separator,close. ...

  9. removeClass()

    定义和用法 removeClass() 方法从被选元素移除一个或多个类. 注释:如果没有规定参数,则该方法将从被选元素中删除所有类. 语法 $(selector).removeClass(class) ...

  10. Lucene.net(4.8.0) 学习问题记录四: IndexWriter 索引的优化以及思考

    前言:目前自己在做使用Lucene.net和PanGu分词实现全文检索的工作,不过自己是把别人做好的项目进行迁移.因为项目整体要迁移到ASP.NET Core 2.0版本,而Lucene使用的版本是3 ...