UICollectionView

最近做需求做到了和 UICollectionView 相关的内容,特此补充整理知识漏洞

UICollectionView 包含多个子类 (subclass) 和协议 (protocol)

  1. 最高级别的控制和管理
    1. UICollectionView → 和 UITableView 一样,作为 UIScrollView 的继承子类,是主要展示内容的页面 作为一个容器,一个中间者,连接起五个不同的部分,并通知和引导数据的流通。
    2. UICollectionViewController
  2. 内容管理
  3. UIViewCollectionDataSource → 供给对应数据来源,告诉 UICollectionView 有几个 section,以及 section 当中应该展示的个数
    1. UIViewCollectionDelegate
      1. 处理事件顺序
        1. 手指按下
          1. shouldHighlightItemAtIndexPath → Yes 则向下执行,No 则到此为止
          2. didHighlightItemAtIndexPath → 高亮
        2. 手指松开
          1. didUnHighlightItemAtIndexPath → 取消高亮
          2. shouldSelectHighlightItemAtIndexPath → Yes 则向下执行,No 则到此为止
          3. didSelectItemAtIndexPath → 执行选择事件
  4. 展示
    1. UICollectionViewCell
      1. 和 UITableViewCell 类似,这些 Cells 作为 CollectionViewCell 的子类,组成了对应的页面内容 
      2. 通过 registerClass:forCellReuseIdentifier: 或 registerNib:forCellReuseIdentifier: 来实现添加自定义的子 Cell
      3. 可以通过
    2. UICollectionReusableView
      1. 当有其他的信息需要在 CollectionView 中展示,但他们不应该在 Cell 里面时,可以利用 supplementary view,一般包含 header 和 footer。
      2. 通过 registerClass:forSupplementaryViewOfKind:withReuseIdentifier: 或 registerNib:forSupplementaryViewOfKind:withReuseIdentifier: 来添加对应的自定义子Cell
  5. 布局
    1. UICollectionViewLayout → 告诉 UICollectionView 中每个 section 的大小和位置信息,可以改变对应视图的大小,位置以及其他的属性
      1. 常用属性:
        1. minimumLineSpacing 行间距,但在每行内 cell 大小都不一致的情况下, 会计算上行最底和下行最顶的间距
        2. minimumInterItemSpacing 列间距
        3. UICollectionViewScrollDirection 滑动方向
    2. UICollectionViewLayoutAttributes → 定义了 UICollectionView 的一些其他属性,例如边框,中心点,大小,是否可隐藏等等属性
    3. UICollectionViewUpdateItem
  6. 流动布局
    1. UICollectionFlowLayout → 用于实现如 grids 或者其他 line-based 的页面布局。 
    2. UICollectionDelegateFlowLayout

众多子类和协议中, UICollectionViewDataSource (datasource 实现),UICollectionViewDelegate 和 UICollectionViewDelegateFlowLayout(controller 实现)。

GCD 多线程

DispatchQueue(简称 GCD) 是 iOS 提供的一套允许代码以多核并发的方式执行程序的一种执行方式。

同步和异步的区别在于线程会等待同步任务执行完成,而线程不会等待异步任务执行完成,而同步和异步任务则是用 syn{ } 和 asyn { } 代码块涵盖的内容。

除此之外,GCD 还会通过两种队列(串行并发)来管理和决定其执行的顺序。串行的状态下,任务会按照队列的顺序一个一个地运行。而在并发的状态下,任务则会快速切换实现“伪同步”运行的效果。

以 GCD 为对象深入了解 iOS 多线程

  • 串行异步

会开启新的线程,按照顺序并一个一个完成任务

  • 串行同步

不会开启新的线程,同样是一步一步地完成任务,要求先执行对应的任务

  • 并行异步

会开启新的线程,并行操作多线程执行任务,任务交替执行

  • 并行同步

不会开启新的线程,所以等执行完一个任务才会执行下一个任务,会导致死锁

  • 主队列同步

在这种场景下,会导致死锁的产生,因为将新的任务添加到主队列中意为着主队列得先完成自己的任务才能完成新的任务,但由于同步,要求得先执行新的任务再执行主队列自己的任务,所以两个产生冲突,导致队列阻塞,导致死锁。

在取消网络请求的应用场景,可以直接在主队列添加任务,而不需要使用并行队列,因为倒计时的任务量不大,在每秒内都可以执行完毕,不会导致主线程拥塞。

GCD 提供几种多线程调用的方法:

  • dispatch_after

倒计时结束后,将block的任务添加到指定的任务队列去里面去

  • dispatch_once

用于执行单例模式

  • dispatch_block

用于实现一个 block 对象,可以方便后续的函数调用 block

  • dispatch_group

用于分组管理异步代码,包括以下三种用法:

  • notify (依赖)

可用于判断组内任务是否完成

  • wait (等待)

可用于等待任务完成

  • enter / group (手动管理计数)

手动添加/减少组内任务,必须一一对应

  • dispatch_semaphore

用于实现线程同步和加锁,同样是三种方法

  • create:用于控制并发数
  • wait:对应信号量的 P 操作,即请求资源,当 > 0 的时候会 – 1, < 0 的时候会等待
  • signal:对应信号量的 V 操作,即释放资源, + 1,可用于唤醒其他线程

可以用于监视某些事情的发生

参考

实操 https://leylfl.github.io/2018/01/16/%E6%B5%85%E8%B0%88iOS%E5%A4%9A%E7%BA%BF%E7%A8%8B-%E4%BD%BF%E7%94%A8%E7%AF%87/

样例:https://juejin.cn/post/6844903766701916168

NSLocalString

苹果针对本土化的服务一直精益求精,在代码中甚至专门用一个NSLocal的对象来实现本地化

NSLocal 的运行原理也非常简单,通过获取用户的系统语言 / 性别 / 国籍 / 地区等等,来实现同一个UI / 功能的不同呈现。如果不用本地化的方法写的话,可能需要用多个 if-else 来处理,但用 NSLocal 这个类似于字典的结构就可以很轻松地实现这个功能

NSLocalizedString

字符串的本土化,最普遍使用

有多种使用方法,一下为最基础的

NSLocalizedString(key, comment)
[NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:nil]

其中的 key 参数为表中的key – value 值的 key,comment 值则为注释

例如同样一个

NSLocalizedString("Debug", nil);

有三个本地化的String

//English
"Debug" = "debug";
//Simple-Chinese
"Debug" = "测试";
//Traditional-Chinese
"Debug" = "調試";

则在三种环境下的值也会不一样,判断的依旧是手机的配置

//TODO

图片及其他本地化 (参考:https://xiaovv.me/2017/06/04/Localization-of-iOS/

CALayer

UIView 作为 iOS 的 UI 最基础的界面显示,CALayer 是 UIView 的一个关键属性,在Apple Documentation给出的定义是

An object that manages image-based content and allows you to perform animations on that content.

翻译成中文就是管理基于图像内容的对象,且允许对此对象执行动画

总览

一般来说,layer是用来存储 Views 的后备数据,但 layer 本身也可以脱离 View 而独立使用。Layer 的主要作用是管理视觉内容,但 layer 本身就有一些可被设置的视觉属性,例如背景色 (background color),边框 (border) 和 阴影 (shadow)。除此之外,layer 还包括一些几何信息可在屏幕上显示的信息,例如位置 (position),大小 (size) 和变换 (transform)。

如果 layer 对象是由 View 创建的话,View 自己会自动将自己赋入 layer 的代理 (delegate),但对于自己创建的 layer,可以自己选择赋入的代理 View,可以动态绑定。

和 UIView 的关系

看完总览肯定有人觉得奇怪,既然 layer 管理了 UIView 的视觉内容,干嘛还要分开管理,为什么不把 layer 和 View 合二为一,用 layer 或者 View 来处理所有的事件呢?

  • 职责不同UIView 负责响应事件,Layer 负责渲染界面,单独把 layer 分出来就是为了处理仅渲染界面的情况UIView 和其他由 UIView 派生出来的类都继承自 UIResponder, 在 UIResponder 中定义了处理各种事件的和事件传递的接口,详情可看我之前关于 iOS 相应链的文章(链接),而 CALayer 则是直接继承自 NSObject,不会对事件进行处理。
  • 分工不同除此之外,UIView 主要针对显示内容的管理,而 CALayer 则侧重于显示内容的绘制也因此,在做 iOS 动画的时候,修改非 RootLayer 的属性(位置和背景色等)会默认产生隐式动画,而修改 UIView 则不会
  • 内部结构不同Layer 内部维护三部分 layer tree,分别是 presentLayer Tree(动画树),modeLayer Tree(模型树),Render Tree (渲染树)。

Mask

mask, 即遮罩,是一个可选的layer,他的 Alpha 通道值用于遮盖 layer 的内容

可以通过 mask.content 来处理,在 content 中设置相关参数,从而实现遮罩的效果

除此之外,还可以通过 CAShapeLayer 来画出遮罩的类型

引用

https://developer.apple.com/documentation/quartzcore/calayer
http://www.cocoachina.com/articles/13244
https://zsisme.gitbooks.io/ios-/content/index.html

VIM 常见命令

  • 用 h j k l 表示⬅️⬇️⬆️➡️
  • x → 删除字符
  • dw → 删除单词 (光标需在第一个字母)
  • dd → 删除整行 (会存在 Vim 里)
  • u → 撤回一条命令
  • U → 撤回一行的命令(对一行操作)
  • y → 复制
  • p → 取出 Vim 内容并放在此处 / 粘贴
  • ctrl + g → 查看当前行数
  • G → 跳到尾部 
  • 行数 + G → 跳到xx行
  • gg → 跳到头部
  • / → 搜索
  • 用 n 往下找
  • 用 N 往上找
  • % → 移动光标到对应括弧
  • :s /old / new/g → 替换将该行的
  • :q → 不保存退出
  • :wq → 保存并退出
  • :w → 只保存不退出
  • :help → 打开help 文件
  • ctrl + w → 在文件中转换

CannyX

项目汇报

目标一:实时调用摄像头输出视频流到屏幕,提供按钮选择前置或后置

使用 AVCaptureSession( ) 来调用摄像头

let session = AVCaptureSession()
var previewLayer: AVCaptureVideoPreviewLayer!
var sequenceHandler = VNSequenceRequestHandler()
let dataOutputQueue = DispatchQueue(
  label: "video data queue",
  qos: .userInitiated,
  attributes: [],
  autoreleaseFrequency: .workItem)

处理摄像头的参数

    func configureCaptureSession() {
    // Define the capture device we want to use
    // default position : .back
    guard let camera = AVCaptureDevice.default(.builtInWideAngleCamera,
                                               for: .video,
                                               position: .back) else {
      fatalError("No back video camera available")
    }

    // Connect the camera to the capture session input
    do {
      let cameraInput = try AVCaptureDeviceInput(device: camera)
      session.addInput(cameraInput)
    } catch {
      fatalError(error.localizedDescription)
    }

    // Create the video data output
    let videoOutput = AVCaptureVideoDataOutput()
    videoOutput.setSampleBufferDelegate(self, queue: dataOutputQueue)
    videoOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA]

    // Add the video output to the capture session
    session.addOutput(videoOutput)

    let videoConnection = videoOutput.connection(with: .video)
    videoConnection?.videoOrientation = .portrait
    // Configure the preview layer
    previewLayer = AVCaptureVideoPreviewLayer(session: session)
    previewLayer.videoGravity = .resizeAspectFill
    previewLayer.frame = view.bounds
    view.layer.insertSublayer(previewLayer, at: 0)
  }

处理前置后置摄像头的替换

// Button Action function
@IBAction func cameraChangedButton(_ sender: Any) {
  // stop running the session to change camera state
  session.stopRunning() 

  // remove the current camera setting
    let currentCameraInput: AVCaptureInput = session.inputs[0]
  session.removeInput(currentCameraInput) 

  // setting new camera .back to .front and .front to .back
  newCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)

  //adding new camera setting
  let cameraInput = try AVCaptureDeviceInput(device: newCamera)
          session.addInput(cameraInput)
          session.outputs[0].connection(with: .video)?.videoOrientation = .portrait
  // Check if need to mirror the video
            session.outputs[0].connection(with: .video)?.isVideoMirrored = (cameraChangeButtonState.currentTitle == "Front" ? true : false)
    session.startRunning()
} 

目标二:提供按钮支持边缘检测功能

使用 Cocoapods 导入 OpenCV 库

pod 'OpenCV'

在 Swift 中无法直接调用 C++ 的库,需要用 OC 进行调用,并进行桥接实现混编。因此在本项目中,edgeDetector 作为 C++ 文件直接使用 OpenCV 库中的 Canny 函数检测边缘,并通过 OpenCVWrapper (OC 文件) 调用 edgeDetector 中的类, 最后在 Project-Bridging-Header.h 中桥接在 ViewController 中使用相关的 OC 函数

此处需将 OpenCVWrapper.m 改为 OpenCVWrapper.mm 以进行 OC 和 C++ 的混编

@implementation OpenCVWrapper : NSObject
- (UIImage *) detectEdgeIn: (UIImage *) image{
    // convert uiimage to mat
        cv::Mat opencvImage;
        UIImageToMat(image, opencvImage, true);
    // convert colorspace to the one expected by the lane detector algorithm (RGB)
        cv::Mat convertedColorSpaceImage;
        cv::cvtColor(opencvImage, convertedColorSpaceImage, COLOR_RGBA2RGB);

    // Run lane detection
    edgeDetector Detector;
    cv::Mat imageWithEdgeDetected = Detector.detect_edges(convertedColorSpaceImage);

    // convert mat to uiimage and return it to the caller
    return MatToUIImage(imageWithEdgeDetected);
}
@end

在 edgeDetector 中用获取边缘图

Mat edgeDetector::detect_edges(Mat image) {

    Mat greyScaledImage;
    cvtColor(image, greyScaledImage, COLOR_RGB2GRAY);

    Mat edgedOnlyImage;
    Canny(greyScaledImage, edgedOnlyImage, 50, 120);
    Mat newBImg(edgedOnlyImage.rows, edgedOnlyImage.cols, edgedOnlyImage.type());
    uchar* newBImgData = newBImg.data;
    uchar* binaryData = edgedOnlyImage.data;
    int step = edgedOnlyImage.step / sizeof(uchar);

    for (int i = 0; i<edgedOnlyImage.rows; i++)
        for (int j = 0; j<edgedOnlyImage.cols; j++)
            newBImgData[i*step + j] = 255 - binaryData[i*step + j];

    edgedOnlyImage = newBImg.clone();
    uchar r, g, b;
        // Converted canny image to BGRA4 channel image
    cvtColor(edgedOnlyImage, edgedOnlyImage, COLOR_GRAY2BGRA);
    for (int i = 0; i < edgedOnlyImage.rows; i++)
        for (int j = 0; j < edgedOnlyImage.cols; j++)
        {
            // R
            r = edgedOnlyImage.at<Vec4b>(i, j)[2];
            // G
            g = edgedOnlyImage.at<Vec4b>(i, j)[1];
            // B
            b = edgedOnlyImage.at<Vec4b>(i, j)[0];

            if (r > 220 && b > 220 && g > 220)
            {
                // A
                edgedOnlyImage.at<Vec4b>(i, j)[3] = 0;
            }
            if (r < 20 && b < 20 && g < 20)
            {
                // A
                edgedOnlyImage.at<Vec4b>(i, j)[1] = 255;
                edgedOnlyImage.at<Vec4b>(i, j)[2] = 0;
                edgedOnlyImage.at<Vec4b>(i, j)[0] = 0;
            }
        }
    return edgedOnlyImage;
}

通过 Project-Bridging-Header.h 中桥接,可以直接在 ViewController 中使用相关的 OC 函数

// get images from the camera
guard let  imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
        CVPixelBufferLockBaseAddress(imageBuffer, CVPixelBufferLockFlags.readOnly)
        let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer)
        let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer)
        let width = CVPixelBufferGetWidth(imageBuffer)
        let height = CVPixelBufferGetHeight(imageBuffer)
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        var bitmapInfo: UInt32 = CGBitmapInfo.byteOrder32Little.rawValue
        bitmapInfo |= CGImageAlphaInfo.premultipliedFirst.rawValue & CGBitmapInfo.alphaInfoMask.rawValue
        let context = CGContext(data: baseAddress, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo)
        guard let quartzImage = context?.makeImage() else { return }
        CVPixelBufferUnlockBaseAddress(imageBuffer, CVPixelBufferLockFlags.readOnly)
        let image = UIImage(cgImage: quartzImage)

因为不能在此处使用UIKit相关的操作,所以需要放入 DispatchQueue.main.async 保证线程安全

let imageWithEdgeOverlay = OpenCVWrapper().detectEdge(in: image)
DispatchQueue.main.async {
  self.CannyView.image = imageWithEdgeOverlay
}

目标三:用 C++ 实现图像均值计算库,导入并实时计算图像均值

用 C++ 实现图像均值我还是沿用了 OpenCV 里的计算库, 考虑到最后导入到项目中还是需要混合编程, 再加上新版 Xcode 不支持写 C++ 的库和框架, 所以最后用 OC 实现

同样,在 OC 中使用混编需要将 .m 文件改成 .mm

@implementation AveragePiexlValueOC : NSObject 
- (double) PixelValueOC: (UIImage *) image{
    cv::Mat opencvImage;
    UIImageToMat(image, opencvImage, true);
    pixelValue calculator;
    double result = calculator.averagePixelValue(opencvImage);
    return result;
}
@end
double pixelValue::averagePixelValue(Mat image)
{
    Scalar mean;
    Scalar dev;
    meanStdDev ( image, mean, dev );
    return mean.val[0];
};

运行后获得 libAveragePiexlValueOC.a 的静态库,将其及 AveragePiexlValueOC.h 拉入项目中,在 Project-Bridging-Header.h 中桥接,便可以在 ViewController 中使用

和 CannyView 一样,需要放入 DispatchQueue.main.async

var averagePixelValueData2 = AveragePiexlValueOC().pixelValueOC(image)
DispatchQueue.main.async {
            self.dataShow.text = "AVERAGE PIXEL: "+String(format: "%.2f", averagePixelValueData2)
            self.CannyView.image = imageWithEdgeOverlay
        }

AppUI相关

App图标

App 启动页

App 主界面UI

对应层级图

最终效果展示

后置摄像头

前置摄像头

计算像素均值

获取边缘

面试题目汇总

一些面试(可能会)遇到的题目,总结整理一下

C++相关

C++内存管理机制

C++内存分为五个区

  • 堆 —— new 申请, delete 释放
  • 栈 —— 局部变量
  • 自由存储区 —— malloc 申请, free 释放
  • 静态区 —— 全局变量和静态变量
  • 常量区 —— 存储不能修改堆常量

JAVA相关

Java的内存管理机制

Java内存同样分为五个区

  • 方法区 —— 全局共享,存放类信息,静态变量, final 常量等,其中还包括运行时常量池
  • 堆区 —— 全局共享,存放对象实例和数组值,new 创建的事物
  • 本地方法栈
  • 程序记数器 —— 线程行号指示器
  • Java虚拟机栈 —— 局部变量

Java面向对象特性

  • 封装 —— 将属性已经操作放在类之中
  • 继承 —— 一个类可以继承父类的特性,
  • 抽象 —— 将一类实体的共同特征提取出来,封装在一个新的类中
  • 多态 —— 传递给父类对象引用不同的子类对象从而表现出不同的行为

List, Set, Map 的区别

  • List 允许重复对象,有序的而且可以有多个null
  • Set 不允许重复对象,只能有一个null且是无序的
  • Map 允许重复对象,每个对象包含一个值一个键,值可以重复但键只能唯一

ArrayList, LinkedList 的区别

  • ArrayList 基于动态数组实现,可以随机访问
  • LinkedList 基于双向链表实现,只能顺序访问,但可以快速增加删除

Java内存回收机制

JVM内存模型

抽象类和接口的区别

  • 抽象类:extend 关键字,可以有构造器,可以用public,protected或者private修饰
  • 接口: implement 关键字,不可以有构造器,只能用public方法

深拷贝和浅拷贝的区别

  • 浅拷贝赋值引用地址,修改值会影响原来的值
  • 深拷贝会在堆中新建对象,修改不会影响原来值

计算机网络

osi七层模型

应用层 表示层 会话层 传输层 网络层 链路层 物理层

五层模型

应用层 传输层 网络层 数据链路层 物理层

四层模型

应用层 传输层 网际层 网络接口层

三次握手

三次握手是指TCP建立链接的过程

第一次握手由客户端向服务端发送带有SYN = 1的数据报文, 此时客户端知道自己发送成功,服务端知道对方发送成功,自己接收成功。

第二次握手由服务端向客户端发送带有ACK = 1,SYN = 1的数据报文,此时客户端知道自己发送接收成功,对方发送接收成功, 服务端知道自己发送接收成功,对方发送成功。

第三次握手由客户端向服务端发送待用ACK的数据报文,此时客户端知道自己发送接收成功,对方发送接收成功,服务端知道自己发送接收成功,对方发送接收成功。

四次挥手

四次挥手是TCP协议断开链接的过程

第一次挥手由客户端向服务端发送断开链接的请求,发送一个带有fin的数据报文。

第二次挥手由服务端接收到客户端发送的请求后,发送一个带ACK的数据报文来表示他已经知道客户端的请求。

第三次挥手由服务端处理完数据后并关闭与客户端之间的链接后,向客户端发送一个带FIN的数据报文声明他已经处理完断开链接所需要处理的数据。

第四次挥手由客户端向服务端发送一个带有ACK的数据报文,声明客户端知道链接已断开。

UDP和TCP的区别

  • tcp面向链接而udp面向无链接
  • tcp保证准确性而udp不保证准确性
  • tcp只支持一对一,而udp支持一对多,多对一,一对一,多对多
  • tcp面向字节而udp面向报文
  • tcp有拥塞控制而udp没有

tcp确认机制

超时重传,流量控制,拥塞控制,校验码,按序号发送接收

tcp用超时重传来保证准确性,即已发送的报文在规定时间内没有答复,则重新发送

tcp拥塞控制

  • 慢开始 —— cwnd 一开始为1,每次接收成功后翻倍,直到达到 ssthresh(慢开始门限)后每次加一
  • 拥塞避免 —— 当 cwnd >= ssthresh 时,进入拥塞避免,每个轮次只将 cwnd 加一
  • 快重传 & 快恢复 —— 当连续收到三次重复报文的确认信号后,立刻重传下一段报文

输入url后的过程

  • DNS将输入域名解析为IP地址
  • 客户端向服务端发送建立TCP请求的过程
  • 客户端向服务端发送Http请求
  • 服务端向客户端响应Http请求
  • 客户端将得到的HTML代码解析并渲染给用户

URL 各部分的含义

三个部分:

  • 协议名: http: https: ftp:
  • 主机名: IP地址
  • 路径名及文件名: / / / 之类的

GET和POST的区别

Get用户获取报文,而Post则用于传输报文

Get可以保存为书签,可缓存,Post不可以保存为书签,不可缓存

Get幂等,post不幂等

udp能否实现和tcp一样的效果

模拟和tcp一样的结果,加入确认,超时重传等机制

Http特点

  • 支持客户/服务模式
  • 简单快速——客户端向服务端请求服务时只需传送请求方法和路径
  • 灵活——可以传输任意数据类型
  • 无链接——每次请求结束后便会断开链接因此是无链接的,但通过Cookie和Session可以记录http联机记录
  • 无状态——对处理事务没有记忆,如需处理之前已传输过的数据,只能重新传送

Cookie和Session

由于Http是无状态的协议,所以在Http1.1中引入Cookie,用Cookie来保存一部分的用户信息,例如登陆状态等,将其保存在本地浏览器中并在下一次链接过程中传输过去。而Session则是将用户信息存储在服务端,这样更安全。用户输入用户名及密码,可从数据库中获取。

两者区别

  • Cookie存储用户信息在本地浏览器,不安全
  • 对于大型的网站,若使用Session来存储会造成巨大开销
  • Cookie只能存储ASCII码的数据,而Session可以存储复杂的数据类型

SSL

公钥和私钥的区别

私钥算法:即对称密钥加密,发送端加密和接收端揭密用的是同一个密钥,这样速度会比较快,但这样可能不是很安全。

公钥算法:即非对称密钥加密,发送端加密和接收端揭密用的不是同一个密钥,接收端向发送端发送公钥,然后发送端使用公钥进行加密,接收端接收到后用私钥进行揭密。使用公钥虽然更加安全,但这样效率较低。

Https采用的加密方式:

结合对称和非对称加密方式: 用非对称密钥加密的方式传输密钥,之后进行对称密钥加密

CA

第三方数字证书认证机构,是服务端和客户端都认可的第三方机构,增加数字签名以避免被其他第三方窃取公钥

Http报文格式

  • 请求行 —— 请求方法,URL,协议
  • 请求头
  • 请求正文

Http相应报文格式

  • 状态行 —— 版本协议,状态码,描述
  • 响应头
  • 响应正文

状态码类型

  • 1xx发送成功
  • 2xx请求处理成功
  • 3xx请求重定向
  • 4xx客户端错误
  • 5xx服务端错误

常见状态码

  • 200 OK —— 客户端请求成功
  • 301 —— 资源被永久转移到其他url
  • 302 —— 临时跳转
  • 400 Bad Request —— 客户端请求有语法错误
  • 402 Unauthorized —— 请求未经授权
  • 404 —— 请求资源不存在,url输入错误
  • 500 —— 服务器内部错误
  • 503 Server Unavailable —— 服务端暂时不可用

Http和Https的区别

  • http 明文传输,不安全
  • http 不验证通信方的身份,可能会遭到伪装
  • http 无法证明报文的完整性,报文可能受篡改
  • 而 https 通过加密,认证和完整性保护避免了这些情况的发生

Http建立链接过程

Https建立链接过程

长链接&短链接

  • 短链接是指每次服务端响应http请求后,就断开链接,这样在请求较多的情况下会比较耗时
  • 长链接则是不断开链接,保持链接方便不断处理http请求

http 1.0, http 1.1 和 http 2.0 区别


操作系统

进程与线程的区别

进程是资源分配的最小单位,线程是CPU分配的最小单位,一个线程只能属于一个进程,一个进程包含多个线程,拥有资源,调度,开销,通信。

进程的通信方式

  • 管道 —— 分为命名进程和非命名进程,非命名进程只允许父子进程间的通信,命名进程(FIFO)则允许非父子进程通信,管道只允许单程流通,因此他是半双工的
  • 消息队列 —— 在一个进程创建消息队列,一个进程写一个进程读,这种方式类似于文件创建的方式,因此当消息队列未读出就接入下一个进程时,很容易读到之前进程的消息
  • 信号量 —— 只能用于同步
  • 共享区域 —— 开辟一块的共享区域用于进程读写

进程状态

  • 就绪模式 —— 该进程未占用了初CPU资源意外的所以资源,等待CPU分配资源
  • 运行状态 —— 该进程正在占用CPU资源,处于此状态的进程数小于等于CPU数
  • 阻塞状态 —— 该进程正在占用CPU资源,但在等待某种条件以继续,或者放弃CPU资源回到就绪状态

管道通信底层实现

进程创建开销为什么比线程高

线程共享那些资源,线程都有自己的栈吗

堆和栈的区别

  • 堆用于存储实例,栈用于存储局部变量
  • 每个线程都有一个栈,而多个线程公用一个堆
  • 栈内存存放变量生命周期结束就会释放,而堆内存则是通过垃圾回收机制处理
  • 效率:

死锁及解决方法

银行家算法

虚拟内存

并发与并行的区别

悲观锁和乐观锁

进程的内存布局,哪些是线程共享的

虚拟内存的作用,地址空间的概念,指针能不能访问0x0,如何在进程中直接操作物理地址

用户态和内核态

异常控制流

LRU

中断

直接寻址和间接寻址


数据结构

八大排序算法

直接插入排序O(N^2)稳定最好O(N) 最坏O(N^2)
希尔排序O(N (logN)^2)不稳定最好O(N) 最坏O(N(logN)^2)
选择排序O(N^2)不稳定永远都是O(N^2)
堆排序O(N (logN))稳定好坏都是O(N (logN))
冒泡排序O(N^2)稳定最好O(N) 最坏O(N^2)
快排O(N (logN))不稳定最好O(N) 最坏O(N (logN))
分组排序O(N (logN))不稳定好坏都是O(N (logN))
基数排序O(kN)稳定好坏都是O(kN)

堆与栈的区别

第k大的数 一个元素添加进去堆调整的复杂度以及排序的复杂度

数组,链表,hash表,二叉树区别:查找,删除,插入时间复杂度分析

数组O(N)O(N)O(1)
链表O(N)O(1)O(N)
hash表O(1)O(1)O(1)
二叉树O(logN)O(logN)O(logN)

哈希表解决冲突的方式

  • 线性探测法
  • 链表法

Huffman 树

Huffman 树是一种编码方式,建树过程是先将需要编码的数据按出现频率从小到大的顺序排列,然后将值最小的两个节点建树并将其和设为一个新的节点,递归进行直到只剩下一个节点便可得到 Huffman 树


算法

链表去除重复数据

知道两个有序数组中的中位数,如何找他们两个数组合并后得到的中位数

根据二叉树的前序和后序序列能恢复出多少棵树

数组中找最大最小数

一般情况:分开去找 —— n-1 + n-1 = 2n-2

优化情况:两个两个地找 —— 3n/2 – 2 —— 每两个两个进行比较,期中大的和max进行比较,小的和min进行比较

数组中第i小的数

一般情况:排序,找第i个位置的数

优化:类似快排的算法,先找一个哨兵k,将小于他的放在左边,大于他的放在右边,若此时k>i,只需要在左边再找i,若k<i, 则需要在右边进行找i-k的位置,递归寻找,平均可以达到O(n)

N叉树第K层节点数量

翻转二叉树的方法

两栈实现一队列

数据库

自旋锁和互斥锁

B树和B+树

事务四特性

ACID

  • A:原子性 —— 事务是不可分割的最小单位,操作或者全部提交成功或者失败全部回滚
  • C:一致性 —— 数据库在事务执行前后保持一致性
  • I:隔离性 —— 在事务最终提交前,对其他事务是不可见对
  • D:持久性 —— 事务提交后,所做对修改便会永久保存到数据库中

Git

git rebase git merge 的区别

IOS

app运行的五个周期

  • 未运行
  • 未激活
  • 激活
  • 后台
  • 挂起

Amazon Cognito

今早凌晨四点考完微观小测,突然想起来下周二要交任务了然而我现在的进度还十分缓慢QAQ。

面试官提到了用Amazon Cognito来对接后端, 亚马逊家的东西果然还是可以的,教程啥的都有,这里附上教程链接🔗

第一步: 创建用户池

进入控制台 点击进入管理用户池

控制台

进入后点击创建用户池

点击创建

输入池名称并按照默认方式创建

在默认方式中进行选择设置

创建成功

到这一步就创建好了用户池

第二步:添加应用程序

如图所示,在应用程序客户端上添加客户端

建立完之后会有一个应用程序客户端 ID,需要记住

再勾选 Cognito User Pool

再输入回调URL和注销URL,如果是网页应用则应该使用https:// IOS或者安装则是用myapps://

自勉

这几天看父母在吵架,作为旁观者我都快火冒三丈

自开年以来,老爸便陷入了一种游手好闲都状态,不怎么工作,一天到晚在家看电视剧。天天嚷嚷着要做大生意,可实际上是从2016年开始就一直在处处碰壁,处处瞎投资,处处打水漂。对自己身上的事情越来越不上心,办事也越来越不麻利。可能是年龄吧,就这件事我看来,更像是以找大生意做借口去逃避当下的任务以及困难,没有人push就慢慢进行,虽说到了这个年纪不那么拼很正常,但对比看到妈妈早出晚归的场景真的能够感受到对比,说到这件事我也是有想在自勉,自从上网课以来,没有压力去push自己向前走导致自己没有按照规划中目标走。本来打算学python学ios开发参加游戏比赛参加lab的,就因为接着找实习的借口一而再再而三的拖延导致到了现在还是所学甚浅。人都是有惰性的,如果没有东西去push你,你就很容易温水煮青蛙一事无成。特此自勉,希望自己以后能不断勉励,不断前进

IOS学习日记二

把想要设置的图片拉到 Assets.xcassets里面

doge

File > New > File中新建一个SwiftUI View的文件,我这里将其命名为CircleImage.swift

用Image来展示该图

import SwiftUI

struct CircleImage: View {
    var body: some View {
        Image("dogHead") // 只需要名字
    }
}

struct CircleImage_Previews: PreviewProvider {
    static var previews: some View {
        CircleImage()
    }
}

.clipShape(Circle())使得切割图像为圆形

var body: some View {
        Image("Doggie")
            .clipShape(Circle())
    }

The Circle type is a shape that you can use as a mask, or as a view by giving the circle a stroke or fill.

an overlay

使用overlay来给外围的圆圈添加参数

Color-> 颜色

LineWidth-> 线宽

.shadow() -> 增加阴影

struct CircleImage: View {
    var body: some View {
        Image("Doggie")
            .clipShape(Circle())
            .overlay(
                Circle().stroke(Color.gray, lineWidth: 4))
            .shadow(radius: 10)
    }
}

新建一个文件并引入MapKit