1、Objective-C语言的消息机制和其他语言的普通函数调用有什么区别?
{
Objective-C通过互相传递消息实现函数调用,而C\C++直接进行函数调用
使用消息结构的语言,其运行时所应执行的代码由运行环境来决定。
使用函数调用的语言,则由编译器决定。
{
扩展:
1.继承:Objective-C与同Java和Smalltalk一样不支持多重继承,而C++语言支持多重继承(从侧面可以说明多重继承的效率不高);通过协议proctol和类目category实现多继承
2.函数调用:Objective-C通过互相传递消息实现函数调用,而C++直接进行函数调用
3.定型:Objective-C是动态定型(dynamicalytyped)。所以它的类库比C++要容易操作。Objective-C在运行时可以允许根据字符串名字来访问方法和类,还可以动态连接和添加类。而C++,对象的静态类型决定你是否可以发送消息给它。
4.接口:Objective-C采用protocol协议(非正式和正式)的形式来定义接口,而C++采用虚函数的形式来定义接口。
5.方法重载:c++中允许两个方法的名字相同,参数个数相同,但是参数类型不同,以及不同的返回值类型。而OC中不允许同一个类中两个方法有相同的名字,参数个数相同,参数类型不同。
}
}
2、UIView的frame、bounds、center有什么区别?各自的使用场景是什么?
{
frame当前视图在父视图中的位置和大小
bounds当前视图在自身坐标系中的位置和大小
center当前视图的中心点在父视图的位置;
使用场景
{
frame:设置视图的大小和位置
bounds:获取自身大小
center:改变或移动视图的位置。2、对视图旋转缩放也基于center
}
}
3、@property后面可以有哪些修饰符?分别列举说明具体含义,weak和assign的使用场景有什么区别
{
readwrite属性是可读可写,默认实现getter和setter方法| readonly属性是只读的,只创建了setter方法;
assign直接赋值,用于基本数据类型,包括c.不会涉及内存管理,如果修饰对象类型,可能导致内存泄露或EXC_BAD_ACCESS;
retain针对对象类型进行内存管理;在setter方法里会将旧对象属性release,对新对象进行一次赋值和retain操作;
copy主要用于NSString类型,表示复制内容;
atomic线程安全;
nonatomic非线程安全;
setter= |getter=设置自定义生成的getter和setter方法默认不在使用系统setter和getter;
strong类似retain只要有一个strong指针指向对象,该对象就不会被销毁;
weak:声明为weak的指针,weak指针指向的对象一旦被释放,weak的指针都将被赋值为nil;
weak和assign的使用场景
{
weak只可以修饰对象。;
assign可修饰对象,和基本数据类型;
assign适用于基本数据类型如int,float,struct等值类型,不适用于引用类型。因为值类型会被放入栈中,遵循先进后出原则,由系统负责管理栈内存。而引用类型会被放入堆中,需要我们自己手动管理内存或通过ARC管理。
weak适用于delegate和block等引用类型,不会导致野指针问题,也不会循环引用,非常安全。
}
}
4、UIViewController的loadView和viewDidLoad分别是什么时候调用的?哪一个函数不可以直接调用,如何间接触发他们的调用?
{
每次访问UIViewController的view(比如controller.view、self.view)而且view为nil,loadView方法就会被调用;
在view创建完毕后,不管是通过xib、storyboard还是loadView自定义view;
loadView不可以直接被调用
}
5、ARC和MRC下有哪些常见的内存泄露的场景,如何解决?
{
ARCxcode4.3后
{
循环引用;其中一个设置属性修饰符为ARC下weak或MRC下assgin
循环未结束;常见animation, viewController关掉时候,停止animation
指针未置空;当一个对象存入到集合中,解决方案:arr = nil;
非OBJC对象; malloc后接freenew后接delete
关于ARC与MRC的混编问题; ARC工程重新其中MRC文件.MRC工程反之
delegate和block
}
MRC xcode4.3前谁创建谁释放,谁引用谁管理的原则
{
单个对象内存管理;
多个对象内存管理;
僵尸对象处理;
- retain和release不匹配,retain多余release导致的内存泄露;
2)对象使用过程中,没有被release,而被赋值为nil;
3)在方法中不当的使用了retain;
}
}
6、CALayer的position和anchorPoint分别是什么?如何使用?
{
postion用来设置CALayer在父层中的位置;
anchorPoint决定着CALayer上的哪个点会在postion点上;
position点的位置根据锚点(anchorPoint)的值来确定;
frame.origin.x = position.x - anchorPoint.x * bounds.size.width;
frame.origin.y = position.y - anchorPoint.y * bounds.size.height;
position是相对于superLayer的point,anchorPoint是相对于自身layer;
anchorPoint锚点和position是永远物理重合的;
}
7、+(void)load;+(void)initialize;什么时候调用,有使用过这两个方法完成过什么功能么?
{
initialize和load的区别在于:load是只要类所在文件被引用就会被调用,而initialize是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有load调用;但即使类文件被引用进来,但是没有使用,那么initialize也不会被调用;
它们的相同点在于:方法只会被调用一次。
+(void)load
{
执行时机在程序运行后立即执行
若自身未定义,是否沿用父类的方法?否
类别中的定义全都执行,但后于类中的方法
}
+(void)initialize
{
执行时机在类的方法第一次被调时执行
若自身未定义,是否沿用父类的方法?是
类别中的定义覆盖类中的方法,只执行一个
}
使用过这两个方法完成过功能
{
使用method swizlling来修改原有的方法时,就是在分类load中实现的;
// load还可以实现无耦合的开屏广告
initialize做静态变量的设置并用于确保在实例初始化前某些条件必须满足.
}
}
8、Objective-C是否有多继承,为什么?如果有请写出一个多继承的类,没有,可以用什么方法来替代实现?
{
Objective-C没有多继承。
代替实现
{
消息转发
{
1.快速消息转发
检查该类是否实现了forwardingTargetForSelector:方法,若实现了则调用这个方法。若该方法返回值对象非nil或非self,则向该返回对象重新发送消息。
{
//------------------------------------------------------
@interface Teacher : NSObject
@end
//------------------------------------------------------
@interface Doctor : NSObject
- (void)operate;
@end
//------------------------------------------------------
#import"Doctor.h"
@implemetation Teacher : NSObject
- (id)forwardingTargetForSelector:(SEL)aSelector
{
Doctor *doctor = [[Doctor alloc]init];
if([doctor respondsToSelector:aSelector]) {
return doctor;
}
return nil;
}
@end
//------------------------------------------------------
@interface Teacher (DoctorMethod)
- (void)operate;
@end
导入头文件、调用时强转类型
Teacher *teacher = [[Teacher alloc]init];
[(Doctor *)teacher operate];
方法1使用类别足够清晰简便,我的想法是,方法1的弊端是抛出来的方法是定死的,而且在.h里露着;
方法2就相对灵活,而且隐藏了我要转发的消息。
}
2.标准消息转发
runtime发送methodSignatureForSelector:消息获取Selector对应的方法签名。返回值非空则通过forwardInvocation:转发消息,返回值为空则向当前对象发送doesNotRecognizeSelector:消息,程序崩溃退出。;
{
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector ;
{
NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];
if(signature==nil) {
signature = [someObj methodSignatureForSelector:aSelector];
}
NSUInteger argCount = [signature numberOfArguments];
for(NSInteger i=0; i
两种消息转发方式的比较;
快速消息转发:简单、快速、但仅能转发给一个对象。;
标准消息转发:稍复杂、较慢、但转发操作实现可控,可以实现多对象转发。;
}
delegate和protocol
{
}
类别
{
@interface Teacher : NSObject
{
NSUInteger age;
}
@end
//------------------------------------------------------
//
//Teacher+Profession.m
//
#import"Teacher+Profession.h"
#import
constchar*ProfessionType ="NSString *";
@implementation Teacher (Profession)
-(void)setProf:(NSString*)prof
{
objc_setAssociatedObject(self, ProfessionType, prof, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)prof
{
NSString *pro = objc_getAssociatedObject(self, ProfessionType);
return pro;
}
@end
9、谈谈你对MVC的Model的理解和MVVM中ViewModel的理解
{
MVC的Model模型负责保持数据,或者对数据的任何操作
MVVM中ViewModel我理解的ViewModel是一个过渡的层,首先Model层获取数据,在ViewModel里对Model层进行操作,将model的数据在view上进行绑定,
然后操作出一个View出来,然后直接在View层显示。这就节省了Controller中View的代码。
}
10、现在我们有一个UIButton按钮的大小只有20px30px,请问怎么样可以在不改变按钮尺寸增大响应区域到44px44px?
{
1、重写UIButton的pointInside: withEvent:方法;
{
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
{
CGRect bounds = self.bounds;
CGFloat widthDelta = MAX(44.0-self.bounds.size.width,0);
CGFloat heightDelta = MAX(44.0-self.bounds.size.height,0);
bounds = CGRectInset(bounds,-0.5*widthDelta,-0.5*heightDelta);
return CGRectContainsPoint(bounds,point);
}
}
2、利用Objective-C中的objc_setAssociatedObject來記錄要變大的範圍;
{
static char topNameKey;
static char rightNameKey;
static char bottomNameKey;
static char leftNameKey;
- (void) setEnlargeEdgeWithTop:(CGFloat) top right:(CGFloat) right bottom:(CGFloat) bottom left:(CGFloat) left
{
objc_setAssociatedObject(self, &topNameKey, [NSNumber numberWithFloat:top], OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_setAssociatedObject(self, &rightNameKey, [NSNumber numberWithFloat:right], OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_setAssociatedObject(self, &bottomNameKey, [NSNumber numberWithFloat:bottom], OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_setAssociatedObject(self, &leftNameKey, [NSNumber numberWithFloat:left], OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (CGRect) enlargedRect
{
NSNumber* topEdge = objc_getAssociatedObject(self, &topNameKey);
NSNumber* rightEdge = objc_getAssociatedObject(self, &rightNameKey);
NSNumber* bottomEdge = objc_getAssociatedObject(self, &bottomNameKey);
NSNumber* leftEdge = objc_getAssociatedObject(self, &leftNameKey);
if(topEdge && rightEdge && bottomEdge && leftEdge)
{
return CGRectMake(self.bounds.origin.x - leftEdge.floatValue,
self.bounds.origin.y - topEdge.floatValue,
self.bounds.size.width + leftEdge.floatValue + rightEdge.floatValue,
self.bounds.size.height + topEdge.floatValue + bottomEdge.floatValue);
}
else
{
return self.bounds;
}
}
//重写
- (UIView*) hitTest:(CGPoint) point withEvent:(UIEvent*) event
{
CGRect rect = [self enlargedRect];
if(CGRectEqualToRect(rect, self.bounds))
{
return [super hitTest:point withEvent:event];
}
return CGRectContainsPoint(rect, point) ? self : nil;
}
//重写
- (UIView*) pointInside:(CGPoint) point withEvent:(UIEvent*) event
{
CGRect rect = [self enlargedRect];
if(CGRectEqualToRect(rect, self.bounds))
{
return [super hitTest:point withEvent:event];
}
return CGRectContainsPoint(rect, point) ? self : nil;
}
}
11、请结合单例和block补全下面代码完成一个简单加法的计算器?
{
#import"CalculateManager.h"
@implementation CalculateManager
+ (instanceType)sharedManager
{
static CalculateManager * sharedInstanceCM = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
sharedInstanceCM = [[CalculateManager alloc] init];
});
return sharedInstanceCM;
}
- (int64_t)calculateParamA:(int64_t)a ParamB:(int64_t)b
{
int64_t (^addBlock)(int64_t , int64_t) = ^(int64_t a,int64_t b){
return a+b;
});
return addBlock(a,b);
});
@end
}
12、寻找面代码中存在的bug,会出现什么错误,如何修复?
{
@property (nonatomic,strong) UILabel *label;
[waitQueue addOpetationWithBlock:^{
[Thread sleepUtilDate:[NSDate dateWithTimeIntervalSinceNow:10]];//sleep10秒
self.label.text = @"Thanks!";
}];
//多线程代码部分NSOperationQueue的addOperationWithBlock函数不能保证block里面的语句是在主线程中运行的,UILabel显示文字属于UI更新,必须要在主线程进行,否则会有未知的操作,无法在界面上及时正常显示
//解决方法
//同步到主线程03
[self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO];
/**
* UI更新函数
*/
- (void)updateUI {
self.alert.text = @"Thanks!";
}
//同步到主线程01
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.alert.text = @"Thanks!";
}];
//同步到主线程02
dispatch_async(dispatch_get_main_queue(), ^{
self.alert.text = @"Thanks!";
});
}
13、实现在Container View Controller中添加移除一个ChildViewController
{
- (void) addViewController:(UIViewController *)childViewController
{
[self addChildViewController:childViewController];
[self.view addSubView:childViewController.view];
[childViewController didMoveToParentViewController:self];
}
- (void) removeViewController:(UIViewController *)childViewController
{
[childViewController willMoveToParentViewController:nil];
[childViewController.view removeFromSuperView];
[childViewController removeToParentViewController];
}
}
14、分别用imageNamed:和initWithContentsOfFile实现加载一张“logo.png”的图片,简述这两种加载方式有什么不同,应用场景以及优缺点?
{
UIImage *img1 = [UIImage imageNamed:@"logo.png"];
NSString *path = [NSString stringFomat:@"%@/%@",[[NSBundle mainBundle] resourcePath],@"logo.png"];
UIImage *img2 = [[UIImage alloc] initWithContentsOfFile:path];
//+imageWithContentsOfFile和initWithContentsOfFile
{
仅仅加载图片,图像数据不会被缓存.因此在加载较大图片的时候,以及图片使用情况很少的时候可以使用这两个方法,降低内存消耗.
imageWithContentsOfFile加载的图片是不会缓存的。得到的对象时autoRelease的,当autoReleasePool释放时才释放。
initWithContentsOfFile要手动release掉。不系统缓存。release后立即释放,一般用在封面等图比较大的地方
}
//imageNamed的方式加载时
{
imageNamed的方式加载时,会把图像数据根据它的名字缓存在系统内存中,以提高imageNamed方法获得相同图片的image对象的性能。即使生成的对象被autoReleasePool释放了,这份缓存也不释放。而且没有明确的释放方法。如果图像比较大,或者图像比较多,用这种方式会消耗很大的内存。
}
使用场景
{
imageNamedUI界面中的贴图的读取,较大的资源文件应该尽量避免使用
initWithContentsOfFile用在封面等图比较大的地方
}
优缺点
{
使用imageNamed方式,用同一张图片贴多个imageView应该是经过极大的优化,耗时和内存都极小,而使用imageWithContentsOfFile则有巨大消耗
}
}
15、对数组进行内容去重,要求时间复杂度尽量低。若是要求去重并有序?
{
NSArray *array = @[@"1000",@"1000",@"1000",@"1001",@"1001",@"1002",@"1003",@"1004",@"1005"];
//利用NSDictionary的AllKeys(AllValues)方法
NSMutableDictionary *mDic = [NSMutableDictionary dictionary];
for(NSString * itemStrin array)
{
[mDic setObject:itemStr forKey:itemStr];
}
NSLog(@"%@",[mDic allValues]);
//利用NSSet的allObjects方法
NSSet *set = [NSSet setWithArray:array];
NSLog(@"%@",[set allObjects]);
//有序去重
NSMutableArray *mArr = [NSMutableArray array];
for(unsignedi =0;i
{
if(![mArr containsObject:[array objectAtIndex:i]])
{
[mArr addObject:[array objectAtIndex:i]];
}
}
//第一种,利用数组的sortedArrayUsingComparator调用NSComparator,obj1和obj2指的数组中的对象
{
NSComparator cmptr = ^(id obj1, id obj2){
if([obj1 integerValue] > [obj2 integerValue]) {
return(NSComparisonResult)NSOrderedDescending;
}
if([obj1 integerValue] < [obj2 integerValue]) {
return(NSComparisonResult)NSOrderedAscending;
}
return(NSComparisonResult)NSOrderedSame;
};
NSArray *sortArray = [array sortedArrayUsingComparator:cmptr];
}
//第二种排序方法利用sortedArrayUsingFunction调用对应方法customSort,这个方法中的obj1和obj2分别是指数组中的对象。
{
NSInteger customSort(id obj1, id obj2,void* context){
if([obj1 integerValue] > [obj2 integerValue]) {
return(NSComparisonResult)NSOrderedDescending;
}
if([obj1 integerValue] < [obj2 integerValue]) {
return(NSComparisonResult)NSOrderedAscending;
}
return(NSComparisonResult)NSOrderedSame;
}
NSArray *array = [sortArray sortedArrayUsingFunction:customSort context:nil];
}
//第三种利用sortUsingDescriptors调用NSSortDescriptor
{
//针对对象中属性排序
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"price"ascending:NO];//其中,price为数组中的对象的属性,这个针对数组中存放对象比较更简洁方便
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:&sortDescriptor count:1];
[_totalInfoArray sortUsingDescriptors:sortDescriptors];
[_airListView refreshTable:_totalInfoArray];
}
}
16、strong和weak使用
{
何时使用的问题,如果一个对象在某段时间中反复加载,而你又不希望每次加载都要重新alloc的话,那就strong,strong保证对此对象保持一个强引用,对于这个对象,只要有1个strong引用的话,那它就不会释放,当然多个strong同时作用于它也不会释放。
如果一个对象在某段时间只会加载一次,并且加载之后确定不再使用了,那就可以使用weak,这样当其他原因导致引用计数减1(比如removefromsuperview)的时候,此对象就自动释放了。无需再在delloc里面再release一次,但你要保证释放之后确实不再使用此对象,否则将导致错误
}