当前位置: 首页 > 编程日记 > 正文

TextKit及应用

在iOS开发中我们常常使用UIKit的UITextView、UITextField、UILabel来显示文字。它们底层都是基于一个叫做TextKit的强大引擎。通过TextKit,我们可以方便地修改文字的样式和排版,而不需要直接操作复杂的Core Text。

在这里插入图片描述

1.什么是TextKit

在iOS7中,苹果引入了Text Kit——一个快速而又现代化的文字排版和渲染引擎。Text Kit在UIKit framework中的定义了一些类和相关协议,它最主要的作用就是为程序提供文字排版和渲染的功能。通过Text Kit可以对文字进行存储(store)、布局(lay out),以及用最精细的排版方式(例如文字间距、换行和对齐等)来显示文本内容。
苹果引入Text Kit的目的并非要取代已有的Core Text,Core Text的主要作用也是用于文字的排版和渲染中,它是一种先进而又处于底层技术,如果我们需要将文本内容直接渲染到图形上下文(Graphics context)时,从性能和易用性来考虑,最佳方案就是使用Core Text。而如果我们直接利用苹果提供的一些控件(例如UITextView、UILabel和UITextField等)对文字进行排版,无疑就是借助于UIkit framework中Text Kit提供的API。

2.TextKit的作用

两个最重要的功能:

  1. 文字排版
  2. 文字渲染

3.TextKit中的类

要了解TextKit需要先了解其包含的几个类:

在这里插入图片描述

1.Text Storage(NSTextStorage):NSMutableAttributedString的子类,保存需要显示的文字和属性。
2.TextContainer(NSTextContainer):确定文字的布局区域。一般为矩形,但是可以创建NSTextContainer的子类来创建其它如圆形、五边形或不规则图形等。
3.Layout Manager(NSLayoutManager):负责根据NSTextContainer的布局信息渲染NSStorage中的文字。
4.TextView一般为UITextView等

TextKit是典型的MVC(model-view-controller )范例:

  1. Controller: NSLayoutManager。负责将NSTextStorage中的字符转换为文字符号,根据NSTextContainer对文字符号进行布局并显示到View中
  2. Model: NSTextStorage和NSTextContainer。前者保存有文字和对应的字体、颜色、大小等属性。后者保存了文字的绘制区域。
  3. View :UITextView或其它UIView的子类

一般情况下,一个NSTextStorage、NSLayoutManager、NSTextContainer为一一对应关系:
在这里插入图片描述

也可能有多个NSTextContainer:
在这里插入图片描述

或者是多个NSLayoutManager:
在这里插入图片描述

实际运用Demo1:高亮显示

效果:
在这里插入图片描述

  1. 新建HYHighlightTextStorage类,继承自NSTextStorage
  2. NSTextStorage的子类需要我们自己存储attributed string,在HYHighlightTextStorage中声明变量
NSMutableAttributedString *_mutableAttributedString;

并且重写以下4个抽象方法:

 - (NSString *)string;- (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range;- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str;- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range;
  1. 修改text storage的内容时,需要3个步骤:
    (1) 首先调用beginEditing方法。
    (2) 通过调用 replaceCharactersInRange:withString: 或 setAttributes:range: 改变字符或属性
    (3)修改完成后调用endEditing,此时会调用代理方法 textStorage:willProcessEditing:range:changeInLength: 以及processEditing方法。

完整代码:
HYHighlightTextStorage.h

@interface HYHighlightTextStorage : NSTextStorage@end

HYHighlightTextStorage.m

#import "HYHighlightTextStorage.h"@implementation HYHighlightTextStorage{NSMutableAttributedString *_mutableAttributedString;NSRegularExpression *_expression;
}-(instancetype)init{if (self = [super init]) {_mutableAttributedString = [[NSMutableAttributedString alloc] init];_expression = [NSRegularExpression regularExpressionWithPattern:@"(\\*\\w+(\\s*\\w+)*\\s*\\*)" options:0 error:NULL];}return self;
}- (NSString *)string{return _mutableAttributedString.string;
}- (NSDictionary<NSString *,id> *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range {return [_mutableAttributedString attributesAtIndex:location effectiveRange:range];
}- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str {[self beginEditing];[_mutableAttributedString replaceCharactersInRange:range withString:str];[self edited:NSTextStorageEditedCharacters range:range changeInLength:(NSInteger)str.length - (NSInteger)range.length];[self endEditing];
}- (void)setAttributes:(NSDictionary<NSString *,id> *)attrs range:(NSRange)range {[self beginEditing];[_mutableAttributedString setAttributes:attrs range:range];[self edited:NSTextStorageEditedAttributes range:range changeInLength:0];[self endEditing];
}- (void)processEditing {[super processEditing];//去除当前段落的颜色属性NSRange paragaphRange = [self.string paragraphRangeForRange: self.editedRange];[self removeAttribute:NSForegroundColorAttributeName range:paragaphRange];//根据正则匹配,添加新属性[_expression enumerateMatchesInString:self.string options:NSMatchingReportProgress range:paragaphRange usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {[self addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:result.range];}];
}

HYHighlightViewController.m

#import "HYHighlightViewController.h"
#import "HYHighlightTextStorage.h"@interface HYHighlightViewController ()@property (nonatomic, strong) UITextView *textView;
@property (nonatomic, strong) HYHighlightTextStorage *textStorage;
@property (nonatomic, strong) NSTextContainer *textContainer;
@property (nonatomic, strong) NSLayoutManager *layoutManager;@end@implementation HYHighlightViewController- (void)viewDidLoad {[super viewDidLoad];_textContainer = [[NSTextContainer alloc] init];_layoutManager = [[NSLayoutManager alloc] init];_textStorage = [[HYHighlightTextStorage alloc] init];[_textStorage addLayoutManager:_layoutManager];[_layoutManager addTextContainer:_textContainer];_textView = [[UITextView alloc] initWithFrame:CGRectMake(10, 100, self.view.bounds.size.width-20, 300) textContainer:_textContainer];_textView.backgroundColor = [UIColor lightGrayColor];[self.view addSubview:_textView];[_textStorage replaceCharactersInRange:NSMakeRange(0, 0) withString:@"星号引起来的字符都会被*高亮*,*hello world* 星号引起来的字符都会"];
}

实际运用Demo2:文本元素与非文本元素混排

效果:
在这里插入图片描述
通过设置NSTextContainer的exclusionPaths属性,可以设置禁止填充文字的区域。此属性为NSArray数组,包含的是一组UIBezierPath数据,表示所有排除路径。如图:

在这里插入图片描述

完整代码:

#import "HYExclusionViewController.h"@interface HYExclusionViewController ()@property (nonatomic, strong) UITextView *textView;
@property (nonatomic, strong) NSTextStorage *textStorage;
@property (nonatomic, strong) NSTextContainer *textContainer;
@property (nonatomic, strong) NSLayoutManager *layoutManager;
@property (nonatomic, strong) UIView *exclusionView;@end@implementation HYExclusionViewController- (void)viewDidLoad {[super viewDidLoad];_textContainer = [[NSTextContainer alloc] init];_layoutManager = [[NSLayoutManager alloc] init];_textStorage   = [[NSTextStorage alloc] init];[_textStorage addLayoutManager:_layoutManager];[_layoutManager addTextContainer:_textContainer];_textView = [[UITextView alloc] initWithFrame:CGRectZero textContainer:_textContainer];_textView.frame = CGRectMake(10, 100, self.view.bounds.size.width-20, 300);_textView.backgroundColor = [UIColor lightGrayColor];[self.view addSubview:_textView];NSString *testString = @"a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a";[_textStorage replaceCharactersInRange:NSMakeRange(0, 0) withString:testString];[self setupExclusion];
}-(void)setupExclusion{//红圆圈_exclusionView = [[UIView alloc] initWithFrame:CGRectMake(140, 40, 120, 120)];_exclusionView.backgroundColor = [UIColor redColor];_exclusionView.layer.cornerRadius = 60;[self.textView addSubview:_exclusionView];CGRect originalPathRect = self.exclusionView.frame;CGFloat circle_X = originalPathRect.origin.x - self.textView.textContainerInset.left;CGFloat circle_Y = originalPathRect.origin.y - self.textView.textContainerInset.top;CGFloat circle_W = originalPathRect.size.width;CGFloat circle_H = originalPathRect.size.height;CGRect circleRect = CGRectMake(circle_X, circle_Y, circle_W, circle_H);UIBezierPath *exclusionCirclePath = [UIBezierPath bezierPathWithOvalInRect:circleRect];_textContainer.exclusionPaths = @[exclusionCirclePath];
}

实际运用Demo3:不规则的显示区域

效果:
在这里插入图片描述
NSTextContainer确定了文字的布局区域,默认是矩形,新建HYCustomTextContainer继承自NSTextContainer,重写NSTextContainer的-(CGRect)lineFragmentRectForProposedRect: atIndex: writingDirection: remainingRect:方法,返回每一行文字的位置个大小,即可将显示区域修改成需要的形状,例如圆形。

#import "HYCustomTextContainer.h"@implementation HYCustomTextContainer-(CGRect)lineFragmentRectForProposedRect:(CGRect)proposedRect atIndex:(NSUInteger)characterIndex writingDirection:(NSWritingDirection)baseWritingDirection remainingRect:(CGRect *)remainingRect{[super lineFragmentRectForProposedRect:proposedRectatIndex:characterIndexwritingDirection:baseWritingDirectionremainingRect:remainingRect];CGSize size = [self size];//圆半径CGFloat radius = fmin(size.width, size.height) * 0.5;CGFloat y = proposedRect.origin.y;CGFloat height = proposedRect.size.height;CGFloat width = 0;if (proposedRect.origin.y == 0) {width = 40.0;}else if(proposedRect.origin.y <= 2*radius){width = 2 * sqrt(powf(radius,2.0) - powf(fabs(y-radius), 2.0));}CGFloat x = radius - width/2.0;return CGRectMake(x, y, width, height);
}@end

实际运用Demo4:可点击字符的UILabel

效果:
在这里插入图片描述

  1. 新建HYLabel继承自UILabel
  2. 在初始化方法中初始化内部的NSTextStorage、NSLayoutManager、NSTextContainer。
  3. 重写drawTextInRect:方法,让我们自己的NSTextContainer去替代默认的展示控件。
  4. 重写touchesBegan:withEvent:方法,进行点击判断。

完整代码HYLabel.m代码:

#import "HYLabel.h"@interface HYLabel()@property (nonatomic, strong) NSTextStorage *textStorage;
@property (nonatomic, strong) NSLayoutManager *layoutManager;
@property (nonatomic, strong) NSTextContainer *textContainer;@end@implementation HYLabel-(void)setText:(NSString *)text{[super setText:text];[self setupTextSystem];[self.textStorage replaceCharactersInRange:NSMakeRange(0, 0) withString:text];
}-(void)setAttributedText:(NSAttributedString *)attributedText{[super setAttributedText:attributedText];[self setupTextSystem];[self.textStorage replaceCharactersInRange:NSMakeRange(0, 0) withAttributedString:attributedText];
}-(instancetype)initWithFrame:(CGRect)frame{if (self = [super initWithFrame:frame]) {self.userInteractionEnabled = YES;[self setupTextSystem];}return self;
}-(void)setupTextSystem{_textStorage = [[NSTextStorage alloc] init];_layoutManager = [[NSLayoutManager alloc] init];_textContainer = [[NSTextContainer alloc] init];[_textStorage addLayoutManager:_layoutManager];[_layoutManager addTextContainer:_textContainer];
}-(void)drawTextInRect:(CGRect)rect{NSRange range = NSMakeRange(0, self.textStorage.length);[self.layoutManager drawBackgroundForGlyphRange:range atPoint:CGPointMake(0, 0)];[self.layoutManager drawGlyphsForGlyphRange:range atPoint:CGPointMake(0, 0)];
}-(void)layoutSubviews{[super layoutSubviews];self.textContainer.size = self.bounds.size;
}-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{UITouch *touch = touches.anyObject;CGPoint point = [touch locationInView:self];//获取点击的字的indexNSUInteger glyphIndex = [self.layoutManager glyphIndexForPoint:point inTextContainer:self.textContainer];//获取字的rectCGRect glyphRect = [self.layoutManager boundingRectForGlyphRange:NSMakeRange(glyphIndex, 1) inTextContainer:self.textContainer];//最后判断点击位置是否在该字的显示范围内if(CGRectContainsPoint(glyphRect, point)){NSUInteger charaterIndex = [self.layoutManager characterIndexForGlyphAtIndex:glyphIndex];unichar charater = [[self.textStorage string] characterAtIndex:charaterIndex];if ([self.delegate respondsToSelector:@selector(didClickCharater:)]) {[self.delegate didClickCharater:charater];}}
}@end

实际运用Demo5:一个比较有趣的demo

网上看到的一个比较有趣的demo:https://www.jianshu.com/p/e72c441f14f3

参考:
TextKit 探究:https://www.jianshu.com/p/3f445d7f44d6
TextKit框架:https://www.jianshu.com/p/a12ecae89d6b
Using Text Kit to Draw and Manage Text:https://developer.apple.com/library/archive/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/CustomTextProcessing/CustomTextProcessing.html#//apple_ref/doc/uid/TP40009542-CH4-SW1
TextKit Best Practices:https://developer.apple.com/videos/play/wwdc2018/221/

相关文章:

判断类之间的父子关系

如何判断两个类之间的父子关系&#xff1f; java为我们提供了instanceof运算符&#xff0c;可以用来判断一个对象是否是否个类的实例&#xff0c;所以很容易的想到子类的对象肯定是父类的实例。但是如何所涉及到的类是不可实例化的该怎么办呢&#xff1f;好在java的Class为我们…

顺F速运,你被爱加M坑了

“ 顺F速运APP安全性分析。”之前的文章《Wireshark分析实战&#xff1a;某达速递登录帐号密码提取》对某达速递的APP进行了分析&#xff0c;该APP将数据完全暴露于网络流量中。于是对快递行业老大顺F速运的APP进行了分析&#xff0c;发现该APP质量还算上乘&#xff0c;但是&am…

[大数据之Spark]——Actions算子操作入门实例

Actions reduce(func) Aggregate the elements of the dataset using a function func (which takes two arguments and returns one). The function should be commutative and associative so that it can be computed correctly in parallel. 这个方法会传入两个参数&#x…

Runloop总结

1.什么是Runloop Runloop字面上翻译就是运行循环&#xff0c;也就是一直在转圈圈运行着&#xff0c;类似于do…while()。我们思考一个问题&#xff1a; 一个线程执行完成后就会退出&#xff0c;当我们启动一个iOS APP时&#xff0c;系统会调用main.m文件的main()函数: int m…

Android拷贝工程不覆盖原工程的配置方法

http://www.2cto.com/kf/201203/125131.html 在Eclipse中改包名的时候选择refactor-->rename,勾选Rename subpackages,这样就不需要一个个修改每个类中导入的包名了转载于:https://www.cnblogs.com/leihupqrst/p/3670224.html

顺F速运国际版,你的密码漏点了

“ 对顺F旗下各APP顺藤摸瓜分析——顺F速运国际版。”前文《顺F速运&#xff0c;你被爱加M坑了》提到&#xff0c;顺F速运APP使用爱加密加壳&#xff0c;流量中传输内容被加密并BASE64编码了&#xff0c;只是安全性不够&#xff0c;壳没有将顺丰的加密算法及密钥保护好。秉承避…

利用Injection插件加快Xcode编译速度

我们在调试iOS原生代码时&#xff0c;每次修改都需要CommandR来重新编译运行。当项目代码量很大&#xff0c;编译时间就会很漫长。因此对于开发中来说&#xff0c;如果能加快编译速度&#xff0c;能大大提高生产效率。如果我们能像Swift Playground、小程序或网页那样修改代码后…

存储过程的优缺点 (转载)

为什么要用存储过程 几个去 IBM 面试的兄弟回来抱怨&#xff1a;去了好几个不同的 IBM 项目组&#xff0c;几乎每个面试官问到数据库的时候都要问用没用过存储过程&#xff0c;烦人不&#xff1f;大家去面的程序员&#xff0c;又不是 DBA&#xff0c;以前的项目都没有用到存储…

计算机知识的学习

我不是计算机科班出生&#xff01; 大学里喜欢跟医电系的人混在一起&#xff0c;受到他们影响较多&#xff0c;开始喜欢上计算机&#xff01;win 98 Office 97 他们有的擅长C、有的擅长Flash、还有哥们喜欢硬件&#xff01; 西安的东六路是图书批发市场&#xff0c;我几乎每周…

Wireshark小技巧:将IP显示为域名

“ 本文介绍如何使Wireshark报文窗口的Source栏及Destination内的IP直接显示为域名&#xff0c;提升报文分析效率。” 一个典型的Wireshark界面如下&#xff1a; 从这个图里&#xff0c;能看到源IP及目的IP&#xff0c;在流量不大&#xff0c;数据不多的情况下&#xff0c;我…

个人学习某个系统或平台的3问式的整理和细化指引

i:三问&#xff1a;是什么&#xff1f;为什么&#xff1f;怎么样&#xff1f; ii:详细化问题指引&#xff1a;是什么的目的在于确定系统的大致范围&#xff0c;明确目标&#xff1a;->平台的主要功能是什么&#xff1f;业务流程是怎样的&#xff1f;业务范围有多大&#xff…

给iOS开发者的React Native入门使用教程

目录一. 原生iOS项目集成React Native二. 原生跳转RN页面三. 显示豆瓣热门电影列表四. 改为导航五.完整源代码一. 原生iOS项目集成React Native 创建一个新的文件夹&#xff0c;如RNProject&#xff0c;然后新建一个/ios的子文件夹&#xff0c;将已有的iOS项目全部文件复制进去…

PHP Memcached应用实现代码

肖理达 (KrazyNio AT hotmail.com), 2006.04. 06, 转载请注明出处 一、memcached 简介 在很多场合&#xff0c;我们都会听到 memcached 这个名字&#xff0c;但很多同学只是听过&#xff0c;并没有用过或实际了解过&#xff0c;只知道它是一个很不错的东东。这里简单介绍一下&a…

顺F分享,你是在裸奔吗?

“ 对顺F旗下各APP顺藤摸瓜分析——顺F分享。”前文对顺F速运和顺F速运国际版进行了分析&#xff0c;二者使用同一套接口&#xff0c;虽然保护强度不高&#xff0c;但对代码和数据的保护却区别对待&#xff0c;实在让人诧异。秉承避免浪费的原则&#xff0c;我们将持续对顺F旗下…

静态链接库与动态链接库 (二)动态链接库的编译与使用

上一篇文章里大概描述linux下静态链接库的编译与使用&#xff0c;下面讲动态链接库的编译与使用方法。 1. 什么是动态链接库 所谓动态链接库&#xff0c;是指编译的时候不会把程序引用到的库插入到执行程序里&#xff0c;而是在执行时候才会去加载相关的库&#xff0c;所有用到…

【React Native】react-navigation导航使用方法

目录集成react-navigation使用react-navigation上一篇介绍了如何在已有iOS项目中集成React Native。这一篇我们把上一篇的demo做下拓展&#xff0c;添加点击电影跳转到详情页。页面跳转使用React Native推荐的第三方导航控件&#xff1a;react-navigation 集成react-navigatio…

请说明在.net中常用的几种页面间传递参数的方法,并说出他们的优缺点。

QueryString 传递一个或多个安全性要求不高或是结构简单的数值。但是对于传递数组或对象的话&#xff0c;就不能用这个方法了 session(viewstate) 简单&#xff0c;但易丢失 作用于用户个人,过量的存储会导致服务器内存资源的耗尽。 application 对象的作用范围是整个全局&am…

邮Z速递物流,让用户密码在网络中遨游

“ 最近分析快递行业的APP上瘾了&#xff0c;求解救。”邮政作为快递行业一个傻大黑的存在&#xff0c;一直很奇怪&#xff0c;我一直在纳闷&#xff0c;邮政和EMS到底是不是一家&#xff0c;在很多网点&#xff0c;它们是一体的存在&#xff0c;但很多东西&#xff0c;又是各自…

servlet response 中文乱码

先&#xff0c;response返回有两种&#xff0c;一种是字节流outputstream&#xff0c;一种是字符流printwrite。 申明&#xff1a;这里为了方便起见&#xff0c;所有输出都统一用UTF-8编码。 先说字节流&#xff0c;要输出“中国"&#xff0c;给输出流的必须是转换为utf-8…

【React Native】iOS原生导航跳转RN页面

上一篇介绍了React Native使用react-navigation进行导航跳转页面&#xff0c;现在我们介绍下原生iOS中怎么导航进一个新的React Native页面。 一、原生跳转React Native 创建HYReactNativeManager管理类. 在HYReactNativeManager.h中声明实现声明RCTBridgeDelegate协议&…

mac 常用指令

苹果公司生产的Mac搭载OS x 系统&#xff0c;OS x基于Unix&#xff0c;所以很多指令都和linux大同小异。 以下是一些常用指令&#xff0c;一点点自己记录下&#xff0c;方便自己和他人。这篇文应该是长期更新的。 1.ls [选项] [目录名] 第一个当然是list 指令 列出目录的文件列…

如何高效地爬取链家的房源信息(一)

“Python实现的链家网站的爬虫第一部分。”在之前的文章&#xff0c;以链家成都站为例&#xff0c;分析过链家网站数据的爬取&#xff0c;文章如下&#xff1a;干货&#xff01;链家二手房数据抓取及内容解析要点但是&#xff0c;当时没有根据分析&#xff0c;将爬取实现。本系…

HDU5886 Tower Defence 【两遍树形dp】【最长链预处理】

题意&#xff1a;N个点的一棵带权树。切掉某条边的价值为切后两树直径中的最大值。求各个边切掉后的价值和&#xff08;共N-1项&#xff09;。 解法一&#xff1a; 强行两遍dp&#xff0c;思路繁琐&#xff0c;维护东西较多&#xff1a; dis表示以i为根的子树的直径&#xff0c…

NPOI读取Excel数据应用

NPOI 是 POI 项目的 .NET 版本。使用 NPOI 你就可以在没有安装 Office 或者相应环境的机器上对 WORD/EXCEL 文档进行读写。NPOI是构建在POI 3.x版本之上的&#xff0c;它可以在没有安装Office的情况下对Word/Excel文档进行读写操作。 需求&#xff1a;根据excel表格提供的SVN相…

pod setup慢的解决方法

最近使用pod setup更新CocoaPods本地检索库&#xff0c;无奈只有10几k&#xff0c;还中途报错。最终通过以下步骤&#xff0c;完成更新。 1.手动下载Specs检索库 执行pod setup后&#xff0c;实质是从github上clone检索库&#xff08;https://github.com/CocoaPods/Specs&…

如何高效地爬取链家的房源信息(二)

“Python实现的链家网站的爬虫第二部分。”本系列文将以链家南京站为例&#xff0c;使用Python实现链家二手房源信息的爬虫&#xff0c;将数据爬取&#xff0c;并存入数据库中&#xff0c;以便使用。本系列第一部分&#xff1a;如何高效地爬取链家的房源信息&#xff08;一&…

C#实现HttpPost提交文件

先建立一个WebApplication Web.config <?xml version"1.0" encoding"utf-8"?><configuration><system.web><!--<globalization requestEncoding"gb2312" responseEncoding"gb2312" fileEncoding"gb231…

16年10月18号2th运算符与流程结构

---恢复内容开始--- 2th: 一&#xff1a;运算符 算数运算符 - * / %取余 9%30 自增 --自减 关系运算符 < < > > 全等于 !不等于 逻辑运算符 & | &#xff01;非 ^异或 &&短路与 || 短路或 赋值…

通用的排序按钮

排序按钮&#xff0c;使用Core Graphic绘制&#xff0c;可以指定颜色、大小、字体等&#xff1a; 使用场景如下&#xff1a; 1.使用方法 下载demo代码。将HYRankView.h和HYRankView.m代码拖入工程。 然后使用如下代码&#xff0c;即可快速添加一个名称为价格的排序按钮 HYR…

如何高效地爬取链家的房源信息(三)

“Python实现的链家网站的爬虫第三部分。”本系列文将以链家南京站为例&#xff0c;使用Python实现链家二手房源信息的爬虫&#xff0c;将数据爬取&#xff0c;并存入数据库中&#xff0c;以便使用。本系列第一部分为基础&#xff1a;如何高效地爬取链家的房源信息&#xff08;…