面试问题总结 (一)

210 阅读11分钟

1: 说说ARC和MRC的区别 

  • MRC(manual reference counting)手动内存管理
  • ARC(automatic reference counting 自动引用用计数)自动内存管理
  • Autoreleasepool自动释放池

    关于内存释放的本质:
    当一块内存释放的时候,本质上只是给这部分字节打了标签。并没有把字节里的二进制数据全部清成0或者1.
    所以,当一块内存说是释放了,但如果没有其他的二进制数据去填充它,那么它的内部数据是一直存在的。

    内存释放,数据仍然存在,就会出现一种僵尸对象的问题。
    什么是僵尸对象?堆空间已经被标记清空,能被其他数据使用。但此时此刻,新的二进制数据还没有进来。
    我们此时用一个指针指向已经标记释放了的堆空间。这个就叫僵尸对象和野指针。

    关于dealloc函数释放堆空间。

    在手动模式下:
    1、可以直接调用dealloc 强制标记当前堆空间直接被释放,而不用去管retainCount是否是0.
    2、每次调用release 把 retainCount-1 的同时会判断retainCount的最终值是否是0,是0接着调用dealloc函数标记当前堆空间释放。

    ARC自动引用计数
    所有堆空间在新指针引用时的 retainCount+1 在指针不引用时 retainCount-1。
    自动维护引用计数,并标记释放当前堆空间。不需要程序员去关心。

    补充一点:
    当一块堆空间被标记可以删除之后,即使暂时没有新的数据填充这块空间。原来空间的数据也不能【复活】过来重新使用。



2: 说说地图的使用 

在iOS开发中要用到地图时选择很多,例如第三方的高德地图、百度地图都是很好的选择,当然最基础的则是iOS中自带的地图,了解基础有助于我们更好的使用地图。

1.所用的框架:

定位:CoreLocation框架
地图:MapKit框架

2.用户配置

1.导入框架MapKit.framework
2.进行请求授权,在info.plist文件中进行配置key。注意:在这里有两种授权
1)NSLocationAlwaysUsageDescription:用户同意授权后可永久使用
2)NSLocationWhenInUseUsageDescription: 当用户打开对应的应用时可以使用(推荐使用)

3.定位与地图的使用

CoreLocation框架与MapKit框架是两个独立的单元,可单独使用,CoreLocation负责定位,MapKit负责地图的开发,通常会配合使用。

1.CoreLocation

这里需要用到操作类CLLocationManager

1)初始化操作类:

@property (nonatomic,strong) CLLocationManager *locationM;

这里我们使用一个懒加载,对操作类进行一次授权赋值

    if (!_locationM) {
        
        self.locationM = [[CLLocationManager alloc] init];
        
        //判断iOS版本
        if ([[UIDevice currentDevice].systemVersion floatValue]>=8.0) {
        
            //此处与info.plist授权配置一致
            [_locationM requestWhenInUseAuthorization];
        }
        
    }
    return _locationM;  

2)开始定位

[self.locationM startUpdatingLocation];

3)实现协议方法

定位成功后方法
注意:此方法在定位成功后会多次重复调用

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    //获取当前位置
    //注意:此处获取的经纬度为WGS84系经纬度,在与MapKit配合使用时,需转为GCJ-02经纬度
    CLLocation *currentLocation = [locations lastObject];
    
    //地理编码
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    
    [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        
        
        if (placemarks.count > 0) {
            
            CLPlacemark *placemark = placemarks[0];
            
            //所在城市
            NSString *city = placemark.locality;
            
            //社区
            NSString *neighborhood = placemark.subLocality;
            
            //街道
            NSString *thoroughfare = placemark.thoroughfare;
            
            NSString *subThoroughfare = placemark.subThoroughfare;
            
            //行政区域:省份
            NSString *province = placemark.administrativeArea;
            
            //子行政区域
            NSString *subProvince = placemark.subAdministrativeArea;

            //四大直辖市的城市信息无法通过locality获取,通过省份获取
            
        }

    }];
    
}

4)结束定位

[manager stopUpdatingLocation];

2.MapKit

1)地图设置
地图设置为属性
代理协议:MKMapViewDelegate

@property (nonatomic,strong) MKMapView *mapView;

    self.mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, kWidth, kHeight - 150)];
    
    //地图类型,枚举值
    self.mapView.mapType = 0;
    
    self.mapView.showsBuildings = YES;
    
    //显示用户当前位置
    self.mapView.showsUserLocation = YES;
    
    //罗盘与比例尺需在iOS9.0及以后版本中方可使用
    self.mapView.showsCompass = YES;
    self.mapView.showsScale = YES;
    
    //设置代理
    self.mapView.delegate = self;  

定位成功后代理方法
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
注意:此处定位成功后,代理方法中返回的userLocation经纬度为GCJ-02坐标,也就是‘火星坐标’,在mapView地图中,地图也已做了对应的偏移,故坐标不需要转换,可直接在地图上使用。

2)地图显示区域
所用结构体:MKCoordinateSpanMKCoordinateRegion

    //显示区域跨度
    MKCoordinateSpan span = MKCoordinateSpanMake(0.01, 0.01);
    
    //显示区域,第一个参数:经纬度为中心,第二个参数:跨区域显示
    MKCoordinateRegion region = MKCoordinateRegionMake(BGCJlocation, span);
    
    //在地图上显示
    [self.mapView setRegion:region animated:YES];

3)大头针
所用类:MapAnnotation

    //初始化
    _mkAnnotation = [[MapAnnotation alloc] init];  
    
    //大头针所在经纬度
    _mkAnnotation.coordinate = BGCJlocation;  
    
    //大头针title
    _mkAnnotation.title = @"目的地";
    //子标题
    _mkAnnotation.subtitle = @"xxx";  
    
    //添加到地图上
    [self.mapView addAnnotation:_mkAnnotation];

此大头针模型可与显示区域配合使用

4.WGS84经纬度转GCJ-02经纬度



3: 说说hybird应用的技术

juejin.cn/post/684490…

4: TableView的使用 tableViewcell基类的设计 

主要从cell的重用机制说起>

查看UITableView头文件,会找到NSMutableArray* visiableCells,和NSMutableDictnery* reusableTableCells两个结构。visiableCells内保存当前显示的cells,reusableTableCells保存可重用的cells。
重用机制是根据相同的标识符来重用cell的,标识符不同的cell不能彼此重用。

5: kvc和kvo的原理

KVO的全称是Key-ValueObserving(键值监听),可以用于监听某个对象属性值的改变。

  • 1.当给A类添加KVO的时候,runtime动态的生成了一个子类NSKVONotifying_A,让A类的isa指针指向NSKVONotifying_A类,重写class方法,隐藏对象真实类信息

  • 2.重写监听属性的setter方法,在setter方法内部调用了Foundation 的 _NSSetObjectValueAndNotify 函数

  • 3._NSSetObjectValueAndNotify函数内部

    a) 首先会调用 willChangeValueForKey

    b) 然后给属性赋值

    c) 最后调用 didChangeValueForKey

    d) 最后调用 observer 的 observeValueForKeyPath 去告诉监听器属性值发生了改变 .

  • 4.重写了dealloc做一些 KVO 内存释放

4、通过KVC设值age会不会触发KVO监听吗?

KVC也会触发KVO监听。其内部也是实现了willChangeValueForKey与didChangeValueForKey的调用。


KVC,键-值编码,使用字符串直接访问对象的属性。

底层实现,当一个对象调用setValue方法时,方法内部会做以下操作:

  • 1.检查是否存在相应key的set方法,如果存在,就调用set方法

    2.如果set方法不存在,就会查找与key相同名称并且带下划线的成员属性 _key,如果有,则直接给成员属性赋值

    3.如果没有找到_key,就会查找相同名称的属性  key,如果有就直接赋值

    4.如果还没找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法




6 : 说说你对自动释放池的理解 

结构:
简单说是双向链表,每张链表头尾相接,有 parent、child指针

每创建一个池子,会在首部创建一个 哨兵 对象,作为标记

最外层池子的顶端会有一个next指针。当链表容量满了,就会在链表的顶端,并指向下一张表。

实现:

  • App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()。

  • 第一个 Observer 监视的事件是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其 order 是 -2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。

  • 第二个 Observer 监视了两个事件: BeforeWaiting(准备进入休眠) 时调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池;Exit(即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池。这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。

  • 在主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被 RunLoop 创建好的 AutoreleasePool 环绕着,所以不会出现内存泄漏,开发者也不必显示创建 Pool 了。

7: 说说代理和Block

block其实是一个对象,代理是一种设计模式(委托-代理模式),本质不同

1.block简介

  在 iOS中, block一共分三种。

  (1)全局静态 block,不会访问任何外部变量,执行完就销毁。

 ^{
        NSLog(@"Hello World!");
    }();

  (2)保存在栈中的 block,当函数返回时会被销毁,和第一种的区别就是调用了外部变量。

    [UIView animateWithDuration:3 animations:^{
        self.view.backgroundColor = [UIColor redColor];
    }];

  (3)保存在堆中的 block,当引用计数为 0 时会被销毁。例如按钮的点击事件,一直存在,即使执行过,也不销毁,因为按钮还可能被点击。直到持有按钮的View被销毁,它才会被销毁。

#import <UIKit/UIKit.h>

typedef void(^ButtonClickBlcok)();

@interface TestView : UIView
@property (nonatomic, copy) ButtonClickBlcok buttonClickBlcok;
@end
#import "TestView.h"
@implementation TestView
- (IBAction)buttonClick:(id)sender {
    if (self.buttonClickBlcok) {
        self.buttonClickBlcok();
    }
}
@end

2.代理简介

  在为其他对象提供一种代理以控制对这个对象的访问。
在某些情况下,一个对象不适合或者不能直接引用另一个对象,
而代理对象可以在客户端和目标对象之间起到中介的作用。

在iOS中,代理作为一种消息传递方式,使用的非常普遍。
代理包括三部分:代理,委托,协议。
代理方通过实现协议里的方法,接收委托方传递过来的消息。

  • block 优势
    block 的代码可读性更好。因为block只要实现就可以了。
    代理 需要遵守协议并且实现协议里的方法,而两者还不在一个地方。代理使用起来也更麻烦,因为要声明协议、声明代理属性、遵守协议、实现协议里的方法

    block是一种轻量级的回调,可以直接访问上下文,由于block的代码是内联的,运行效率更高。block就是一个对象,实现了匿名函数的功能。所以我们可以把block当做一个成员变量、属性、参数使用,使用起来非常灵活。
    block 劣势
    blcok 的运行成本高。block出栈需要将使用的数据从栈内存拷贝到堆内存,当然对象的话就是引用计数加1,使用完或者block置nil后才销毁。
    delegate 只是保存了一个对象指针(一定要用week修饰delegate,不然也会循环引用),直接回调,没有额外消耗。就像C的函数指针,只多做了一个查表动作。
    block 容易造成循环引用,而且不易察觉。因为为了blcok不被系统回收,所以我们都用copy关键字修饰,实行强引用。block对捕获的变量也都是强引用,所以就会造成循环引用。

    5.如何使用

      优先使用block。
      如果回调的状态很多,多于三个使用代理。
      如果回调的很频繁,次数很多,像UITableview,每次初始化、滑动、点击都会回调,使用代理。
      block和代理都各有优缺点,所以我们一定要理解区分使用场景,应用适合的回调方式。优化APP的性能,提高流畅性,从点滴做起。


8: 说说对http的了解

HTTP超文本传输协议(HTTP,HyperText Transfer Protocol)
HTTP 协议本身是非常简单的。它规定,只能由客户端主动发起请求,服务器接收请求处理后返回响应结果(是基于TCP/IP协议进行通信的,TCP/IP协议是一个协议族,HTTP应用层,tcp传输层,ip网络层),同时 HTTP 是一种无状态的协议,协议本身不记录客户端的历史请求记录。

HTTP 请求 由3部分组成,分别是请求行、请求首部、请求体,首部和请求体是可选的,并不是每个请求都需要的。

HTTP 响应 服务端接收请求并处理后,返回响应内容给客户端,同样地,响应内容也必须遵循固定的格式浏览器才能正确解析。HTTP 响应也由3部分组成,分别是:响应行、响应首部、响应体,与 HTTP 的请求格式是相对应的。

Http 和 Https 的区别?Https为什么更加安全?

  • 区别
    1.HTTPS 需要向机构申请 CA 证书,极少免费。
    2.HTTP 属于明文传输,HTTPS基于 SSL 进行加密传输。
    3.HTTP 端口号为 80,HTTPS 端口号为 443 。
    4.HTTPS 是加密传输,有身份验证的环节,更加安全。
  • 安全
    SSL(安全套接层) TLS(传输层安全)
    以上两者在传输层之上,对网络连接进行加密处理,保障数据的完整性,更加的安全。
HTTPS连接过程大致可分为八步:
HTTP 三次握手 建立连接 四次挥手

  • TCP:面向连接、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。

  • UDP:面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快。


9: UIScrollView原理

UIScrollView 滑动效果是通过panGestureRecognize手势实现

ContentOffset、ContentSize、ContentInset还是Bounces效果本质都是在跟origin玩耍:Offset直接是origin的别称,而Size、Inset都是修改了origin的改变范围。
但是各个属性又有自己专有的作用,Size可以确定滚动的范围,而Inset可以在不修改原有滚动范围的同时,扩大总体滚动范围。
实现了这三个属性,也就能实现最基本的UIScrollView