某公司iOS面试题01

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前谁创建谁释放,谁引用谁管理的原则

{

单个对象内存管理;

多个对象内存管理;

僵尸对象处理;

  1. 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一次,但你要保证释放之后确实不再使用此对象,否则将导致错误

}

你可能感兴趣的:(某公司iOS面试题01)