首页 > 技术文章 > iOS开发笔记1

dev-walden 2019-05-08 17:37 原文

1.在堆上模拟函数调用栈

背景: 在看算法书时候, 很多地方提到要谨防递归的栈溢出问题.

分析: 递归调用时候, 有可能出现非常深的函数调用. 对于每次的函数调用, 都需要将函数体内的局部变量保存在栈上, 如果函数体内包含大量的局部变量, 那么每次递归都会占用大量的栈空间, 非常容易导致栈溢出崩溃.

经过分析发现, 递归的栈溢出主要是局部变量占用太多空间而导致的. 那么我们只要想办法将局部变量封装起来放在堆上, 那么就能减少栈上空间的占用, 从而防止栈溢出.

青蛙跳台阶问题的递归算法如下所示(Swift).

// 定义一个对象, 用来存储局部变量信息
class FakeStack {
    var num: Int
    init(num: Int) {
        self.num = num
    }
    
    func nextStep() -> Int {
        if num == 1 {
            return 1
        }
        
        if num == 2 {
            return 2
        }
        
        return FakeStack(num: num - 1).nextStep() + FakeStack(num: num - 2).nextStep()
    }
}

//栈上的函数调用
let stepNumber = FakeStack(num: 10).nextStep()
print(stepNumber)

2.去掉WKWebView弹出键盘的ToolBar

原理就是替换原有的WKContentView,在新的NoInputAccessoryView中的inputAccessoryView属性中返回nil。

final class FauxBarHelper: NSObject {
    @objc var inputAccessoryView: AnyObject? { return nil }
    
    func removeInputAccessoryView(webView: WKWebView) {
        var targetView: UIView? = nil
        
        for view in webView.scrollView.subviews {
            if String(describing: type(of: view)).hasPrefix("WKContent") {
                targetView = view
            }
        }
        
        guard let target = targetView else { return }
        
        let noInputAccessoryViewClassName = "\(target.superclass!)_NoInputAccessoryView"
        var newClass: AnyClass? = NSClassFromString(noInputAccessoryViewClassName)
        if newClass == nil {
            let targetClass: AnyClass = object_getClass(target)!
            newClass = objc_allocateClassPair(targetClass, noInputAccessoryViewClassName.cString(using: String.Encoding.ascii)!, 0)
        }
        
        let originalMethod = class_getInstanceMethod(FauxBarHelper.self, #selector(getter: FauxBarHelper.inputAccessoryView))
        class_addMethod(newClass!.self, #selector(getter: FauxBarHelper.inputAccessoryView), method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
        object_setClass(target, newClass!)
    }
}

3.关于HuggingPriority和CompressionResistance

setContentHuggingPriority ==> 抗拉伸-此view不想被拉伸
setContentCompressionResistancePriority ==> 抗压缩-此view不想被压缩
举个例子,当有两个横排的label,当左右label数据都被填满导致label显示文字长度不够的时候,如果左边label设置了setContentCompressionResistancePriority,则系统会尽可能将左边label文字显示全部,从而压缩右边label;如果左边设置setContentHuggingPriority,当左右空间都足够的时候,右边label会被拉伸,而左边label宽度会尽量以显示完全内容的最小宽度显示内容。

参考链接:
https://www.jianshu.com/p/5cf559435eb9
https://www.cnblogs.com/wobuyayi/p/9501391.html

4.项目添加预处理宏定义

添加自定义预处理宏定义意义在于,当你需要beta版本时候你可以为beta版本做特殊的证书配置,环境配置等等。

5.使用自定义字体样式,字体倾斜

不得不说,UIFont提供的字体样式太强大了,虽然我们平时需要用到的并不多,但是如果了解下高级的字体样式配置方式,在遇到各种变态的需求时候才能处乱不惊。这里要说的是如何让字体倾斜一定角度,如下图所示:

实际上,这种效果实现起来非常简单,你只需要配置字体的UIFontDescriptor即可,UIFontDescriptor提供了专门的属性来修改字体的倾角、字体名字、字体大小、文字样式等等。

具体的代码如下所示:

//生成CGAffine对象
let transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi / 8))
//配置UIFontDescriptor.AttributeName.matrix属性
let fontDescriptor = UIFontDescriptor(fontAttributes:
    [UIFontDescriptor.AttributeName.matrix: transform])
//生成字体样式
let font = UIFont(descriptor: fontDescriptor, size: 0)

//将字体样式配置给UILabel
let label = UILabel()
label.font = font

6.NumberFormatter-保留小数位

很多时候我们需要讲Double类型保留指定位数的小数位,使用NumberFormatter我们可以方便的保留我们需要的小数位数并转换成字符串类型, 示例代码如下所示:

extension Double {
    func toString(_ minF: Int = 0, maxF: Int = 10, minI: Int = 1) -> String {
        let valueDecimalNumber = NSDecimalNumber(value: self)
        let twoDecimalPlacesFormatter = NumberFormatter()
        twoDecimalPlacesFormatter.maximumFractionDigits = maxF
        twoDecimalPlacesFormatter.minimumFractionDigits = minF
        twoDecimalPlacesFormatter.minimumIntegerDigits = minI
        return twoDecimalPlacesFormatter.string(from: valueDecimalNumber)!
    }
}

如有任何错误, 请不吝赐教.

推荐阅读