分类目录归档:iOS

iOS开发入门和提高::::::演道网IOS专栏提供一线IOS研发人员在工作学习过程中的经验总结。让大家少走弯路。

ios内存管理很简单

作者QQ:415074476

QQ群:191280586

Ios内存篇
引用计数
+alloc和-copy生成的对象retain计数值为1
-retain增加 retain计数
-release减少 retain计数
当retain计数减为0时,对象被释放.
-dealloc将被调用.(具体调用时间由系统决定)
一旦dealloc方法被调用,对象就直接释放了,原则上是不允许程序员调用的..

代码1:
implementation persion
{

-(NSString *)name{
return name;
}

-(void)setName:(NSString *)newName{
name = newName;
}
}
问题:name = newName,相当于只是给newName指向的对象增加了一个别名为name,并没有增加retain.
只有创建和复制时,对象的retain数值为1.之后也只能通过retain和release方法来改变retain计数.

代码2:
-(void)setName:(NSString *)newName{

if(name)
{
[name release];//先把之前引用的对象retain减一
}
else
{
name = [newName retain];//再增加当前指向对象的retain
}
}

代码3:
-(void)setName:(NSString *)newName{
if(name)
{
[name release];//先把之前引用的对象retain减一
}
else
{
name = [newName copy];//实际上内容还是使用的retain方法@@
}
}

代码2和代码3都能工作.他们的区别是什么呢?
简单来说:
retain只是把原有对象引用数增1.
字面上看来,Copy是复制原来的对象数据,生成了一个全新的对象.原来的对象retain不变.新对象retain为1.实际上这信赖于copy方法的具体实现,对于不可变对象来说,复制的只是一个指针而已,效果同retain.

由于NSString对象是不可变对象,代码2和代码3实际上就是一样的.

Property 本身的属性
• 只读与读写均可
@property int age; // 默认读写均可
@property (readonly) BOOL canLegallyVote;
• 内存管理策略(仅针对对象property)
@property (assign) NSString *name; // 指针赋值
@property (retain) NSString *name; // 调用retain
@property (copy) NSString *name; // 调用copy
• 不同于默认的setter/getter方法
@property (getter=getAge, setter=setAge) int age;

点语法使用注意:
@implementation Person
– (void)doSomething {
name = @”Fred”; // 直接访问实例变量!
self.name = @”Fred”; // 调用访问方法

}

例子:
@interface Test
{
NSString *name;
}
@property(retain) NSString *name;
-(id)initWithName: (NSString *)_name;

@end

@implementation Test
-(id)initWithName: (NSString *)_name
{
if (self == [super init])
{

name = name;//1错误,引用计数没有加1,有风险.
name = [_name retain];//2正确
self.name = _name;//3正确
[self SetName: _name];//4正确
}
}

-(void)resetName: (NSString *)_newName
{
name = name;//1错误,引用计数没有加1,有风险.
name = [_name retain];//2错误,之前持有的对象没有release
self.name = _name;//3正确
[self SetName: _name];//4正确

}
-(void)dealloc
{
[name release];
[super dealloc];
}
@end

总结,定义了property的属性,建议用点语法

Autorelease的使用.
在函数中返回的对象要使用autorelease
-(NSString *)testLocalVariable
{
NSString *dd = [[NSString alloc] initWithString:@”this is dd”];
NSString *str = [[[NSString alloc] initWithFormat:@”%@”,dd] autorelease];//这里要注意.一定得用autorelease
[dd release];
return str;
}

可以想像代码调用处会是这样的:
NSString *test = [self testLocalVariable];
根据前面的规则,通过alloc,copy,retain调用的对象才应该调用release来降低retain计数.
所以test对象是不应该管理的.
但函数内部又不能release,否则返回的对象就是无意义的对象,故只能打上autorelease 标记,由@autoreleasepool来管理

在Iphone项目中,大家会看到一个默认的Autorelease pool,程序开始时创建,程序退出时销毁,按照对Autorelease的理解,岂不是所有autorelease pool里的对象在程序退出时才release, 这样跟内存泄露有什么区别?
答案是,对于每一个Runloop, 系统会隐式创建一个Autorelease pool,这样所有的release pool会构成一个象CallStack一样的一个栈式结构,在每一个Runloop结束时,当前栈顶的Autorelease pool会被销毁,这样这个pool里的每个Object会被release。
那什么是一个Runloop呢? 一个UI事件,Timer call, delegate call, 都会是一个新的Runloop。例子如下:
NSString* globalObject;
– (void)applicationDidFinishLaunching:(UIApplication *)application
{
globalObject = [[NSString alloc] initWithFormat:@”Test”];
NSLog(@”Retain count after create: %d”, [globalObject retainCount]); // output 1.
[globalObject retain];
NSLog(@”Retain count after retain: %d”, [globalObject retainCount]); // output 2.
}
– (void)applicationWillTerminate:(UIApplication *)application
{
NSLog(@”Retain count after Button click runloop finished: %d”, [globalObject retainCount]);
// 输出1. Button click loop finished, it’s autorelease pool released, globalObject get released once.
}
-(IBAction)onButtonClicked
{
[globalObject autorelease];
NSLog(@”Retain count after autorelease: %d”, [globalObject retainCount]);
// 输出2。 Autorelease被call, globalObject被加如当前的AutoreleaePool。
}

ios 日期时间的使用

作者QQ:415074476

QQ群:191280586

1.工作中遇到的问题:

NSString *dateStr = @"Fri Dec 03 18:30:01 +0800 2010";
NSDateFormatter *dateformatter=[[NSDateFormatter alloc] init];
[dateformatter setDateFormat:@"EEE MMM dd HH:mm:ss zzz yyyy"];

NSDate *date = [dateformatter dateFromString:dateStr];
[dateformatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

NSString *dateString = [dateformatter stringFromDate:date];
NSLog(@"%@",dateString);

这段代码 在真机上打印不出“dateString”,而在模拟器上可以打印出来,真机的系统是IOS5.0,
解决办法如下:

    [dateformatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];

2.关于setTimeZone

从字符串转换成日期
setTimeZone 是指定字符串当前使用的时区
从日期转换成字符串
setTimeZone 是指要转换成目标字符串使用的时区

 

3.时间API使用总结:

 

1.使用NSDate获取时间

2.使用NSDateFormatter做时间格式的转换

3.需要使用时分秒等信息时,先获得NSDate,再使用NSDateComponents解析NSDate.

NSDate * startDate = [[NSDate alloc] init];

NSCalendar * chineseCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSUInteger unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit |

NSSecondCalendarUnit | NSDayCalendarUnit  |

NSMonthCalendarUnit | NSYearCalendarUnit;

NSDateComponents * cps = [chineseCalendar components:unitFlags fromDate:startDate];

NSUInteger hour = [cps hour];

NSUInteger minute = [cps minute];

!importance: 千万不要通过字符串截取的方式.因为NSDate永远是返回格式威治时区的时间, 而NSDateComponents解析时,会把时区再转成本地时区.

Ios splash设计

作者QQ:415074476

QQ群:191280586

Ios  splash设计

一.最简单的是放一个default.png

也可以在plist 中指定一个文件名.

Key为Launch image(iPhone)和Launch image(iPad)

 

二.动画实现.

又分为两种.

一种是UIView层面的,

一种是使用CATransition进行更低层次的控制

 

UIView代码示例:

[code]

[UIView beginAnimations:@”Curl”context:nil];//动画开始

[UIView setAnimationDuration:0.75];

[UIView setAnimationDelegate:self];

[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:myview cache:YES]; //动画转化在这里定义,关键字CurlUp

[myview removeFromSuperview];

[UIView commitAnimations];

[/code]

 

 

CATransition 代码示例:

[code]

CATransition *animation = [CATransition animation];

[animation setDuration:1.25f];

[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];

[animation setType:kCATransitionReveal]; //动作定义

[animation setSubtype: kCATransitionFromBottom];//方向定义

[self.view.layer addAnimation:animation forKey:@”Reveal”];

[/code]

这里使用了setType与setSubtype组合,这使用个比较保险,因为他的参数就是官方API里定义的,他们的参数说明可以参考如下:

 

[animation setType:@”suckEffect”];

这里的suckEffect就是效果名称,可以用的效果主要有:

pageCurl 向上翻一页

pageUnCurl 向下翻一页

rippleEffect 滴水效果

suckEffect 收缩效果,如一块布被抽走

cube 立方体效果

oglFlip 上下翻转效果

 

除了以上效果.还可以自定义效果.

 

 

CGAffineTransformMakeRotation();//旋转

CGAffineTransformMakeScale();//缩放

CGAffineTransformMakeTranslation ();//位移

CGAffineTransformMake(CGFloat a,

CGFloat b,

CGFloat c,

CGFloat d,

CGFloat tx,

CGFloat ty);//自定义变换.自己提供坐标系转换参数

设原坐标点为(x,y);

新坐标点为(x1,y1);

则有下面的对应关系:

x1 = ax+cy+dx;

y1 = bx+dy+dy;

 

问题:如何把动画应用到splash中.

 

第一种:在loadView中实现.

分两层,1是splash图片,一个是主场景.

先把主场景隐藏起来.

两个动画:

1.动画过程1把splash图片隐藏掉.即alpha=0.0

在setAnimationDidStopSelector指定新动画过程2

CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@”opacity”];
[scaleAnimation setDuration:0.3];
[scaleAnimation setFromValue: [NSNumber numberWithDouble:0.0]];
[scaleAnimation setToValue: [NSNumber numberWithDouble:1.0]];
[scaleAnimation setFillMode:kCAFillModeForwards];
[scaleAnimation setRemovedOnCompletion:NO];
[iCityItem.btnDelete.layer addAnimation:scaleAnimation forKey:@”opacity”];

[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:0.05] forKey:kCATransactionAnimationDuration];
[CATransaction setValue:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn] forKey:kCATransactionAnimationTimingFunction];
[CATransaction setCompletionBlock:^{
[self performSelector:@selector(fadout)];
}];
middleLayer.transform = [self getTransformSkew:70];
topLayer.transform = [self getTransformSkew:85];
middleLayer.opacity=0.1;
topLayer.opacity=0.1;

[CATransaction commit];

2.动画过程2把主场景展示出来

 

第二种:在application:didFinishLaunchingWithOptions方法中实现.

1.加载splash图片

2. 延迟加载主过程

3.在主过程中调用动画..

关键在于延迟调用

[self performSelector:@selector(loadMain) withObject:nil afterDelay:0.1f];

 

 

 

 

视图的几种创建方式

Interface builder介绍

构建视图的三种方式:

1.用objective-c手动构建GUI,使用loadView创建主视图,添加其界面元素

2.通过interface Builder,使用可视编辑器布局界面元素.

基于xib的视图控制器在从.xib文件中加载预先构建的界面后,在viewDidLoad中完成自身设置.

3.混合模式.

又分两种类型:

a..xib文件的静态加载

无论何时xcode找到名称与UIViewController派生出的类相匹配的.xib文件,它在初始化实例时都会自动加载该.xib文件.

b.编程式动态加载

通过直接使用objective-c命令加载.xib文件.如initWithNibName: bundle

 

1.手动创建

a覆盖-loadView (Never call this directly)

b生成你的视图

c设置view property

d使用-init生成视图控制器

// UIViewController的子类 步骤a

  • (void)loadView

{

//步骤b

MyView *myView = [[MyView alloc] initWithFrame:frame];

//步骤c

self.view = myView; // 视图控制器现在拥有这个视图

[myView release];

}

 

 

使用interface builder 是个比较快捷的方式.下面着重介绍

 

表示视图控制器.这个是一个抽象类,它的图标被称为代理,因为它虽然在IB中起到一定的作用,但是对象本身并没有嵌入到.xib归档中.

每个视图控制器都有一个称作”view”的实例变量,该变量被设为某个UIView,负责提供实际的屏幕显示.所以,对于视图控制器,File’s Owner代理表示加载并拥有.xib的对象.

 

Outlet是实例变量在IB中的表示.

 

,代理对象,表示当前响应用户触摸屏幕上的对象.在应用程序生命周期内,First Responder 在用户与屏幕交互时变化.例如,假设有一个表单.当用户触摸表单中的某个文本域时,那个文本域将成为活动文本域,并担当First Responder的角色.

 

提供实际的屏幕显示,即为上文本中所指File’s Owner实例变量”view”所对象的UIView

 

 

重点是viewCtroller中的view需要加上IBOutlet,这样才可以与view做连接.

 

 

附录:

做iphone开发就需要接触其中的xib文件。Interface Builder(IB)是Mac OS X平台下用于设计和测试用户界面(GUI)的应用程序,可以很直观的设计图形界面。实际上Mac OS X下所有的用户界面元素都可以使用代码直接生成;但IB能够使开发者简单快捷的开发出符合Mac OS X human-interface guidelines的GUI。通常你只需要通过简单的拖拽(drag-n-drop)操作来构建GUI就可以了。

IB使用Nib文件储存GUI资源,同时适用于Cocoa和Carbon程序。在需要的时候,Nib文件可以被快速地载入内存。

这里介绍一下ib相关的一点小技巧。

 

将XIB文件转换为Objective-C源程序

 

nib2objc是一个小巧的转换工具,可以将XIB文件自动转换为Objective-C的源代码文件。

 

通常,考虑到程序的效率时,才将XIB直接转换为源代码文件。但是这样一来,通过Interface Builder设定的实例变量与行为方法的接续也没有了,需要重新手写。但是,该工具的源代码是公开的,稍加修饰,就能完成大部分工作。

 

使用的时候,首先下载的工程代码并用XCode编译一下,会生成一个命令行程序文件 nib2objc。然后如下所示执行转换:

$ nib2objc testnib2objc.xib > testnib2objc.m

这样就可以转换成代码。

附下载地址: https://github.com/akosma/nib2objc/downloads

 

Ibtool是一个nib资源文件本地化的小工具:

1.从nib文件里面提取可以被本地化的字符串。 可以通过如下的命令在终端里面处理:

ibtool –generate-stringsfile MyNib.strings MyNib.nib

2.等翻译好了字符串以后,就需要通过ibtool去把字符串合并到.nib文件里面去。 具体的命令如下:

ibtool –strings-file MyNib.strings –write MyNewNib.nib MyNib.nib

其中MyNib.nib是你想修改的xib文件。

 

实例演战:如何建立window-base application

在xcode 4.2之前是有个window-based application的模版.现在改成了empty-application

现在由演示如何从empty-application补充元素成为window-based application

第一步建立项目.选Empty Application.命名就选经典的helloworld

记住,开发ios时,要去掉User Autonatic Reference Counting.

 

第二步.增加xib, 新建文件选择user interface->empty.

取名MainWindow

同时在target里把Main interface选择MainWindow

 

第三步增加object 和window.

并把object的classt选择为helloworldAppDelegate

 

第四步就是关联窗口对象了.

在IB中是用IBOutlet来标识可以连接的.

所以需要更改helloworldAppDelegate.h

看到@propert左边的圈没?这就是标识可以拖动的.

先确保打开了MainWindow.xib,然后打开辅助编辑器().

如图所示.

怎么样?左键选择这个圈看看,可以拖动吧.连接到左边的window吧.任务就完成了哦.

 

Run下看看,是不是正常哩.

 

 

 

 

 

 

视图切换

视图切换
在多视图程序中,怎么从一个视图切换到另一个视图呢?

Ios主要有两类组织内容的方式:

UIViewController只负责管理一屏的内容.

为每一屏的内容生成你自己的UIViewController子类.
使用已有的合成视图控制器将他们连在一起.

哈.说到这其实很清楚了.
你不需要再去琢磨怎么从一个视图切换到另一个视图了.
API已经为我们做好了准备.
合理利用UINavigationController类和UITabBarController类吧.
他们对应两浏览和tab 两种内容管理模式.当然,你可以混合使用.

addSubView虽然可以切换视图,但我并不建议…我感觉addsubview的正确使用方法应该仅限于父视图管理自己的子视图.
涉及到几大主界面的切换还是用UINavigationController类和UITabBarController
临时的视图切换使用presentModalViewController

常用视图切换:

1.addSubView 针对为视图

2. presentModalViewController/dismissModalViewControllerAnimated

对象为视图控制器,由任意视图控制器调用

3. pushViewController
对象为视图控制器,由导航控制器调用

addSubView和presentModalViewController的区别.
AddSubView
在ios4.x中
持有view的视图控制器不能接收到viewDidAppear/ViewWillAppear消息
在ios5.x中
持有view的视图控制器都能接收到viewDidAppear/ViewWillAppear消息
问题是:我遇到一个情况,用presentModalViewController能显示出视图.
但用AddSubView不能显示视图,在ios5.x中同样不能.为什么这样,还要研究.

显示视图过程中:
1.loadView
2.viewWillApear
3.viewDidAppear

 

UIViewController类或其子类会在初始化时创建一个UIView对象,会作为控制器的默认视图显示出来,可以通过self.view寻址访问。但没有调用loadView方法时,self.view=nil。默认loadView方法(即[super loadView])的作用是产生一个空白的view。

 

关于:

presentModalViewController

viewcontroller是使用[self.view addSubView:viewController.view]出现的.

1.放到viewController中的viewDidLoad中不会显示

2.  放到viewController中viewDidAppear中取消不了..会反复出现

3.在其它主动调用.都ok.

 

 

另一种viewController使用[navigationcontroller pushviewcontroller:viewcontroller]出现.

1.viewDidLoad;会显示,并且能正常取消

2.viewDidAppear:会显示,不能正常取消

3.在其它地方主动调用:会显示,能正常取消

 

 

阅读twitter分享代码总结:

1.初始化Engin实例

2.判断是否登陆.如果已经登陆,直接调用分享控件.

如果没有登陆,显示登陆控件.

其中有两个协议:

SA_OAuthTwitterEngineDelegate:用于管理用户授权,实际由engin来调用.

SA_OAuthTwitterControllerDelegate:用于登陆成功/失败处理,实际由SA_OAuthTwitterController来调用.

 

附一个我犯过小错误

[code]

demoViewController *dvc = [[demoViewController alloc]initWithFrame:CGRectMake(0,0,360,480)];

[self.view addSubView:dvc.view];//没有正确显示

[dvc viewDidAppear:NO];//说明,ios4.x中这块要用户来调用,5以后系统会自动调用

[/code]

上述是我遇到的问题.

最后发现dvc.view不是没有正确显示,而是一闪而过.

因为没有对dvc retain, 或者说dvc没有被任何对象所引用,所以会自动调用dealloc,从而动view一闪而过(其实看不到).

 

自定义视图

自定义视图

UIKit框架提供了很多经典视图,但实际工作中还是需要一些自定义视图来完成工作.

 

自定义视图就是UIView的子类,然后实现drawRect方法,会绘制具体的图形.

 

这个方法会在视图刷新时自动调用,不需要程序员来手动调用.

在明确地需要重绘时,请调用setNeedsDisplay

 

图形相关的请参考http://developer.apple.com/library/ios/#referencelibrary/GettingStarted/GS_Graphics_iPhone/_index.html#//apple_ref/doc/uid/TP40007300

 

http://developer.apple.com/library/ios/#documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_overview/dq_overview.html#//apple_ref/doc/uid/TP30001066-CH202-TPXREF101

几种框架:

1.UIKit

2.Core Graphics

3.Core Animation

4.OpenGL ES

 

几个概念:

1.图形上下文

A graphics context is an opaque data type (CGContextRef) that encapsulates the information Quartz uses to draw images to an output device, such as a PDF file, a bitmap, or a window on a display.

所谓图形上下文就是指你要画到什么地方去.如pdf,位图,打印机等.

这个绘图目的地会影响绘图的一些行为.

2.绘图状态

就是指填充颜色,笔触宽度等,但不包括下面要讲的绘制路径.

 

3.绘制路径

分为开放路径和闭合路径. 其实很简单,起点和终点位于同一点就是闭合路径,反之就是开放路径.

图片painting又分为两种

 

哈,用过ps没?这个路径和ps差不多同一个概念.路径不是图形,你要么描边,要么填充,才能看到一个图形.

 

 

总结一下

drawRect:的常用步骤是

■ 获得当前的图形上下文环境

■ 定义一个路径

■ 设置颜色 // 这里是指绘图状态等.

■ 画边界或者填充这个路径

■ 如果需要,重复上面的步骤

api参考:

0 CGContextRef context = UIGraphicsGetCurrentContext(); 设置上下文

1 CGContextMoveToPoint 开始画线

2 CGContextAddLineToPoint 画直线

 

4 CGContextAddEllipseInRect 画一椭圆

4 CGContextSetLineCap 设置线条终点形状

4 CGContextSetLineDash 画虚线

4 CGContextAddRect 画一方框

4 CGContextStrokeRect 指定矩形

4 CGContextStrokeRectWithWidth 指定矩形线宽度

4 CGContextStrokeLineSegments 一些直线

 

5 CGContextAddArc 画已曲线 前俩店为中心 中间俩店为起始弧度 最后一数据为0则顺时针画 1则逆时针

5 CGContextAddArcToPoint(context,0,0, 2, 9, 40);//先画俩条线从point 到 弟1点 , 从弟1点到弟2点的线  切割里面的圆

6 CGContextSetShadowWithColor 设置阴影

7 CGContextSetRGBFillColor 这只填充颜色

7 CGContextSetRGBStrokeColor 画笔颜色设置

7 CGContextSetFillColorSpace 颜色空间填充

7 CGConextSetStrokeColorSpace 颜色空间画笔设置

8 CGContextFillRect 补充当前填充颜色的rect

8 CGContextSetAlaha 透明度

 

9 CGContextTranslateCTM 改变画布位置

10 CGContextSetLineWidth 设置线的宽度

11 CGContextAddRects 画多个线

12 CGContextAddQuadCurveToPoint 画曲线

13 CGContextStrokePath 开始绘制图片

13 CGContextDrawPath 设置绘制模式

14 CGContextClosePath 封闭当前线路

15 CGContextTranslateCTM(context, 0, rect.size.height);    CGContextScaleCTM(context, 1.0, -1.0);反转画布

16 CGContextSetInterpolationQuality 背景内置颜色质量等级

16 CGImageCreateWithImageInRect 从原图片中取小图

 

17 字符串的 写入可用  nsstring本身的画图方法 – (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment;来写进去即可

 

18对图片放大缩小的功能就是慢了点

UIGraphicsBeginImageContext(newSize);

UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

 

19 CGColorGetComponents() 返回颜色的各个直 以及透明度 可用只读const float 来接收  是个数组

 

20 画图片 CGImageRef image=CGImageRetain(img.CGImage);

CGContextDrawImage(context, CGRectMake(10.0, height –

100.0, 90.0, 90.0), image);

 

21 实现逐变颜色填充方法 CGContextClip(context);

CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();

CGFloat colors[] =

{

204.0 / 255.0, 224.0 / 255.0, 244.0 / 255.0, 1.00,

29.0 / 255.0, 156.0 / 255.0, 215.0 / 255.0, 1.00,

0.0 / 255.0,  50.0 / 255.0, 126.0 / 255.0, 1.00,

};

CGGradientRef gradient = CGGradientCreateWithColorComponents

(rgb, colors, NULL, sizeof(colors)/(sizeof(colors[0])*4));

CGColorSpaceRelease(rgb);

CGContextDrawLinearGradient(context, gradient,CGPointMake

(0.0,0.0) ,CGPointMake(0.0,self.frame.size.height),

kCGGradientDrawsBeforeStartLocation);

22 注:  画完图后,必须

先用CGContextStrokePath来描线,即形状

后用CGContextFillPath来填充形状内的颜色.

 

 

填充一个路径的时候,路径里面的子路径都是独立填充的。

假如是重叠的路径,决定一个点是否被填充,有两种规则

1,nonzero winding number rule:非零绕数规则,假如一个点被从左到右跨过,计数器+1,从右到左跨过,计数器-1,最后,如果结果是0,那么不填充,如果是非零,那么填充。

2,even-odd rule: 奇偶规则,假如一个点被跨过,那么+1,最后是奇数,那么要被填充,偶数则不填充,和方向没有关系。

 

 

Function

Description

CGContextEOFillPath

使用奇偶规则填充当前路径

CGContextFillPath

使用非零绕数规则填充当前路径

CGContextFillRect

填充指定的矩形

CGContextFillRects

填充指定的一些矩形

CGContextFillEllipseInRect

填充指定矩形中的椭圆

CGContextDrawPath

两个参数决定填充规则,kCGPathFill表示用非零绕数规则,kCGPathEOFill表示用奇偶规则,kCGPathFillStroke表示填充,kCGPathEOFillStroke表示描线,不是填充

 

 

 

 

 

设置当一个颜色覆盖上另外一个颜色,两个颜色怎么混合

默认方式是

result = (alpha * foreground) + (1 – alpha) * background

 

CGContextSetBlendMode :设置blend mode.

CGContextSaveGState :保存blend mode.

CGContextRestoreGState:在没有保存之前,用这个函数还原blend mode.

CGContextSetBlendMode 混合俩种颜色

iOS富文本

最简单的方法是使用UIWebView.因为这家伙直接就支持html代码.

看手册:

loadHTMLString:baseURL:

Sets the main page content and base URL.

– (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
Parameters
string
The content for the main page.

baseURL
The base URL for the content.

Availability
  • Available in iOS 2.0 and later.
Declared In
UIWebView.h
不要被baseURL吓到了.传个nil就ok的.
示例代码:

 [webView loadHTMLString:@”<ul><li>aaa</li><li>abbbb</li><li style=’text-decoration:underline;’>cccc</li></ul>” baseURL:nil];

看下效果:

有点需要注意,使用自己的html串时

scalesPageToFit要设为NO(默认值).

看来起UIWebView是不错,功能强大.但他也有一些需要注意的地方:

Important You should not embed UIWebView or UITableView objects in UIScrollView objects. If you do so, unexpected behavior can result because touch events for the two objects can be mixed up and wrongly handled.

为了避免事件混淆,别把UIWebView嵌到UIScrollView里去,要不然会有一些草名其妙的问题的.

还有就是下面的缺点了:

1.    UIWebView效率太低,不适合嵌套到列表UITableView里

2.    UIWebView只能在加载完后才能通过Javascript查到内容高度

3.    UIWebView封装太过,不可以被继承,屏蔽了用户触摸事件,很难对View进行自定义化,只能通过调整HTML代码来修改样式。

除了UIWebView,还可以参看其它几种方式:

1.Facebook Three20的TTStyledText,

2.苹果iOS3.2新加库CoreText的NSAtrributedString

3.Zynga FontLabel的ZAttributedString.


用户交互与响应.

用户交互与响应.

用户触发界面上的一个按钮,应用程序怎么来响应呢?

这里提供了三种编程模型:

1.委拖

2.目标操作

3.通知

 

一.委拖

许多UIKit类都使用委拖交出响应用户交互的责任.在设置某个对象的委托时,便是让对象将任何交互消息传递出去,让该委托负责处理这些事务.

 

就拿官网上的第一个HelloWorld的例子来说.

当按下键盘的Done键时,就是实现了UITextFieldDelegate(通常是一个视图控制器类或主应用程序委托来实现,例子中是视图控制器实现的.)的textFieldShouldReturn方法.

 

要设置某个对象的委拖,可以指定它的委托属性,或者使用setDelegate:方法的一些变体.

官网上是用IB设置的委托

如图所示.去掉Outlets下面的设置,点x就行.

再运行下看看.键盘又解除不掉了.

 

在HelloWorldViewController.m中改处代码,用下SetDelegate看看.

代码如下所示:

  • (void)viewDidLoad

{

[super viewDidLoad];

[textField setDelegate:self];//这里设置的

// Do any additional setup after loading the view, typically from a nib.

}

再运行,是不是就可以了.

 

 

二.目标操作

一种较为低级的方式.几乎只有在实现UIControl类的子类时,你才会遇到它们.

如下代码:

UIBarButtonItem *testBarItem = [[UIBarButtonItem alloc] initWithTitle:@”test” style:UIBarButtonItemStyleBordered target:self action:@selector(testAction:)];

 

相对于委拖来说.你得自己确保你的自定义方法testAction是有实现的,否则在运行时会崩溃.

 

三.通知

通知支持应用程序中对象的相互交流,以及与系统上的其他应用程序通信

iOS启动过程

Ios应用程序的启动过程

 

由于使用xcode建立项目时,xcode都已经配置好了一系列的模板.这些模板已经配置好了应用程序启动的基本环境.譬如说xcode创建了这样一个对象,他会去连接窗口服务,建立运行循环等等.大部分这类工作都是由UIApplicationMain函数完成的.其定义如下.

 

// If nil is specified for principalClassName, the value for NSPrincipalClass from the Info.plist is used. If there is no

// NSPrincipalClass key specified, the UIApplication class is used. The delegate class will be instantiated using init.

UIKIT_EXTERN int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);

 

Objective-c的入口函数是main.看下main.m文件

#import <UIKit/UIKit.h>

 

#import “AppDelegate.h”

 

int main(int argc, char *argv[])

{

@autoreleasepool {

return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

}

}

 

可以看到UIApplicationMain被调用了.

一般principalClassName是传nil,正如上面注释所说,指定为nil时,会使用UIApplication.

.

UIApplicationMain这个调用做了什么事呢?

1.创建了UIApplication实例

2.创建应用程序代理实例.即上面的AppDelegate

AppDelegate主要功能是提供一个应用程序内容绘制的窗口

3.浏览Info.plist.Info.plist文件提供应用程序的属性列表,如名字,图标等.

 

 

如果应用程序用到了interface builder.比如MainStroy.xib或者MainStroyBoard.storyboard. Info.plist文件还要指定要加载的xib or storyboard的文件名.

 

这里插一下.xib/storyboard是什么哩. 就是压缩文件.在应用程序使用的时候,又还原成代码.如果读者学过其它语言,可以理解成序列化和反序列化.它是用于给用户直接设计界面的,一是减少工程师的工作量,二是做了所见即所得的编辑效果.

应用程序启动时,会根据info.plist 来加载nib/storyboard文件,然后初始化一个viewcontroller实例对象.

 

 

During setup, the application object performs the following tasks:

1.Loads the main storyboard file.

2.Gets the window object from the app delegate (or creates a new instance of UIWindow and associates it with the app delegate).

3.Instantiates the storyboard’s initial view controller and assigns it as the window object’s root view controller.

 

When the application object has completed these tasks, it sends its delegate an application:didFinishLaunchingWithOptions: message. This message gives the delegate an opportunity to perform other tasks, such as additional configuration, before the application is displayed.

 

 

总结一下:

1.入口main

2.调用UIApplicationMain

1.创建了UIApplication实例

2.创建应用程序代理实例.即上面的AppDelegate

AppDelegate主要功能是提供一个应用程序内容绘制的窗口

3.浏览Info.plist.Info.plist文件提供应用程序的属性列表,如名字,图标等.

3.加载xib/storyboard文件

4.从app delegate 获取window对象

5.从xib/storyboard初始化viewcontroller对象,并赋值给window对象的root view controller

6.发送application:didFinishLaunchingWithOptions消息给代理对象.让用户完成自己的一些初始化工作.