1.ViewController的生命周期
按结构可以对iOS的所有ViewController分成两类:
1、主要用于展示内容的ViewController,这种ViewController主要用于为用户展示内容,并与用户交互,如UITableViewController,UIViewController。
2、用于控制和显示其他ViewController的ViewController。这种ViewController一般都是一个ViewController的容器。如UINavigationController,UITabbarController。它们都有一个属性:viewControllers。其中UINavigationController表示一种Stack式结构,push一个ViewController或pop一次,因此后一个ViewController一般会依赖前一个ViewController。而UITabbarController表示一个Array结构,各个ViewController是并列的。
当你alloc并init了一个ViewController时,这个ViewController应该是还没有创建view的。ViewController的view是使用了lazyInit方式创建,就是说你调用的view属性的getter:[self view]。在getter里会先判断view是否创建,如果没有创建,那么会调用loadView来创建view。loadView完成时会继续调用viewDidLoad。loadView和viewDidLoad的一个区别就是:loadView时还没有view。而viewDidLoad时view以及创建好了。
当view被添加其他view中之前时,会调用viewWillAppear,而之后会调用viewDidAppear。
当view从其他view中移出之前时,会调用viewWillDisAppear,而之后会调用viewDidDisappear。
当view不在使用,而且是disappeared,受到内存警告时,那么viewController会将view释放并将其指向nil。
ViewController生命周期中有那么多函数,一个重要问题就是什么代码该写在什么地方。
1、init里不要出现创建view的代码。良好的设计,在init里应该只有相关数据的初始化,而且这些数据都是比较关键的数据。init里不要掉self.view,否则会导致viewcontroller创建view。(因为view是lazyinit的)。
2、loadView中只初始化view,一般用于创建比较关键的view如tableViewController的tabView,UINavigationController的navgationBar,不可掉用view的getter(在掉super loadView前),最好也不要初始化一些非关键的view。如果你是从nib文件中创建的viewController在这里一定要首先调用super的loadView方法,但建议不要重载这个方法。
3、viewDidLoad 这时候view已经有了,最适合创建一些附加的view和控件了。有一点需要注意的是,viewDidLoad会调用多次(viewcontroller可能多次载入view,参见图2)。
4、viewWillAppear 这个一般在view被添加到superview之前,切换动画之前调用。在这里可以进行一些显示前的处理。比如键盘弹出,一些特殊的过程动画(比如状态条和navigationbar颜色)。
5、viewDidAppear 一般用于显示后,在切换动画后,如果有需要的操作,可以在这里加入相关代码。
6、viewDidUnload 这时候viewController的view已经是nil了。由于这一般发生在内存警告时,所以在这里你应该将那些不在显示的view释放了。比如你在viewcontroller的view上加了一个label,而且这个label是viewcontroller的属性,那么你要把这个属性设置成nil,以免占用不必要的内存,而这个label在viewDidLoad时会重新创建。
2 使用block和使用delegate完成委托模式有什么优点?
使用block实现委托模式,其优点是回调的block代码块定义在委托对象函数内部,使代码更为紧凑;适配对象不再需要实现具体某个protocol,代码更为简洁。代码可读性更强,更有连贯性,block经常可以用于completion handler、error handler等。网络请求回调。
delegation的基本特征是,一个controller定义了一个协议(即一系列的方法定义)。该协议描述了一个delegate对象为了能够响应一个controller的事件而必须做的事情。协议就是delegate说,“如果你想作为我的delegate,那么你就必须实现这些方法”。实现这些方法就是允许controller在它的delegate能够调用这些方法,而它的delegate知道什么时候调用哪种方法。delegate可以是任何一种对象类型,因此controller不会与某种对象进行耦合,但是当该对象尝试告诉委托事情时,该对象能确定delegate将响应。
delegate的优势:
1.非常严格的语法。所有将听到的事件必须是在delegate协议中有清晰的定义。
2.如果delegate中的一个方法没有实现那么就会出现编译警告/错误
3.协议必须在controller的作用域范围内定义
4.在一个应用中的控制流程是可跟踪的并且是可识别的;
5.在一个控制器中可以定义多个不同的协议,每个协议有不同的delegate
6.没有第三方对象要求保持/监视通信过程。
7.能够接收调用的协议方法的返回值。这意味着delegate能够提供反馈信息给controller
缺点:
1.需要定义很多代码:1.协议定义;2.controller的delegate属性;3.在delegate本身中实现delegate方法定义
2.在释放代理对象时,需要小心的将delegate改为nil。一旦设定失败,那么调用释放对象的方法将会出现内存crash
3.在一个controller中有多个delegate对象,并且delegate是遵守同一个协议,但还是很难告诉多个对象同一个事件,不过有可能。
3 delegate和Notification的区别
delegate针对one-to-one关系,并且reciever可以返回值给sender;
notification 可以针对one-to-one/many/none,reciever无法返回值给sender;
所以,delegate用于sender希望接受到reciever的某个功能反馈值,notification用于通知多个object某个事件。
delegate主动,notification被动
1.
Delegate:
消息的发送者(sender)告知接收者(receiver)某个事件将要发生,delegate同意然后发送者响应事件,delegate机制使得接收者可以改变发送者的行为。通常发送者和接收者的关系是直接的一对多的关系。
Notification:
消息的发送者告知接收者事件已经发生或者将要发送,仅此而已,接收者并不能反过来影响发送者的行为。通常发送者和接收者的关系是间接的多对多关系。
2.
简单说,
1. 效率肯定是delegate比nsnotification高。
2. delegate方法比notification更加直接,最典型的特征是,delegate方法往往需要关注返回值,也就是delegate方法的结果。
notification
在IOS应用开发中有一个”Notification Center“的概念。它是一个单例对象,允许当事件发生时通知一些对象。它允许我们在低程度耦合的情况下,满足控制器与一个任意的对象进行通信的目的。这种模式的基本特征是为了让其他的对象能够接收到在该controller中发生某种事件而产生的消息,controller用一个key(通知名称)。这样对于controller来说是匿名的,Source
Code其他的使用同样的key来注册了该通知的对象(即观察者)能够对通知的事件作出反应。
优势:
1.不需要编写多少代码,实现比较简单;
2.对于一个发出的通知,多个对象能够做出反应,即1对多的方式实现简单
3.controller能够传递context对象(dictionary),context对象携带了关于发送通知的自定义的信息
缺点:
1.在编译期不会检查通知是否能够被观察者正确的处理;
2.在释放注册的对象时,需要在通知中心取消注册;
3.在调试的时候应用的工作以及控制过程难跟踪;
4.需要第三方对喜爱那个来管理controller与观察者对象之间的联系;
5.controller和观察者需要提前知道通知名称http://www.androide-apps.com/、UserInfo dictionary keys。如果这些没有在工作区间定义,那么会出现不同步的情况;
6.通知发出后,controller不能从观察者获得任何的反馈信息。
4.多线程(NSThread、NSOperation Queue、GCD,block)
使用NSOperationQueue用来管理子类化的NSOperation对象,控制其线程并发数目。GCD和NSOperation都可以实现对线程的管理,区别是 NSOperation和NSOperationQueue是多线程的面向对象抽象。项目中使用NSOperation的优点是NSOperation是对线程的高度抽象,在项目中使用它,会使项目的程序结构更好,子类化NSOperation的设计思路,是具有面向对象的优点(复用、封装),使得实现是多线程支持,而接口简单,建议在复杂项目中使用。
block
对于闭包(block),有很多定义,其中闭包就是能够读取其它函数内部变量的函数
block可以满足用delegation实现的消息传递机制。不过这两种机制都有各自的需求和优势。
为了让代码可读性更强,更有连贯性,那最好是使用block了。根据这个思路,block经常可以用于completion handler、error handler等。网络请求回调,
Block实体开头是“^”,接着是由小括号所包起来的参数列(比如 int a, int b, int c),行为主体由大括号包起来,专有名字叫做block literal。行为主体可以用return回传值,类型会被compiler自动辨别。如果没有参数列要写成: ^(void)。
int multiplier = 7;
NSLog(@"%d",aBlock(multiplier));
NSLog(@"%d",chengfa(multiplier));
int(^aBlock)(int) = ^(int num2) {
return num2;
};
int (^chengfa)(int ) = ^(int a){
return a*a;
};
这是代表Block会回传输入值的平方值(int a 就是参数列, return a*a; 就是行为主体)。记得行为主体里最后要加“;”,因为是叙述,而整个{}最后也要加“;”,因为Block是物件实体。用法如下:
int (^square)(int);
square = ^(int a){
return a*a;
};
int result = square(5);
NSLog(@"%d",result);
1
//声明一个square的Block Pointer,其所指向的Block有一个int输入和int输出
2
int (^square)(int);
3
//将Block实体指定给square
4
square = ^(int a){ return a*a ; };
5
//调用方法,感觉是是不是很像function的用法?
6
int result = square(5);
7
NSLog(@"%d", result);
int b = 20;
int (^abc)(int)=^(int a ){
return b*a;
};
int gloabalInt = 0;
int(^getGlobal)(void)=^(void){
return
gloabalInt;
};
int(^oneFron)(int);
oneFron = ^(int a ){
return a;
};
int (^bcd)(int)=^(int a){
return a*20;
};
int(^oneFrom)(int)=^(int annt)
{
return annt-1;
};
float(^distanceTraved)(float,float,float)=^(float startSpeed,float acceleration,float time)
{
float distance = (startSpeed*time)+(0.5*acceleration*time*time);
return distance;
};
多线程编程[email protected]的使用
1.显示调用的类为NSThread有两种直接创建方式:
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument(手动开启)
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument(自动开启)
[NSThread
detachNewThreadSelector:@selector(dosomething:)
toTarget:self
withObject:nil];
NSThread *thread = [[NSThread
alloc] initWithTarget:self
selector:@selector(dosomething:)
object:nil];
[thread start];
Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。
gcd实现倒计时,注册页面发送验证码的倒计时。
- (void)viewDidLoad
{
[super
viewDidLoad];
[l_timeButton addTarget:self
action:@selector(startTime)
forControlEvents:UIControlEventTouchUpInside];
}
-(void)startTime{
__block int timeout=130;
//倒计时时间
dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0);
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
0, 0,queue);
dispatch_source_set_timer(_timer,dispatch_walltime(NULL,
0),1.0*NSEC_PER_SEC,
0); //每秒执行
dispatch_source_set_event_handler(_timer, ^{
if(timeout<=0){
//倒计时结束,关闭
dispatch_source_cancel(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
//设置界面的按钮显示
根据自己需求设置
[l_timeButton
setTitle:@"发送验证码" forState:UIControlStateNormal];
l_timeButton.userInteractionEnabled =
YES;
});
}else{
// int minutes = timeout / 60;
int seconds = timeout %
130;
NSString *strTime = [NSString
stringWithFormat:@"%.2d", seconds];
dispatch_async(dispatch_get_main_queue(), ^{
//设置界面的按钮显示
根据自己需求设置
NSLog(@"____%@",strTime);
[l_timeButton
setTitle:[NSString
stringWithFormat:@"%@秒后重新发送",strTime] forState:UIControlStateNormal];
l_timeButton.userInteractionEnabled =
NO;
});
timeout--;
}
});
dispatch_resume(_timer);
}
dispatch queue分成以下三种:
1)运行在主线程的Main queue,通过dispatch_get_main_queue获取。
2)并行队列global dispatch queue,通过dispatch_get_global_queue获取,由系统创建三个不同优先级的dispatch queue。并行队列的执行顺序与其加入队列的顺序相同。
3)串行队列serial queues一般用于按顺序同步访问,可创建任意数量的串行队列,各个串行队列之间是并发的。
//后台执行
dispatch_async(dispatch_get_global_queue(0,
0), ^{
});
//主线程执行
dispatch_async(dispatch_get_main_queue(), ^{
});
//一次性执行
static
dispatch_once_t onceToken ;
dispatch_once(&onceToken, ^{
});
//延迟2秒执行:
double delayInseconds =
2.0;
dispatch_time_t popTime =
dispatch_time(DISPATCH_TIME_NOW, delayInseconds *
NSEC_PER_SEC);
dispatch_after(popTime,
dispatch_get_main_queue(), ^{
});
//自定义dispatch_queue_t
dispatch_queue_t urls_queue =
dispatch_queue_create("blog.devtang.com",
NULL);
dispatch_async(urls_queue, ^{
});
dispatch_release(urls_queue);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0), ^{
NSURL *url = [NSURL
URLWithString:@"http://www.baidu.com"];
NSError *error ;
NSString *data = [NSString
stringWithContentsOfURL:url encoding:NSUTF8StringEncoding
error:&error];
if (data !=
nil) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"call back,the data is :%@",data);
});
}else{
NSLog(@"%@",error);
}
});
GCD的另一个用处是可以让程序在后台较长久的运行。
在没有使用GCD时,当app被按home键退出后,app仅有最多5秒钟的时候做一些保存或清理资源的工作。但是在使用GCD后,app最多有10分钟的时间在后台长久运行。这个时间可以用来做清理本地缓存,发送统计数据等工作。
// AppDelegate.h文件 @property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask;
// AppDelegate.m文件 - (void)applicationDidEnterBackground:(UIApplication *)application
{
[self beingBackgroundUpdateTask]; // 在这里加上你需要长久运行的代码 [self endBackgroundUpdateTask];
} - (void)beingBackgroundUpdateTask
{
self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundUpdateTask];
}];
} - (void)endBackgroundUpdateTask
{
[[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
self.backgroundUpdateTask = UIBackgroundTaskInvalid;
}
2. 不显式创建线程的方法:
通过NSObject的Category方法调用:
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait; //在主线程中运行方法,wait表示是否阻塞这个方法的调用,如果为YES则等待主线程中运行方法结束。一般可用于在子线程中调用UI方法。
if (![[NSThread
currentThread] isMainThread]) {
[self
performSelectorOnMainThread:@selector(transitionToNextPhase)
withObject:nil
waitUntilDone:YES];
return
YES;
}
[self performSelector:@selector(TanChu) withObject:nil afterDelay:0.3];//前一个view事情木有做完,久push到另一个VC,导致弹出错误,比如说uiwebview的999错误。
[self
performSelector:@selector(navBarHidens)
withObject:self
afterDelay:ANIMATION_TIME+0.1];// 导航栏隐藏
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thread withObject:(id)arg waitUntilDone:(BOOL)wait; //在指定线程中执行,但该线程必须具备run loop。
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg; //产生新线程。
3.NSThread的其它一些常用的方法
1. + (NSThread *)currentThread; //获得当前线程
2. + (void)sleepForTimeInterval:(NSTimeInterval)ti; //线程休眠
3. + (NSThread *)mainThread; //主线程,亦即UI线程了
4. - (BOOL)isMainThread; + (BOOL)isMainThread; //当前线程是否主线程
5. - (BOOL)isExecuting; //线程是否正在运行
6. - (BOOL)isFinished; //线程是否已结束
7.- (void)cancel // 终止线程循环
8.- (void)start // 开启线程循环
5.动画
+ (void)animationFlipFromLeft:(UIView *)view
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.35f];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft
forView:view cache:NO];
[UIView commitAnimations]; }
- (void)moveToUpSide {
[UIView animateWithDuration:0.7 //速度0.7秒
animations:^{//修改rView坐标
rView.frame =
CGRectMake(self.window.frame.origin.x,
}
CATransition
6.绘图
7.设计模式( MVC、单例等)
模型-视图-控制器(MVC) 是Cocoa的构建块之一,毫无疑问它是使用最频繁的设计模式。它根据通用的角色去划分类,这样就使得类的职责可以根据角色清晰的划分开来。
涉及到的三个角色如下:
Model:模型保存应用程序的数据,定义了怎么去操作它。
View: 视图是模型的可视化表示以及用户交互的控件;基本上来说,所有的UIView对象以及它的子类都属于视图。
Controller: 控制器是一个协调所有工作的中介者(Mediator)。它访问模型中的数据并在视图中展示它们,同时它们还监听事件和根据需要操作数据。你可以猜猜哪个类是控制器吗?它正是:ViewController。
一个MVC模式的好的实现也就意味着每一个对象都会被划分到上面所说的组中。
单例设计模式确保对于一个给定的类只有一个实例存在,这个实例有一个全局唯一的访问点。它通常采用懒加载的方式在第一次用到实例的时候再去创建它。
客户端第一次发送sharedInstance消息的时候,instance属性尚未被初始化,所以此时你需要创建一个新的实例,然后返回它的引用。
当你下一次调用sharedInstance的时候,instance不需要任何初始化可以立即返回。这个逻辑保证总是只有一个实例。
@interface LibraryAPI : NSObject
+ (LibraryAPI*)sharedInstance;
@end
+ (LibraryAPI*)sharedInstance
{
// 1
static LibraryAPI *_sharedInstance = nil;
// 2
static dispatch_once_t oncePredicate;
// 3
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[LibraryAPI alloc] init];
});
return _sharedInstance;
}
在这个简短的方法中,有一些需要需要注意的点:
1.声明一个静态变量去保存类的实例,确保它在类中的全局可用性。
2.声明一个静态变量dispatch_once_t ,它确保初始化器代码只执行一次
3.使用Grand Central Dispatch(GCD)执行初始化LibraryAPI变量的block.这 正是单例模式的关键:一旦类已经被初始化,初始化器永远不会再被调用。
下一次你调用sharedInstance的时候,dispatch_once块中的代码将不会执行(因为它已经被执行了一次),你将得到原先已经初始化好的实例。
8.Objective-C语言的特征(KVO、Notification、delegate)
Notification
在不相关的两部分代码中要想进行消息传递,通知(notifacation)是非常好的一种机制,它可以对消息进行广播。特别是想要传递丰富的信息,并且不一定指望有谁对此消息关心。
通知可以用来发送任意的消息,甚至包含一个userInfo字典,或者是NSNotifacation的一个子类。通知的独特之处就在于发送者和接 收者双方并不需要相互知道。这样就可以在非常松耦合的模块间进行消息的传递。记住,这种消息传递机制是单向的,作为接收者是不可以回复消息的。
[[NSNotificationCenter
defaultCenter] postNotificationName:@"TestNotification"
object:self];
[[NSNotificationCenter
defaultCenter] addObserver:self
selector:@selector(receiveTestNotification)
name:@"TestNotification"
object:nil];
- (void)dealloc
{
[[NSNotificationCenter
defaultCenter] removeObserver:self];
[super
dealloc];
}
KVO
对象中的某个属性支持KVO,那么谁修改这个值,谁就是发送者,对应 的观察者(observer)则是接收者。
KVO提供了这样一种机制:当对象中的某个属性值发生了改变,可以对这些值的观察者做出通知。KVO的实现包含在Foundation里面,基于 Foundation构建的许多Framework对KVO都有所依赖。要想了解更多关于如何使用KVO
如果对某个对象中值的改变情况感兴趣,那么可以使用KVO消息传递机制。这里有两个要求,首先,接收者(会接收到值发生改变的消息)必须知道发送者 (值将发生改变的那个对象)。另外,接收者同样还需要知道发送者的生命周期,因为在销毁发送者对象之前,需要取消观察者的注册。如果这两个要求都满足了, 消息传递过程中可以是1对多(多个观察者可以注册某个对象中的值)。
如果计划在Core Data对象上使用KVO,需要知道这跟一般的KVO使用方法有点不同。那就是必须结合Core Data的故障机制(faulting mechanism),一旦core data出现了故障,它将会触发其属性对应的观察者(即使这些属性值没有发生改变)。
KVO是一个对象能够观察另外一个对象的属性的值,并且能够发现值的变化。前面两种模式更加适合一个controller与任何其他的对象进行通信,而KVO更加适合任何类型的对象侦听另外一个任意对象的改变(这里也可以是controller,但一般不是controller)。这是一个对象与另外一个对象保持同步的一种方法,即当另外一种对象的状态发生改变时,观察对象马上作出反应。它只能用来对属性作出反应,而不会用来对方法或者动作作出反应。
优点:
1.能够提供一种简单的方法实现两个对象间的同步。例如:model和view之间同步;
2.能够对非我们创建的对象,即内部对象的状态改变作出响应,而且不需要改变内部对象(SKD对象)的实现;
3.能够提供观察的属性的最新值以及先前值;
4.用key paths来观察属性,因此也可以观察嵌套对象;
5.完成了对观察对象的抽象,因为不需要额外的代码来允许观察值能够被观察
缺点:
1.我们观察的属性必须使用strings来定义。因此在编译器不会出现警告以及检查;
2.对属性重构将导致我们的观察代码不再可用;
3.复杂的“IF”语句要求对象正在观察多个值http://www.pudncom.com/ 。这是因为所有的观察代码通过一个方法来指向;
4.当释放观察者时不需要移除观察者。
KVO(Key Value Observing),是观察者模式在Foundation中的实现。
KVO的原理
简而言之就是:
1、当一个object有观察者时,动态创建这个object的类的子类
2、对于每个被观察的property,重写其set方法
3、在重写的set方法中调用- willChangeValueForKey:和- didChangeValueForKey:通知观察者
4、当一个property没有观察者时,删除重写的方法
5、当没有observer观察任何一个property时,删除动态创建的子类
delegation
delegation允许我们定制某个对象的行为,并且可以收到某些确定 的事件。为了使用delegation模式,消息的发送者需要知道消息的接收者(delegate),反过来就不用了。这里的发送者和接收者是比较松耦合 的,因为发送者只知道它的delegate是遵循某个特定的协议。
delegate协议可以定义任意的方法,因此你可以准确的定义出你所需要的类型。你可以用函数参数的形式来处理消息内容,delegate还可以 通过返回值的形式给发送者做出回应。如果只需要在相对接近的两个模块之间进行消息传递,那么Delegation是一种非常灵活和直接方式。
譬如:在两个页面(UIIview视图对象)实现传值,用委托(delegate)可以很好做到!
方法:
类A
@interface A:UIView
id transparendValueDelegate;
@property(nomatic, retain) idtransparendValueDelegate;
@end
@implemtion A
@synthesize transparendValueDelegate
-(void)Function
{
NSString* value = @"hello";
//让代理对象执行transparendValue动作
[transparendValueDelegate transparendValue:value];
}
@end
类B
@interface B:UIView
NSString* value;
@end
@implemtion B
-(void)transparendValue:(NSString*)fromValue
{
value = fromValue;
NSLog(@"the value is %@",value);
}
@end
//下面的设置A代理委托对象为B
//在定义A和B类对象处:
A* a = [[A alloc] init];
B* b = [[B alloc] init];
a. transparendValueDelegate = b;//设置对象a代理为对象b
这样在视图A和B之间可以通过委托来传值!
1。简述push原理,push的证书和其它的右什么不一样?
推送通知更是一种技术。简单点就是客户端获取资源的一种手段。
普通情况下,都是客户端主动的pull。推送则是服务器端主动push
2。viewcontroller的一些方法的说明viewDidLoad, viewWillDisappear, viewWillAppear方法的 顺序和 作用?
viewwillappear
viewdidload
viewwilldisappear
3。frame 和 bounds 的 区别 ,bound的大小改变frame 改变吗?
http://blog.csdn.net/mad1989/article/details/8711697
先看到下面的代码你肯定就明白了一些:
-(CGRect)frame{
return CGRectMake(self.frame.origin.x,self.frame.origin.y,self.frame.size.width,self.frame.size.height);
}
-(CGRect)bounds{
return CGRectMake(0,0,self.frame.size.width,self.frame.size.height);
}
很明显,bounds的原点是(0,0)点(就是view本身的坐标系统,默认永远都是0,0点,除非认为setbounds),而frame的原点却是任意的(相对于父视图中的坐标位置)。
frame: 该view在父view坐标系统中的位置和大小。(参照点是,父亲的坐标系统)
bounds:该view在本地坐标系统中的位置和大小。(参照点是,本地坐标系统,就相当于ViewB自己的坐标系统,以0,0点为起点)
center:该view的中心点在父view坐标系统中的位置和大小。(参照电是,父亲的坐标系统)
我个人认为,bounds稍微有点费解,稍不留神,想的多了,就会绕进去。每个view都有一个本地坐标系统。这个坐标系统作用比较重要,比如触 摸的回调函数中的UITouch里面的>坐标值都是参照这个本地坐标系统的坐标。当然bounds这个属性也是参照这个本地坐标系统来的。其实本地 坐标系统的关键就是要知道的它的原点(0,0)在什么位置(这个位置又是相对于上层的view的本地坐标系统而言的,当然最上面的一层view就是 window它的本地坐标系统原点就是屏幕的左上角了)。通过修改view的bounds属性可以修改本地坐标系统的原点位置。
所以,我个人认为,bounds影响到子view的位置和大小。
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 280, 250)];
[view1 setBounds:CGRectMake(-20, -20, 280, 250)];
view1.backgroundColor = [UIColor redColor];
[self.view addSubview:view1];//添加到self.view
NSLog(@"view1 frame:%@========view1 bounds:%@",NSStringFromCGRect(view1.frame),NSStringFromCGRect(view1.bounds));
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
view2.backgroundColor = [UIColor yellowColor];
[view1 addSubview:view2];//添加到view1上,[此时view1坐标系左上角起点为(-20,-20)]
NSLog(@"view2 frame:%@========view2 bounds:%@",NSStringFromCGRect(view2.frame),NSStringFromCGRect(view2.bounds));
4。sqlite中插入特殊字符的方法和接收到处理方法。
特殊字符转义
keyWord = keyWord.replace("/", "//");
keyWord = keyWord.replace("‘", "‘‘");
keyWord = keyWord.replace("[", "/[");
keyWord = keyWord.replace("]", "/]");
keyWord = keyWord.replace("%", "/%");
keyWord = keyWord.replace("&","/&");
keyWord = keyWord.replace("_", "/_");
keyWord = keyWord.replace("(", "/(");
keyWord = keyWord.replace(")", "/)");
5。谈谈你对数组和连表认识,还有你是怎么用他们的?
6。冒泡算法。
它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
冒泡排序算法的运作如下:(从后往前)
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较
- (void)bubbleSort:(NSMutableArray *)array
{
for (int i =0; i <[array
count]-1; i++) {
for (int j = i+1; j <[array
count]; j++) {
if ([array
objectAtIndex:j]<[array objectAtIndex:i]) {
[array exchangeObjectAtIndex:j
withObjectAtIndex:i];
}
}
}
}
快速排序(Quicksort)是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
void QuickSort(int a[],int numsize)/*a是整形数组,numsize是元素个数*/
{
int i=0,j=numsize-1;
int val=a[0];/*指定参考值val大小*/
if(numsize>1)/*确保数组长度至少为2,否则无需排序*/
{
while(i<j)/*循环结束条件*/
{
/*从后向前搜索比val小的元素,找到后填到a[i]中并跳出循环*/
for(;j>i;j--)
if(a[j]<val)
{
a[i++]=a[j];
break;
}
/*从前往后搜索比val大的元素,找到后填到a[j]中并跳出循环*/
for(;i<j;i++)
if(a[i]>val)
{
a[j--]=a[i];
break;
}
}
a[i]=val;/*将保存在val中的数放到a[i]中*/
QuickSort(a,i);/*递归,对前i个数排序*/
QuickSort(a+i+1,numsize-i-1);/*对i+2到numsize这numsize-1-i个数排序*/
}
}
7。socket编程简述
Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。
http连接:http连接就是所谓的短连接,即客户端向服务器端发送一次请求,服务器端响应后连接即会断掉;
socket连接:socket连接就是所谓的长连接,理论上客户端和服务器端一旦建立起连接将不会主动断掉;但是由于各种环境因素可能会是连接断开,比如说:服务器端或客户端主机down了,网络故障,或者两者之间长时间没有数据传输,网络防火墙可能会断开该连接以释放网络资源。所以当一个socket连接中没有数据的传输,那么为了维持连接需要发送心跳消息~~具体心跳消息格式是开发者自己定义的
1)Socket是一个针对TCP和UDP编程的接口,你可以借助它建立TCP连接等等。而TCP和UDP协议属于传输层 。
而http是个应用层的协议,它实际上也建立在TCP协议之上。
(HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。)
2)Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。Socket的出现只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口。
8。asihttp代码原理 ,异步请求的原理,异步请求最大数目,为什么只能这么多?
这个数量是跟cpu有关的,并发性取决于cpu核数,每个核只能同时处理一个任务.4核cpu理论上可以并发处理4个任务,如果按http来算就是4个请求,但是cpu是抢占式资源,所以一般来说并发量是要根据任务的耗时和cpu的繁忙度来计算4个左右只是个经验值你开10个短耗时的任务和几个长耗时任务的效率是不同的- -..一般来说估算这个量的最大效率估算公示是cpu核数*2-1,这个公式是当时对集群进行压测得到的结论.cpu抢占时间跟任务时长…开启这个数量的线程可以最大化的榨干cpu。一个道理。cpu不可能都被抢去做connection.iOS是cpu密集型的消耗
。这个大概知道就行了,也不会有人特别在意吧…cpu核数*2-1那个是做淘宝的java团队压测得到的线程最优数
,放在iOS上也多少适用…一般来说不超过这个量就好,线程不是起的越多越好,线程数就是…cpu来决定的
9。http请求方式?
get post head
http(超文本传输协议)是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式,HTTP1.1版本中给出一种持续连接的机制,绝大多数的Web开发,都是构建在HTTP协议之上的Web应用。
HTTP协议的主要特点可概括如下:
1.支持客户/服务器模式。
2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
3.灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
10。uiview的圆角属性设置方法。
(m_mainImgView.layer.cornerRadius = 6;
m_mainImgView.layer.masksToBounds = YES;)
11。 masksToBounds属性的作用。(决定子layer是否被当前layer的边界剪切。默认是NO。
/**
* 去除iOS7新的功能api,tableView的分割线变成iOS6正常的样式
*/
func configuraTableViewNormalSeparatorInset() {
self.tableView.separatorInset =
UIEdgeInsetsZero
}
/**
* 配置tableView右侧的index title
背景颜色,因为在iOS7有白色底色,iOS6没有
*
* @param tableView 目标tableView
*/
func configuraSectionIndexBackgroundColorWithTableView(tableView:UITableView!) {
tableView.sectionIndexBackgroundColor =
UIColor.clearColor()
}
12 sdwebimage
实现加载网络图片,并可以设置图片加载前的默认图片,监听图片加载进度以及图片加载完成事件
#import导入"UIImageView+WebCache.h",
[_imageView setImageWithURL:url placeholderImage:nil options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) {//查看下载进度
NSLog(@"receive = %d,expected = %d",receivedSize,expectedSize);
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {//加载成功后调用
NSLog(@"加载成功");
}];
调用此方法会下载URL所指向的网络图片(如果本地无缓存的话),并且可以监听下载进度以及下载完成事件
#import导入“SDImageCache.h”可实现储存加载的图像到缓存,并且可以找出储存的缓存,使图片显示
13 SizeClass 本质上就是AutoLayout
AutoLayout到底是什么?其实就是个约束布局
NSLayoutConstraint
UIButton *button=[[UIButton alloc]init];
[button setTitle:@"点击一下" forState:UIControlStateNormal];
button.translatesAutoresizingMaskIntoConstraints=NO;
[button setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:button];
NSArray *constraints1=[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[button]-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(button)];
NSArray *constraints2=[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[button(==30)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(button)];
[self.view addConstraints:constraints1];
[self.view addConstraints:constraints2];
14 arc
自动引用计数(Automatic Reference Counting, ARC)
引用计数: 快速复习
手工管理、引用计数式的内存管理在iOS中是这样工作的: 当使用alloc/init(或其它类似方法)创建对象时,随同对象返回的,还有个retainCount,其值为1,表明我们获得了这个对象的所有权。
NSObject *obj = [[NSObject alloc] init];
// do some stuff
[obj release];
在对象的alloc/init和release(即放弃对象的所有权)之间,我们可以任意处理它,这很安全,因为系统是无法回收正在使用中的对象的。
将对象加入到自动释放池也是类似,对象会一直存在,直到未来的某个时间我们不再需要它,才会被系统回收。
-(NSObject*) someMethod {
NSObject *obj = [[[NSObject alloc] init] autorelease];
return obj; // will be deallocated by autorelease pool later
}
ARC的工作原理
大多数新的iOS程序员都会在引用计数这问题上遇到理解障碍。ARC则是一个编译前的步骤,它为我们的代码自动加上retain/release/autorelease语句。
ARC并不是垃圾收集,而且,引用计数也没有消失,只是变成自动而已。听起来像是事后追加的这么一个功能,不过,只要我们想一想Objective-C有多少功能是通过对源文件的预处理来实现的,就不会这么想了。
当采用ARC后,代码只要这样写:
NSObject *obj = [[NSObject alloc] init];
// do some stuff
ARC会自动将它变成:
NSObject *obj = [[NSObject alloc] init];
// do some stuff
[obj release]; // **Added by ARC**
如果想开启ARC,只要在工程的Build Settings中设置ARC为YES。在幕后,实际上是设置了-fobj-arc的编译器标识。
ARC施加的新规则
如果想用ARC,必须服从一些新规则。
1. 对象的Alloc/Init
创建对象的方法跟以前一样,但你一定不能调用retain/release/autorelease/retainCount。也不能通过selector偷偷地调用它们: 禁止使用@selector(retain)和@selector(release)。
2. dealloc方法
ARC为自动为你调用,一定不能直接调用dealloc。不过,如果你需要释放实例变量以外的资源,还是可以创建自定义的dealloc方法。但在这个方法里,不要调用[super dealloc]。因为ARC会帮你调。
3. 声明的属性
在ARC之前,我们是用@property指令中的assign/retain/copy参数来告诉编译器,如何管理这些属性的内存。用了ARC之后,这些参数就作废了,改用weak/strong这两个参数。
4. C结构中的对象指针
同样禁止使用。文档里建议不要把它们放在结构了,改放到类里去。否则ARC就不认识它们了。可能会出现一些移植上的问题。不过,ARC是可以以文件为单位来关闭的。参考下文的“引入不兼容ARC的代码”。
5. id与void*之间的临时互转
当我们在Core Foundation的C函数和Foundation Kit的Objective-C方法间传递对象时,常常需要进行id和void*两个类型的互转。叫做无缝桥接(Toll Free Bridging)。
如果使用ARC,必须在CF对象进入和脱离ARC的控制时,用提示/限定符来告知编译器。限定符有__bridge、__bridge_retain和__bridge_transfer。另外,仍需要用CFRetain和CFRelease来管理Core Foundation的对象。
这一块已经比较高深了,如果你不清楚CF对象是什么,也不需要太烦恼。
6. 以@autoreleasepool代替NSAutoReleasePool
兼容ARC的代码不能再使用NSAutoReleasePool对象,而要改用@autoreleasepool{}块。一个很好的例子:
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([ExampleAppDelegate class]));
}
}
7. 其它
基于Zone的内存已经没了(在运行时里也没了)。不能再使用NSAllocateObject和NSDeallocateObject。
性能方面,早前有报告指出用ARC之后速度会变快,我想可能是由于减少对自动释放的依赖的缘故。虽然这完全可以通过改进代码、更好地使用retain/release来实现,但我觉得重点在于,ARC总是会自动帮你选择最优的方法。
探索iOS开发中的消息传递机制
KVO
KVO提供了这样一种机制:当对象中的某个属性值发生了改变,可以对这些值的观察者做出通知。KVO的实现包含在Foundation里面,基于 Foundation构建的许多Framework对KVO都有所依赖。要想了解更多关于如何使用KVO,可以阅读本期由Daniel写的的KVO和KVC文章。
如果对某个对象中值的改变情况感兴趣,那么可以使用KVO消息传递机制。这里有两个要求,首先,接收者(会接收到值发生改变的消息)必须知道发送者 (值将发生改变的那个对象)。另外,接收者同样还需要知道发送者的生命周期,因为在销毁发送者对象之前,需要取消观察者的注册。如果这两个要求都满足了, 消息传递过程中可以是1对多(多个观察者可以注册某个对象中的值)。
如果计划在Core Data对象上使用KVO,需要知道这跟一般的KVO使用方法有点不同。那就是必须结合Core Data的故障机制(faulting mechanism),一旦core data出现了故障,它将会触发其属性对应的观察者(即使这些属性值没有发生改变)。
Notification
在不相关的两部分代码中要想进行消息传递,通知(notifacation)是非常好的一种机制,它可以对消息进行广播。特别是想要传递丰富的信息,并且不一定指望有谁对此消息关心。
通知可以用来发送任意的消息,甚至包含一个userInfo字典,或者是NSNotifacation的一个子类。通知的独特之处就在于发送者和接 收者双方并不需要相互知道。这样就可以在非常松耦合的模块间进行消息的传递。记住,这种消息传递机制是单向的,作为接收者是不可以回复消息的。
delegation
delegation允许我们定制某个对象的行为,并且可以收到某些确定 的事件。为了使用delegation模式,消息的发送者需要知道消息的接收者(delegate),反过来就不用了。这里的发送者和接收者是比较松耦合 的,因为发送者只知道它的delegate是遵循某个特定的协议。
delegate协议可以定义任意的方法,因此你可以准确的定义出你所需要的类型。你可以用函数参数的形式来处理消息内容,delegate还可以 通过返回值的形式给发送者做出回应。如果只需要在相对接近的两个模块之间进行消息传递,那么Delegation是一种非常灵活和直接方式。
block
Block相对来说,是一种比较新的技术,它首次出现是在OS X 10.6和iOS 4中。一般情况下,block可以满足用delegation实现的消息传递机制。不过这两种机制都有各自的需求和优势。
当不考虑使用block时,一般主要是考虑到block极易引起retain环。如果发送者需要reatain
block,而又不能确保这个引用什么时候被nil,这样就会发生潜在的retain环。
假设我们想要实现一个table view,使用block替代delegate,来当做selection的回调,如下:
1
self.myTableView.selectionHandler = ^void(NSIndexPath *selectedIndexPath) {
2
// handle selection ...
3
};
上面代码的问题在于self retain了table view,而table view为了之后能够使用block,进而 retain了block。而table view又不能把这个引用nil掉,因为它不知道什么时候不在需要这个block了。如果我们保证不了可以打破这个retain环,而我们又需要 retain发送者,此时block不是好的选择。
NSOperation就可以很好的使用block,因为它能再某个时机打破retain环:
1
self.queue = [[NSOperationQueue alloc] init];
2
MyOperation *operation = [[MyOperation alloc] init];
3
operation.completionBlock = ^{
4
[self finishedOperation];
5
};
6
[self.queue addOperation:operation];
乍一看这似乎是一个retain环:self retain了queue,queue retain了operation,而operation retain了completion block,而completion blockretain了self。不过,在这里,将operation添加到queue时,会使operation在某个时机被执行,然后从queue 中remove掉(如果没有被执行,就会有大问题了)。一单queue移除了operation之后,retain环就被打破了。
再来一个示例:这里实现了一个视频编码器的类,里面有一个名为encodeWithCompletionHandler:的方法。为了避免出现retain环,我们需要确保编码器这个对象能够在某个时机nil掉其对block的引用。其内部代码如下所示:
1
@interface Encoder ()
2
@property (nonatomic, copy) void (^completionHandler)();
3
@end
4
5
@implementation Encoder
6
7
- (void)encodeWithCompletionHandler:(void (^)())handler
8
{
9
self.completionHandler = handler;
10
// do the asynchronous processing...
11
}
12
13
// This one will be called once the job is done
14
- (void)finishedEncoding
15
{
16
self.completionHandler();
17
self.completionHandler = nil; // <- Don‘t forget this!
18
}
19
20
@end
在上面的代码中,一旦编码任务完成,就会调用complietion block,进而把引用nil掉。
如果我们发送的消息属于一次性的(具体到某个方法的调用),由于这样可以打破潜在的retain环,那么使用block是非常不错的选择。另外,如 果为了让代码可读性更强,更有连贯性,那最好是使用block了。根据这个思路,block经常可以用于completion handler、error handler等。
Target-Action
Target-Action主要被用于响应用户界面事件时所需要传递的消息中。iOS中的UIControl和Mac中的 NSControl/NSCell都支持这种机制。Target-Action在消息的发送者和接收者之间建立了一个非常松散耦合。消息的接收者不知道发 送者,甚至消息的发送者不需要预先知道消息的接收者。如果target是nil,action会在响应链(responder
chain)中被传递,知道找到某个能够响应该aciton的对象。在iOS中,每个控件都能关联多个target-action。
基于target-action消息传递的机制有一个局限就是发送的消息不能携带自定义的payload。在Mac的action方法中,接收者总 是被放在第一个参数中。而在iOS中,可以选择性的将发送者和和触发action的事件作为参数。除此之外,没有别的办法可以对发送action消息内容 做控制。
做出正确的选择 Framework示例
本节我们通过一些来自苹果Framework的示例,来看看在实际使用某种机制之前,苹果是处于何种原因做出选择的。
KVO
消息的接收者(operation queue)明确的知道发送者(opertation),以及通过retain来控制operation的生命周期。另外,在这种情况下,只需要单向的消 息传递机制。当然,如果这样考虑:如果operation queue只关心operation值的改变情况,可能还不足以说服大家使用KVO。但是我们至少可以这样理解:什么机制可以对值的改变进行消息传递呢。
Notifications
Core Data使用notification来传递事件(例如一个managed object context内部的改变——NSManagedObjectContextDidChangeNotification)。
change notification是由managed object context发出的,所以我们不能确定消息的接收者一定知道发送者。如果消息并不是一个UI事件,而有可能多个接收者对该消息感兴趣,并且消息的传递属 于单向(one-way communication channel),那么notification是最佳选择。
Delegation
Blocks
Target-Action
Target-Action用的最明显的一个地方就是button(按钮)。button除了需要发送一个click事件以外,并不需要再发送别的信息了。所以Target-Action在用户界面事件传递过程中,是最佳的选择。
iOS程序运行流程{
1. 系统调用app的main函数
2. main函数调用UIApplicationMain.
3. UIApplicationMain创建sharedapplication instance, UIApplication默认的instance.
4. UIApplicationMain读取Info.plist找到主nib文件, 加载nib,把shared applicationinstance 设为nib的owner.
5. 通过nib文件,创建app的独立UIWindows object.
6. 通过nib,实例化了程序的AppDelegate object.
7. app内部启动结束,application:didFinishLaunchingWith-Options: 被设定成 wAppDelegate instance.
8. AppDelegate向UIWindowinstance发makeKeyAndVisible消息, app界面展示给用户. app准备好接收用户的操作指令.
}
什么是TCP连接的三次握手
第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。断开连接时服务器和客户端均可以主动发起断开TCP连接的请求,断开过程需要经过“四次握手”(过程就不细写了,就是服务器和客户端交互,最终确定断开)
利用Socket建立网络连接的步骤
建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket 。
套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
1。服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
2。客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
3。连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。