iOS面试2021iOS 面试题整理

面试总结一

2020-12-23  本文已影响0人  纳兰沫

1.对于cell而言,使用自动布局和高度缓存哪种方式比较好,为什么

1.使用自动布局会根据给出的约束,在运行时对约束的描述信息进行求解,最终使用frame来绘制视图
2.iOS应用的视图要保持60fps的刷新帧率,那么必须在16.67ms之内完成包括布局,绘制以及渲染等操作,由于自动布局本身的计算量非常巨大,而且还有设置frame的过程消耗时间,那么当页面上的视图非常多的时候,自动布局就无法达到绝对流畅的要求
3.由于自动布局的实现原理导致他的时间复杂度为多项式时间,其性能损耗是仅使用frame的十几倍,所以,在处理庞大的UI界面时表现差强人意
4.强制视图在主线程上布局

2.UIWebView和WKWebView的区别

1.对于UIWebView而言 js的alert是可以直接执行的,而在WKWebView上,js弹窗是弹不出来的,需要通过WKUIDelegate协议接收弹窗事件,然后通过iOS原生弹窗runJavaScriptAlertPanel
2.UIWebView接受一个js字符串参数 返回一个字符串,同步执行
WKWebView接受一个js字符串参数 返回一个ID类型参数 异步执行
3.WKWebView js调用OC的方法使用交互管理WKUserContentController 注册方法 在didReceiveScriptMessage里面具体实现
4. WKWebView使用WKWebViewConfiguration可以设置一些属性 轻松的对载入的网页进行一些简单高效的配置
5.WKWebView的占用内存更小,加载速度比UIWebView更快
6.WKWebView的cookie问题很难处理 与js的交互不够灵活
//创建网页配置对象
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
        
// 创建设置对象
WKPreferences *preference = [[WKPreferences alloc]init];
//最小字体大小 当将javaScriptEnabled属性设置为NO时,可以看到明显的效果
preference.minimumFontSize = 0;
//设置是否支持javaScript 默认是支持的
preference.javaScriptEnabled = YES;
// 在iOS上默认为NO,表示是否允许不经过用户交互由javaScript自动打开窗口
preference.javaScriptCanOpenWindowsAutomatically = YES;
 
config.preferences = preference;
        
// 是使用H5的视频播放器在线播放, 还是使用原生播放器全屏播放
config.allowsInlineMediaPlayback = YES;
//设置视频是否需要用户手动播放  设置为NO则会允许自动播放
config.requiresUserActionForMediaPlayback = YES;
//设置是否允许画中画技术 在特定设备上有效
config.allowsPictureInPictureMediaPlayback = YES;
//设置请求的User-Agent信息中应用程序名称 iOS9后可用
config.applicationNameForUserAgent = @"ChinaDailyForiPad";

3.使用WKWebView进行和js的交互

1.oc调用js方法

使用evaluateJavaScript

//changeColor()是JS方法名,completionHandler是异步回调block
 NSString *jsString = [NSString stringWithFormat:@"changeColor('%@')", @"Js参数"];
    [_webView evaluateJavaScript:jsString completionHandler:^(id _Nullable data, NSError * _Nullable error) {
        NSLog(@"改变HTML的背景色");
 }];

1.js调用oc方法

//这个类主要用来做native与JavaScript的交互管理
WKUserContentController * wkUController = [[WKUserContentController alloc] init];
//注册一个name为jsToOcNoPrams的js方法,设置处理接收JS方法的代理
[wkUController addScriptMessageHandler:self  name:@"jsToOcNoPrams"];
[wkUController addScriptMessageHandler:self  name:@"jsToOcWithPrams"];
config.userContentController = wkUController;

注意:遵守WKScriptMessageHandler协议,代理是由WKUserContentControl设置
 //通过接收JS传出消息的name进行捕捉的回调方法  js调OC
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    NSLog(@"name:%@\\n body:%@\\n frameInfo:%@\\n",message.name,message.body,message.frameInfo);
}

WKWebView的使用
WKWebView和UIWebView的区别

4.WKWebview Cookie

WKWebview Cookie 如何存储的

session级别的cookie

session级别的cookie是保存在WKProcessPool里的,每个WKWebView都可以关联一个WKProcessPool,如果需要在整个App生命周期内访问h5保留h5里的登录状态,可以将使用WKProcessPool的单列来共享登录状态

WKProcessPool是没有属性和方法的对象,唯一的作用就是标识是不是需要新的session级别的管理对象,一个实例代表一个对象

未过期的cookie

有有效期的 cookie 被持久化存储在 NSLibraryDirectory 目录下的 Cookies/文件夹。

image
在Cookie目录下两个文件比较重要
Cookie.binarycookies
<appid>.binarycookies
两者的区别是<appid>.binarycookies是NSHTTPCookieStorag文件对象
Cookie.binarycookies是WKWebView实例化对象

这就是WKWebview 和 NSHTTPCookieStorage 的原因——因为被保存在不同的文件当中

WKWebview Cookie 如何工作的

1.当webView loadRequest或者302或者webView加载完毕,触发了ajax请求时,WKWebView所需的Cookie会去Cookie.binarycookies里读取本域名下的Cookie,加上WKProcessPool持有的Cookie一起作为request头里的Cookie数据

如何传递cookie

let cooki = "document.cookie = '这里是你需要的cookie值'
let userContentController = WKUserContentController()       
let userScript = WKUserScript(source: cooki, injectionTime:WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false)    

userContentController.addUserScript(userScript)       

let config = WKWebViewConfiguration()       
config.userContentController = userContentController    
   
var url = URLRequest(url: URL(string: sqlUrl)!, cachePolicy: URLRequest.CachePolicy.useProtocolCachePolicy, timeoutInterval: 20)       

webV = WKWebView(frame: UIScreen.main.bounds, configuration: config)

cookie

第一次拿到cookie

NSString *cookieStr = [self setupCookie];  //保持APP登录状态同步到web
WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource:cookieStr injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[configuration.userContentController addUserScript:cookieScript];
- (NSString *)setupCookie
{     NSMutableDictionary *cookieDic = [NSMutableDictionary dictionary];
      NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
      NSString *currentHostUrl = [IQHAPIService apiBaseUrlString];;
      NSString *hostDomin = [currentHostUrl stringByReplacingOccurrencesOfString:@"http://mobile" withString:@""];
      for (NSHTTPCookie *cookie in [cookieJar cookies]) {
          if ([hostDomin isEqualToString:cookie.domain]) {
             [cookieDic setObject:cookie.value forKey:cookie.name];
          }
      }
      NSString *sessionType = @"APPSESSIONID";
      NSString *cookieStr = @"";
      for (NSString *key in cookieDic) {
          if([key isEqualToString:@"SESSION"]){
              NSString *appendString = [NSString stringWithFormat:@"'%@=%@;path=/';",sessionType,[cookieDic valueForKey:key]];
              cookieStr = [NSString stringWithFormat:@"%@document.cookie=%@",cookieStr,appendString];
          }
      }
      return cookieStr;
}

5.远程推送原理

Provider是自己程序的后台服务器,APNS是Apple Push Notification Server的缩写,苹果推送服务器
分为三个阶段
1.应用程序的服务端把要发送的信息,目的iPhone的标识打包,发送给APNS
2.APNS在自身的已注册Push服务的iPhone列表中,查找相应标识的iPhone,并把消息发送到iPhone
3.iPhone把发来的消息传递给相应的应用程序,并且按照设定弹出Push通知


APNS推送通知的详细工作流程

1.应用程序注册APNS消息推送
2.iOS从APNS获取deviceToken 应用程序接受deviceToken
3.应用程序将device token发送给程序的PUSH服务器程序
4.服务端程序向APNS服务发送消息
5.APNS服务奖消息发送给iPhone应用程序

由于直接生成的证书windows系统是不识别的,所以我们需要生成一个后缀为pem的带证书带秘钥的文件

1.把.cer的ssl证书转换为.pem文件
openssl x509 -in aps_development.cer -inform der -out PushChatCert.pem
2.把私钥Push.p12证书转换为.pem文件
openssl pkcs12 -nocerts -out PushChatKey.pem -in Push.p12
3.把生成的两个pem文件再生成一个pem文件 把证书和私钥整合到一个文件里
cat PushChatCert.pem PushChatKey.pem > ck.pem
4.测试证书是否工作
telnet gateway.sandbox.push.apple.com 2195
5.使用SSL证书和私钥来设置一个安全的链接去链接苹果服务器
openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushChatCert.pem -key PushChatKey.pem
6.建立推送
在AppDelegate里didFinishLaunchingWithOptions函数里写

  • (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
    //推送的形式:标记,声音,提示
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeBadge |UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert];
    return YES;
    }

  • (void)application:(UIApplication *)applicationdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)pToken {
    NSLog(@"regisger success:%@",pToken);
    //注册成功,将deviceToken保存到应用服务器数据库
    }

  • (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
    // 处理推送消息
    NSLog(@"userinfo:%@",userInfo);

    NSLog(@"收到推送消息:%@",[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]);
    }

  • (void)application:(UIApplication *)applicationdidFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"Registfail%@",error);
    }

上一篇下一篇

猜你喜欢

热点阅读