下面就是小编给大家带来的iOS开发,谓词(NSPredicate)的用法:(一)基本用(共含8篇),希望大家喜欢阅读!同时,但愿您也能像本文投稿人“kelvin1323”一样,积极向本站投稿分享好文章。
在iOS开发中,系统提供了NSPredicate这个类给我们进行一些匹配、筛选操作,非常方便,
iOS开发,谓词(NSPredicate)的用法:(一)基本用
。在没有用这个类时,我们要获取两个数组中某些特定的元素时,需要写代码一一对比,但是使用了这个类,只需要三四行代码就够了。为了演示,先定义一个person类
.h文件
#import
.m文件
#import “Person.h”@implementation Person- (instancetype)initWithName:(NSString *)name Age:(NSInteger)age { if (self = [super init]) { _name = name; _age = age; } return self;}+ (Person *)personWithName:(NSString *)nsme Age:(NSInteger)age { Person *person = [[Person alloc] initWithName:nsme Age:age]; return person;}- (NSString *)description { return [NSString stringWithFormat:@“name = %@, age = %ld”,_name, _age];}@end
我在实现文件中重写了description方法,是为了一会在打印筛选结果时能打印出对象属性的值。
然后将person引入main文件中(为了方便演示,没有使用cocoa),创建出10个不同的person对象,并放进数组中。
// 创建出10个person对象,并加入数组 NSMutableArray *muArray = [NSMutableArray array]; for (int i = 0; i <10; i++) {Person *person = [Person personWithName:[NSString stringWithFormat:@“zhang%d”,i] Age:i];[muArray addObject:person]; } NSLog(@“muArray = %@”, muArray);
ok,准备工作完成,下边主角闪亮登场。
NSPredicate使用时主要分两步走:第一步,定义谓词语句;第二步,根据要求,选择不同的方法执行谓词语句。
首先,我们来定义一个谓词语句,在定义谓词语句时,顺便会介绍谓词的语法。
1)比较运算符
/**比较运算符 * >:大于 * <:小于 * >=:大于等于 * <=:小于等于 * =,==:等于 * !=,:不等于 * between:左边的表达式等于右边的表达式的值或者介于它们之间。右边是一个有两个指定上限和下限的数值的数列(指定顺序的数列)。比如,1 BETWEEN { 0 , 33 },或者$INPUT BETWEEN { $LOWER, $UPPER }。 **/ // 例子:年龄属性大于3岁,注意:键路径不能用单引号引起来,否则会报错 NSPredicate *predicate = [NSPredicate predicateWithFormat:@“age >3”];2)逻辑运算符
/**逻辑运算符 * and/&&:与 * or/||:或 * not/!:非 **/ // 例子:年龄大于三岁或名字叫“zhang1”的,注意:字符串的值需要用单引号引起来,否则会报错,错误信息是:this class is not key value coding-compliant for the key zhang1. NSPredicate *predicate = [NSPredicate predicateWithFormat:@“age >3 || name = 'zhang1'”];
3)关系运算符
/**关系操作 * ANY,SOME:指定下列表达式中的任意元素。比如,ANY children.age < 18。 * ALL:指定下列表达式中的所有元素。比如,ALL children.age < 18。 * NONE:指定下列表达式中没有的元素。比如,NONE children.age < 18。它在逻辑上等于NOT (ANY ...)。 * IN:等于SQL的IN操作,左边的表达必须出现在右边指定的集合中。比如,name IN { 'Ben', 'Melissa', 'Nick' }。 **/ // 例子:in关键字:左边的关键字里必须包含右边的集合的元素 NSPredicate *predicate = [NSPredicate predicateWithFormat:@“ name in {'zhang1','zhang4'}”];
4)数组操作
/**数组操作 * array[index]:指定数组中特定索引处的元素, * array[FIRST]:指定数组中的第一个元素。 * array[LAST]:指定数组中的最后一个元素。 * array[SIZE]:指定数组的大小。 **/
以上就是对谓词的定义,我们可以看出,我是主要使用了predicateWithFormat:这个类方法进行定义的。
下面进入第二步:执行谓词语句。
1)、过滤对象是数组:使用- (void)filterUsingPredicate:(NSPredicate *)predicate; 针对可变数组进行过滤,过滤掉可变数组中不符合条件的。- (NSArray *)filteredArrayUsingPredicate:(NSPredicate *)predicate; 针对不可变数组进行过滤,将符合条件的元素组成一个新数组进行返回
2)、对单个对象进行判断过滤使用:- (BOOL)evaluateWithObject:(id)object; 向谓词对象发送该方法,参数是过滤的对象。常见于和正则表达式配合使用。
下边分别示范上边的三种方法。
a)、- (void)filterUsingPredicate:(NSPredicate *)predicate; 针对可变数组进行过滤
// 1、创建出10个person对象,并加入数组 NSMutableArray *muArray = [NSMutableArray array]; for (int i = 0; i <10; i++) {Person *person = [Person personWithName:[NSString stringWithFormat:@“zhang%d”,i] Age:i];[muArray addObject:person]; } NSLog(@“muArray = %@”, muArray);
// 2、定义谓词语句:年龄属性大于3岁,注意:键路径不能用单引号引起来,否则会报错 NSPredicate *predicate = [NSPredicate predicateWithFormat:@“age >3”];
// 3、对可变数组进行过滤 [muArray filterUsingPredicate:predicate]; NSLog(@“可变数组过滤后的结果%@”, muArray);我们可以看到打印的结果是:
-06-17 11:58:23.126 NSPredicate[3183:277528] 可变数组过滤后的结果( “name = zhang4, age = 4”, “name = zhang5, age = 5”, “name = zhang6, age = 6”, “name = zhang7, age = 7”, “name = zhang8, age = 8”, “name = zhang9, age = 9”)
b)、- (NSArray *)filteredArrayUsingPredicate:(NSPredicate *)predicate; 针对不可变数组进行过滤,将符合条件的元素组成一个新数组进行返回。
// - (NSArray *)filteredArrayUsingPredicate:(NSPredicate *)predicate; 针对不可变数组进行过滤,将符合条件的元素组成一个新数组进行返回 NSArray *beforeFilterArray = [NSArray arrayWithArray:(NSArray *)muArray]; NSArray *afterFilterArray = [beforeFilterArray filteredArrayUsingPredicate:predicate]; NSLog(@“不可变数组过滤结果%@”, afterFilterArray);
我们可以看到打印结果是:
2015-06-17 11:58:23.126 NSPredicate[3183:277528] 不可变数组过滤结果( “name = zhang4, age = 4”, “name = zhang5, age = 5”, “name = zhang6, age = 6”, “name = zhang7, age = 7”, “name = zhang8, age = 8”, “name = zhang9, age = 9”)
c)、- (BOOL)evaluateWithObject:(id)object; 对数组中的每一个元素进行筛选
NSMutableArray *matchObjArray = [NSMutableArray array]; for (Person *item in muArray) {// A、判断是否满足条件// 判断语句:evaluateWithObject,符合过滤条件就返回yesif ([predicate evaluateWithObject:item]) { [matchObjArray addObject:item];} } NSLog(@“符合过滤条件的对象是:%@”, matchObjArray);
筛选结果是:
2015-06-17 11:58:23.125 NSPredicate[3183:277528] 符合过滤条件的对象是:( “name = zhang4, age = 4”, “name = zhang5, age = 5”, “name = zhang6, age = 6”, “name = zhang7, age = 7”, “name = zhang8, age = 8”, “name = zhang9, age = 9”)
小结:以上三种方法都可以执行谓词短语,如果是对数组元素进行过滤的话,我们使用:- (void)filterUsingPredicate:(NSPredicate *)predicate、- (NSArray *)filteredArrayUsingPredicate:(NSPredicate *)predicate;更方便,如果是只针对一个对象进行判断的话,使用- (BOOL)evaluateWithObject:(id)object; 更方便。
在上一篇中,我们聊了NSPredicate的基本用法:谓词的基本语法、谓词的定义和使用,在本篇中,我们聊聊NSPredicate和正则表达式的结合使用来进行表单内容的筛选。
我们常常遇到这种需求:要求用户输入的用户名必须是字母、密码必须是数字、判断用户输入的手机号是否合法等等。这些需求我们就可以使用NSPredicate和正则表达式来配合筛选了。
首先我们来说说正则表达式。正则表达式的语法非常复杂,对于一般的验证条件,我们可以在网上找到现成的表达式,拿来就能用,我展示一些常用的正则出来:
1.验证用户名和密码:(“^[a-zA-Z]\w{5,15}$”)正确格式:“[A-Z][a-z]_[0-9]”组成,并且第一个字必须为字母6~16位;2.验证电话号码:(“^(\\d{3,4}-)\\d{7,8}$”)正确格式:xxx/xxxx-xxxxxxx/xxxxxxxx;3.验证手机号码:“^1[3|4|5|7|8][0-9]\\d{8}$”;4.验证身份证号(15位或18位数字):“\\d{14}[[0-9],0-9xX]”;5.验证Email地址:(“^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\.\\w+([-.]\\w+)*$”);6.只能输入由数字和26个英文字母组成的字符串:(“^[A-Za-z0-9]+$”) ;7.整数或者小数:^[0-9]+([.]{0,1}[0-9]+){0,1}$8.只能输入数字:“^[0-9]*$”。9.只能输入n位的数字:“^\\d{n}$”。10.只能输入至少n位的数字:“^\\d{n,}$”。11.只能输入m~n位的数字:“^\\d{m,n}$”。12.只能输入零和非零开头的数字:“^(0|[1-9][0-9]*)$”。13.只能输入有两位小数的正实数:“^[0-9]+(.[0-9]{2})?$”。14.只能输入有1~3位小数的正实数:“^[0-9]+(\.[0-9]{1,3})?$”。15.只能输入非零的正整数:“^\+?[1-9][0-9]*$”。16.只能输入非零的负整数:“^\-[1-9][]0-9”*$。17.只能输入长度为3的字符:“^.{3}$”。18.只能输入由26个英文字母组成的字符串:“^[A-Za-z]+$”。19.只能输入由26个大写英文字母组成的字符串:“^[A-Z]+$”。20.只能输入由26个小写英文字母组成的字符串:“^[a-z]+$”。21.验证是否含有^%&',;=?$\“等字符:”[^%&',;=?$\x22]+“。22.只能输入汉字:”^[\u4e00-\u9fa5]{0,}$“。23.验证URL:”^([\\w-]+\.)+[\\w-]+(/[\\w-./?%&=]*)?$“。24.验证一年的12个月:”^(0?[1-9]|1[0-2])$“正确格式为:”01“~”09“和”10“~”12“。25.验证一个月的31天:”^((0?[1-9])|((1|2)[0-9])|30|31)$“正确格式为;”01“~”09“、”10“~”29“和“30”~“31”。26.获取日期正则表达式:\\d{4}[年|\-|\.]\\d{\1-\12}[月|\-|\.]\\d{\1-\31}日?评注:可用来匹配大多数年月日信息。27.匹配双字节字符(包括汉字在内):[^\x00-\xff]评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)28.匹配空白行的正则表达式:\n\s*\r评注:可以用来删除空白行29.匹配HTML标记的正则表达式:<(\S*?)[^>]*>.*?|<.*? />评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力30.匹配首尾空白字符的正则表达式:^\s*|\s*$评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式31.匹配网址URL的正则表达式:[a-zA-z]+://[^\s]*评注:网上流传的版本功能很有限,上面这个基本可以满足需求32.匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$评注:表单验证时很实用33.匹配腾讯QQ号:[1-9][0-9]\{4,\}评注:腾讯QQ号从10 000 开始34.匹配中国邮政编码:[1-9]\\d{5}(?!\d)评注:中国邮政编码为6位数字35.匹配ip地址:((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)。评注:提取ip地址时有用
如果验证条件更加复杂或者找不到想要的正则式,则可以参考这个地方,自己动手写一个出来:点击打开链接 。不过在使用之前,切记要先用工具测试一下,
上边说的是正则表达式,下边就说谓词如何与正则表达式联用。
在上一篇中我们介绍了谓词的语法,当谓词和正则联用时,我们就需要认识两个新的关键字:SELF、MATCHES。
self的意思是指代要验证的字符串本身,matches是一个字符串操作:表示匹配。我们用self+matches+正则表达式就可以拼接出一个谓词了。如:
// 判断字符串首字符是否为字母 NSString *string = @”wo“; // 1、准备正则式 NSString *regex = @”^[A-Za-z]*$“; // 只能是字母,不区分大小写 // 2、拼接谓词 NSPredicate *predicateRe1 = [NSPredicate predicateWithFormat:@”self matches %@“, regex]; // 3、匹配字符串 BOOL resualt = [predicateRe1 evaluateWithObject:string]; NSLog(@”匹配结果%d“, resualt);
打印的结果是:
2015-06-17 11:58:23.129 NSPredicate[3183:277528] 匹配结果1
表示字符串符合正则式的要求。
系统还给我们提供了一个类,共我们使用正则表达式:NSRegularExpression。这个类非常简单,不做过多描述,大家看下边的例子,进入方法的头文件中可以了解更多用法。
/**NSRegularExpression类和正则表达式联用 * * * **/ // 1、创建NSRegularExpression对象并指定正则表达式 // 由于NSRegularExpression需要一个nserror对象,所以要先创建出来 NSError *error; // 第一个参数是正则表达式,第二个参数是匹配操作的类型(枚举值),第三个是error的地址 NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:regex options:NSRegularExpressionCaseInsensitive error:&error]; // 如果没有错误,则进行正则匹配 if (!error) {NSRange range = NSMakeRange(0, string.length);// 第一个参数是要匹配的字符串,第二个参数是匹配操作的类型,第三个是要匹配字符串的范围// 建议进入头文件查看其他方法NSTextCheckingResult *match = [regularExpression firstMatchInString:stringoptions:NSMatchingReportProgress range:range];if (match) { NSLog(@”NSRegularExpression匹配成功“);} // 如果发生错误,打印错误类型 } else {NSLog(@”错误类型:%@“,error); }
打印的结果是:
2015-06-17 11:58:23.129 NSPredicate[3183:277528] NSRegularExpression匹配成功
ios中多线程有三种,NSTread, NSOperation,GCD
这篇就讲讲GCD的基本用法
平时比较多使用和看到的是:
复制代码
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//异步操作代码块
dispatch_async(dispatch_get_main_queue, ^{
//回到主线程操作代码块
});
});
复制代码
比较多的用于更新ui操作
比如从数据库获取数据需要花较长的时间,又不希望卡主线程,就把获取数据库数据操作放在异步操作代码快中,等获取结束,回调主线程,更新ui,在主线程操作代码块中进行操作
下面我们来解析一下这代码块中的每个方法:
复制代码
dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>)
表示异步操作,与之对应的是
dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>),同步操作,block中的代码执行完了才能执行后面的操作
方法中第一个参数 dispatch_queue_t queue 表示队列,无非是两种:串行和并行,另外可自建串行或并行队列
获取系统串行队列,也就是主线程串行队列:
dispatch_get_main_queue()
获取系统并行队列:
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
其中第一个参数,是队列优先级,有四种:
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
会根据优先级高低,进行处理
自建队列:
dispatch_queue_create(”com.example.serial“, NULL);
第一个参数,文档规范说:
A string label to attach to the queue.这个字符串需要唯一性,一般是以上形式呈现
第二个参数传NULL或者 DISPATCH_QUEUE_SERIAL 表示串行
传 DISPATCH_QUEUE_CONCURRENT表示并行
当执行结束,必须要有 dispatch_release(),将队列释放
复制代码
最近看到一篇文章讲到GCD, 比较深入,还有些没有理解,以上我描述的内容是GCD较为基础的用法,一般程序也就用到这些
前言:在iOS开发中,系统已经给我们提供了功能强大的控件,可是很多并不能满足我们的需求,这时候我们需要,自定义一些美观的控件。所用的知识也就是下面的绘图。
1.基本的绘图知识
1.1图形上下文
1.1图形上下文(Graphics Context):是一个CGContextRef类型的数据
1.2图形上下文的作用
保存绘图信息、绘图状态
决定绘制的输出目标(绘制到什么地方去?)
(输出目标可以是PDF文件、Bitmap或者显示器的窗口上)
1.2 - (void)drawRect:(CGRect)rect
作用:就是用来绘图 什么调用:当控件第一次显示的时候 rect:当前控件的bounds1.2 绘图的步骤
1.获得图形上下文:
CGContextRef ctx = UIGraphicsGetCurrentContext();
2.拼接路径
新建一个起点
void CGContextMoveToPoint(CGContextRef c, CGFloat x, CGFloat y)
添加新的线段到某个点
void CGContextAddLineToPoint(CGContextRef c, CGFloat x, CGFloat y)
添加一个矩形
void CGContextAddRect(CGContextRef c, CGRect rect)
添加一个椭圆
void CGContextAddEllipseInRect(CGContextRef context, CGRect rect)
添加一个圆弧
void CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y,
CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)
3.添加路径到上下文
Mode参数决定绘制的模式
void CGContextDrawPath(CGContextRef c, CGPathDrawingMode mode)
绘制空心路径
void CGContextStrokePath(CGContextRef c)
绘制实心路径
void CGContextFillPath(CGContextRef c)
提示:一般以CGContextDraw、CGContextStroke、CGContextFill开头的函数,都是用来绘制路径的
4.渲染到View上面
1.3 基本的绘图实例
1. 绘制线条
获得图形上下文:UIGraphicsGetCurrentContext()
拼接路径:UIBezierPath
添加路径到上下文CGContextAddPath(ctx, path.CGPath)
渲染到View上面CGContextStrokePath(ctx)
- (void)drawLine{ // 一个路径对象,可以对应多跟线 // 1.获取跟当前view想关联的上下文,系统自动帮我们创建的上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 设置上下文的状态,应该放在渲染之前就可以 // 创建对应颜色对象,调用set方法 [[UIColor redColor] set]; // 设置上下文的线宽 CGContextSetLineWidth(ctx, 15); // 设置线段的连接样式 CGContextSetLineJoin(ctx, kCGLineJoinRound); // 设置线段的端点样式 CGContextSetLineCap(ctx, kCGLineCapRound); // 2.拼接路径,UIBezierPath,封装好了一套很好使用的路径 UIBezierPath *path = [UIBezierPath bezierPath]; // 2.1 设置起点 [path moveToPoint:CGPointMake(10, 125)]; // 2.2 添加一根线到某个点 [path addLineToPoint:CGPointMake(220, 125)]; // 如果只使用一根路径,默认下一根线的起点在上一根跟线终点 [path addLineToPoint:CGPointMake(200, 150)]; // 3.添加路径到上下文 CGContextAddPath(ctx, path.CGPath); // 4.渲染到view上面的图层 CGContextStrokePath(ctx);}
2.绘制曲线
一般通过贝塞尔曲线来绘制图形:UIBezierPath
-(void)drawLIneQuadCurve{ // 1.获取上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.拼接路径 UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(10, 125)]; [path addQuadCurveToPoint:CGPointMake(240, 125) controlPoint:CGPointMake(125, 0)]; // 3.路径添加到上下文 CGContextAddPath(ctx, path.CGPath); // 4.渲染上下文 //以填充的方式渲染 //CGContextFillPath(ctx); CGContextStrokePath(ctx);}
3.绘制矩形
// 绘制矩形- (void)drawRect{ CGContextRef ctx = UIGraphicsGetCurrentContext(); UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 100, 100) cornerRadius:50]; CGContextAddPath(ctx, path.CGPath); // 设置填充的颜色 [[UIColor redColor] setFill]; [[UIColor greenColor] setStroke]; // 填充:必须封闭的路径 // 即描边又填充 // 如果以后只需要描边,最好不要使用fill CGContextDrawPath(ctx, kCGPathFillStroke); // CGContextFillPath(ctx); CGContextStrokePath(ctx);}
4.绘制圆弧
- (void)drawRect:(CGRect)rect { // 画圆弧 // center:圆心 // radius:半径 // clockwise:当前是 yes:顺时针 no:逆时针 CGPoint center = CGPointMake(125, 125); UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(125, 125) radius:100 startAngle:0 endAngle:-M_PI_2 clockwise:NO]; // 添加一根线到圆心 [path addLineToPoint:center]; // 关闭路径:从路径的终点到起点 // [path closePath]; // 填充,默认会关闭路径,从路径的终点到起点 [path fill];}
5.绘制文字
- (void)drawRect:(CGRect)rect{ //=========================绘制文字========================== NSString *name = @会长桂雏菊; // 描述文字的属性,颜色,字体大小 NSMutableDictionary *attr = [NSMutableDictionary dictionary]; // 字体 attr[NSFontAttributeName] = [UIFont systemFontOfSize:15]; // 颜色 attr[NSForegroundColorAttributeName] = [UIColor redColor]; // 边框颜色 attr[NSStrokeColorAttributeName] = [UIColor redColor]; // 边框宽度 attr[NSStrokeWidthAttributeName] = @1; // 阴影 NSShadow *shadow = [[NSShadow alloc] init]; shadow.shadowOffset = CGSizeMake(3, 3); shadow.shadowColor = [UIColor yellowColor]; shadow.shadowBlurRadius = 3; attr[NSShadowAttributeName] = shadow; [name drawInRect:CGRectMake(90, 100, 100, 50) withAttributes:attr];}
6.绘制饼状图
在初始化的时候时候,系统通过调用drawRect方法绘图。但是如果我们要重绘,手动调用drawRect方法是无效的。不过系统为我们准备了重绘的方法:
重绘:setNeedsDisplay
- (void)drawRect:(CGRect)rect { // Drawing code NSArray *datas = @[@25,@25,@50]; CGPoint center = CGPointMake(125, 125); CGFloat r = 100; CGFloat startA = 0; CGFloat angle = 0; CGFloat endA = 0; for (NSNumber *number in datas) { // 遍历一个数据,绘制一根扇形 startA = endA; angle = number.intValue / 100.0 * M_PI * 2; endA = startA + angle; // 描述圆弧 UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:r startAngle:startA endAngle:endA clockwise:YES]; [path addLineToPoint:center]; [[self randomColor] set]; [path fill]; }}//当点击View的时候,重绘- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ [self setNeedsDisplay];}//生成随机的颜色- (UIColor *)randomColor{ CGFloat r = arc4random_uniform(256) / 255.0; CGFloat g = arc4random_uniform(256) / 255.0; CGFloat b = arc4random_uniform(256) / 255.0; return [UIColor colorWithRed:r green:g blue:b alpha:1];}
7.上下文栈
将当前的上下文copy一份,保存到栈顶(那个栈叫做”图形上下文栈”):
void CGContextSaveGState(CGContextRef c)
将栈顶的上下文出栈,替换掉当前的上下文:
void CGContextRestoreGState(CGContextRef c)
- (void)drawRect:(CGRect)rect { // Drawing code // 1.获取上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.拼接路径 UIBezierPath *path = [UIBezierPath bezierPath]; // 横 [path moveToPoint:CGPointMake(10, 150)]; [path addLineToPoint:CGPointMake(290, 150)]; // 3.把路径添加到上下文 CGContextAddPath(ctx, path.CGPath); //================================================ // 保存上下文状态 CGContextSaveGState(ctx); //================================================ // 设置上下文的状态 CGContextSetLineWidth(ctx, 10); [[UIColor redColor] set]; // 4.渲染上下文,查看上下文的状态,根据状态去渲染 CGContextStrokePath(ctx); // 竖 path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(150, 10)]; [path addLineToPoint:CGPointMake(150, 290)]; // 3.把路径添加到上下文 CGContextAddPath(ctx, path.CGPath); // ============================================== // 从上下文状态栈里面取出保存的状态,替换掉当前的状态 CGContextRestoreGState(ctx); // ============================================= // 4.渲染上下文,查看上下文的状态,根据状态去渲染 CGContextStrokePath(ctx);}
8.上下文的平移,旋转,缩放
利用矩阵操作,能让绘制到上下文中的所有路径一起发生变化
缩放
void CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy)
旋转
void CGContextRotateCTM(CGContextRef c, CGFloat angle)
平移
void CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty)
- (void)drawRect:(CGRect)rect { // 获取上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 拼接路径 UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-100, -50, 200, 100)]; // 矩阵操作:必须要在添加路径之前进行形变 //平移上下文 CGContextTranslateCTM(ctx, 100, 100); // 旋转 CGContextRotateCTM(ctx, M_PI_4); // 缩放 CGContextScaleCTM(ctx, 0.5, 0.5); // 添加路径到上下文 CGContextAddPath(ctx, path.CGPath); // 渲染上下文 CGContextFillPath(ctx);}
9.图片加水印
1.开启一个基于位图的图形上下文
void UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale)
2.从上下文中取得图片(UIImage):
UIImage* UIGraphicsGetImageFromCurrentImageContext()
3.结束基于位图的图形上下文:
void UIGraphicsEndImageContext()
- (void)viewDidLoad {开启一个基于位图的图形上下文void UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale) [super viewDidLoad]; UIImage *image = [UIImage imageNamed:@hina]; // 创建位图上下文 UIGraphicsBeginImageContextWithOptions(image.size, NO, 0); [image drawAtPoint:CGPointZero]; // 文字 NSString *str = @会长桂雏菊; [str drawAtPoint:CGPointMake(0, 0) withAttributes:nil]; // 根据上下文的内容生成一张图片 image = UIGraphicsGetImageFromCurrentImageContext(); // 关闭上下文 UIGraphicsEndImageContext(); // 用来网络中传输图片 NSData *data = UIImagePNGRepresentation(image); [data writeToFile:@/Users/apple/Desktop/image.png atomically:YES];}
10.图片裁剪
1.将当前上下所绘制的路径裁剪出来(超出这个裁剪区域的都不能显示):
void CGContextClip(CGContextRef c)
思路分析
先画一个大圆,在设置裁剪区域,把图片画上去,超出裁剪区域的自动裁剪掉,
* 加载旧图片,根据旧图片,获取上下文尺寸。
* 确定圆环宽度 borderW
* 上下文的尺寸 = 新图片的尺寸
* 确定新的上下文尺寸: newImageW : oldImageW + 2 * borderW newImageH : oldImageH + 2 * borderW,
* 绘制大圆:
1.获取上下文 2.添加路径到上下文 3.设置大圆的颜色 = 圆环的颜色 4.渲染
* 设置裁剪区域,和图片尺寸一样大,只不过,x,y不一样,x=borderW,y=borderW.
* 绘制旧图片
* 获取新图片
* 关闭上下文
* 抽分类,3个参数,图片名称,圆环宽度,圆环颜色
+ (UIImage*)imageCircleWithImage:(UIImage *)image borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor{ // 设置圆环宽度 CGFloat boardW = borderWidth; CGFloat imageW = image.size.width + 2 * boardW; CGFloat imageH = image.size.height + 2 *boardW; // 只有正方形才能正切圆,选择一个最短的尺寸,正切。 CGFloat circleW = imageW >imageH ? imageH : imageW; CGRect rect = CGRectMake(0, 0, circleW, circleW); // 2.开启图像上下文 UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0); // 3。获取当前上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 4.画外圆 UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:rect]; CGContextAddPath(ctx, path.CGPath); [borderColor set]; CGContextFillPath(ctx); // 设置头像尺寸 rect = CGRectMake(boardW, boardW, image.size.width , image.size.height); // 5.创建裁剪路径 UIBezierPath *clipPath = [UIBezierPath bezierPathWithOvalInRect:rect]; // 6.裁剪路径 // 根据这个路径进行裁剪,超出路径以外的部分就不会显示了 [clipPath addClip]; // 7.画头像 [image drawInRect:rect]; // 不能直接在这返回,上下文没有关闭,会消耗内存. // 8.获取新图片 image = UIGraphicsGetImageFromCurrentImageContext(); // 9.关闭上下文 UIGraphicsEndImageContext(); return image;}
11.截取屏幕
View之所以能显示东西,完全是因为它内部的layer。View内部有个layer(图层)属性,drawRect:方法中取得的是一个Layer Graphics Context,因此,绘制的东西其实是绘制到view的layer上去了
- (void)renderInContext:(CGContextRef)ctx;
//截取屏幕+ (UIImage*)imageWithCaptureView:(UIView*)captureView;{ // 1.开启上下文 UIGraphicsBeginImageContextWithOptions(captureView.bounds.size, NO, 0.0); // 2.获取当前上下文 CGContextRef ctx = UIGraphicsGetCurrentContext(); // 3.把控制器图层渲染到上下文 [captureView.layer renderInContext:ctx]; // 4.取出新图片 UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage;}
SQLite3是嵌入在iOS中的关系型数据库,对于存储大规模的数据很有效,SQLite3使得不必将每个对象都加到内存中。
基本操作:
(1)打开或者创建数据库
sqlite3 *database;
intresult = sqlite3_open(”/path/databaseFile“, &database);
如果/path/databaseFile不存在,则创建它,否则打开它。如果result的值是SQLITE_OK,则表明我们的操作成功。
注意上述语句中数据库文件的地址字符串前面没有@字符,它是一个C字符串。将NSString字符串转成C字符串的方法是:
constchar*cString = [nsString UTF8String];
(2)关闭数据库
sqlite3_close(database);
(3)创建一个表格
char*errorMsg;
constchar*createSQL =”CREATE TABLE IF NOT EXISTS PEOPLE (ID INTEGER PRIMARY KEY AUTOINCREMENT, FIELD_DATA TEXT)“;
intresult = sqlite3_exec(database, createSQL, NULL, NULL, &errorMsg);
执行之后,如果result的值是SQLITE_OK,则表明执行成功;否则,错误信息存储在errorMsg中,
sqlite3_exec这个方法可以执行那些没有返回结果的操作,例如创建、插入、删除等。
(4)查询操作
NSString *query = @”SELECT ID, FIELD_DATA FROM FIELDS ORDER BY ROW“
一、一个简单的英雄展示程序
NJHero.h文件代码(字典转模型)
复制代码
1 #import
2
3 @interface NJHero : NSObject
4 /**
5 * 头像
6 */
7 @property (nonatomic, copy) NSString *icon;
8 /**
9 * 名称
10 */
11 @property (nonatomic, copy) NSString *name;
12 /**
13 * 描述
14 */
15 @property (nonatomic, copy) NSString *intro;
16
17 - (instancetype)initWithDict:(NSDictionary *)dict;
18 + (instancetype)heroWithDict:(NSDictionary *)dict;
19 @end
复制代码
NJViewController.m文件代码
复制代码
1 #import ”NJViewController.h“
2 #import ”NJHero.h“
3
4 @interface NJViewController
5 /**
6 * 保存所有的英雄数据
7 */
8 @property (nonatomic, strong) NSArray *heros;
9 @property (weak, nonatomic) IBOutlet UITableView *tableView;
10
11 @end
12
13 @implementation NJViewController
14
15 #pragma mark - 懒加载
16 - (NSArray *)heros
17 {
18 if (_heros == nil) {
19 // 1.获得全路径
20 NSString *fullPath = [[NSBundle mainBundle] pathForResource:@”heros“ ofType:@”plist"];
21 // 2.更具全路径加载数据
22 NSArray *dictArray = [NSArray arrayWithContentsOfFile:fullPath];
23 // 3.字典转模型
24 NSMutableArray *models = [NSMutableArray arrayWithCapacity:dictArray.count];
25 for (NSDictionary *dict in dictArray) {
26 NJHero *hero = [NJHero heroWithDict:dict];
27 [models addObject:hero];
28 }
29 // 4.赋值数据
30 _heros = [models copy];
31 }
32 // 4.返回数据
33 return _heros;
34 }
35
36 - (void)viewDidLoad
37 {
38 [super viewDidLoad];
39 // 设置Cell的高度
40 // 当每一行的cell高度一致的时候使用属性设置cell的高度
41 self.tableView.rowHeight = 60;
42 self.tableView.delegate = self;
43 }
44
45 #pragma mark - UITableViewDataSource
46 // 返回多少组
47 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
48 {
49 return 1;
50 }
51 // 返回每一组有多少行
52 - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
53 {
54 return self.heros.count;
55 }
56 // 返回哪一组的哪一行显示什么内容
57 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
58 {
59 // 1.创建CELL
60 UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle.:UITableViewCellStyleSubtitle reuseIdentifier:nil];
61 // 2.设置数据
62 // 2.1取出对应行的模型
63 NJHero *hero = self.heros[indexPath.row];
64 // 2.2赋值对应的数据
65 cell.textLabel.text = hero.name;
66 cell.detailTextLabel.text = hero.intro;
67 cell.imageView.image = [UIImage imageNamed:hero.icon];
68 // 3.返回cell
69 return cell;
70 }
71 #pragma mark - UITableViewDelegate
72 /*
73 // 当每一行的cell的高度不一致的时候就使用代理方法设置cell的高度
74 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
75 {
76 if (1 == indexPath.row) {
77 return 180;
78 }
79 return 44;
80 }
81 */
82
83 #pragma mark - 控制状态栏是否显示
84 /**
85 * 返回YES代表隐藏状态栏, NO相反
86 */
87 - (BOOL)prefersStatusBarHidden
88 {
89 return YES;
90 }
91 @end
复制代码
实现效果:
代码注意点:
(1)在字典转模型的代码处用下面的代码,为可变数组分配dictArray.count个存储空间,可以提高程序的性能
NSMutableArray *models = [NSMutableArrayarrayWithCapacity:dictArray.count];
IOS是目前最为流行、最热门的操作系统之一,在全球有着不可替代的地位,虽然在中国,android的市场占有率与IOS想比较要高的多,但是IOS系统的苹果手机在中国也属于高端品牌。从品牌以及系统技术含量做人就要做一个徘徊在牛A和牛C之间的人。上来看,IOS就业岗位都属于高端企业。而且基于IOS系统的app应用程序开发更是行业的旗帜。但由于我国IOS开发起步较晚,人才培养体系还跟不上市场的发展速度,IOS开发人才都成为我国企业必争的资源。在做人就要做一个徘徊在牛A和牛C之间的人。我们看来,目前很多企业都有收购的行为,其实被收购的公司并不是因为有技术秘方,也不是被收购的企业真的市值非常大,更不会因为品牌好,其实收购就是在于人才的收购。
IOS人才缺口大:据相关数据显示,目前我捐款就像发-情,一想起来马上就要。国IOS软件人才出现了接近四十万的缺口,而且未来几年呢IOS软件开发人才缺口将过百万。但是目前IOS最大的人才输出地也就是培训机构,远远无法满足,而大学有未开设IOS专业,因此IOS人才欠缺将是持久问只要功夫深,拉屎也认真啊!题。
IOS技术领先: 凡是IOS系统的智能设备,都属于苹果公司的终端设备,苹果公司在品牌营造上本身就是高端品牌。再看IOS系统开发中的开发语言是objective Cc,单从objective C只要功夫深,拉屎也认真啊!c来说,技能起点也相对较高,因此具有IOS平台开发经验的比其他的平台开发经验的技术水平要高很多。那么从IOS品牌的高端性和技术水平的要求来看都比同行业要高,自然在薪资待遇上也会相应的高很多,有数据显示工资就像例假,一月不来你就傻眼。,IOS开发从业者比同行其他平台的开发从业者待遇要平均高到20%-30%左右。
我国IOS就业前景自然不用说,开发岗位也非常的多,就app应用开发工程师、游戏开发工程师、测试工程师、UI设计师每个岗捐款就像发-情,一想起来马上就要。位都有大量的欠缺,当然人才只能从培训机构中补给,但是人才补给相对较慢。因此只要具备IOS相关的技能,拥有一定的项目实战经验之后,前途无量。也正因为企业及开发者看到了IOS的市场前景,大力推动IOS开发谈判就像口-交,费尽了口舌也就那点收获。行业,也使得越来越多的学子们加入了IOS培训行业,希望通过培训,让自己的发展起点更高。
[ios开发就业前景]
1.“省电,流畅,优质应用,响应速度快,用户体验好……”也许是众多用户眼中的苹果系统,
2.在众手机商拼CPU主频,拼4核,8核的年代,苹果依然坚持双核,iphone用户体验仍然坚挺。
以上两点IOS是如何优化,在续航,流畅度和响应速度上完胜安卓,答案就是多线程&RunLoop...
RunLoop是IOS事件响应与任务处理最核心机制,它贯穿IOS整个系统运作,
RunLoop不像一般的线程循环等待任务,传统的线程循环等待任务会导致CPU时间被占用,虽然你设置了睡眠时间,但很多时候会出现空转,
而RunLoop是监控事件触发处理机制,说白了,在有事件的时候CPU全力生产,当没有事件产生的时候,线程就挂起等待事件。
可以说,RunLoop是IOS比android省电,流畅,用户体验好的主要原因。