iOS 项目总结

一、前言

尽管早就想开写这么一个系列,但迟迟没有付诸实践。就现在开始吧,这个系列会记录我项目中遇到的问题和一些我以前不知道的小知识点等等。

二、问题

2.1 消除 Pod 文件中的警告

作为强迫症患者,看到一个警告就会让我不舒服。但以前不知道 Pod 文件中的警告可以被忽略,直到有一天发现警告全部不见了,原来是同事在 Podfile 文件中加入了这么一个配置:

inhibit_all_warnings!

2.2 引入 R.swift 三方后,自定义 Warning 显示,脚本冲突

以前写 OC 时,我们可以用如下代码来让 Xcode 给出 Warning 提示:

#warning

但在 Swift 项目代码中,这种写法无效了,当然 Swift 也有新的解决办法:

image

如图所示点击 New Run Script Phase, 然后在添加的 Run Script 中写入如下脚本代码:

TAGS="TODO:|FIXME:"
echo "searching ${SRCROOT} for ${TAGS}"
find "${SRCROOT}" \( -name "*.swift" \) -print0 | xargs -0 egrep --with-filename --line-number --only-matching "($TAGS).*\$" | perl -p -e "s/($TAGS)/ warning: \$1/"

image

然后在项目中,就能使用 FIXME:&TODO: 来让 Xcode 显示提醒,当然你可以自定义标识符。

image

这段脚本代码笔者本来就是从网上复制的,也从来没仔细看过,直到引入了 R.swift(强烈推荐) 这个三方,造成冲突了。冲突的原因很简单,因为上面脚本代码中匹配的是 .swift,结果这个三方名字中就含有这个,尼玛!所以解决方法就是忽略 Pod 文件。

TAGS="TODO:|FIXME:"
echo "searching ${SRCROOT}/项目工程文件本名 for ${TAGS}"
find "${SRCROOT}/项目工程文件名" \( -name "*.swift" \) -print0 | xargs -0 egrep --with-filename --line-number --only-matching "($TAGS).*\$" | perl -p -e "s/($TAGS)/ warning: \$1/"

2.3 直接在 StoryBoard 中使用 UIScrollView 布局界面

最近笔者完全沦为 IB 党了,哈哈!

没有尝试过的读者会认为这个不会有什么问题。往下看吧:

image

往控制器中拖入一个 UIScrollView ,上下左右约束都为 Safe Area
就像笔者第一次使用一样,直接放一个 UIViewUIScrollView 中,并约束为上下左右都等于父视图的边界。

image

问题就来了,报错说 UIScrollView 需要新的位置或大小约束,笔者目前也没想通为啥会报错。

实际开发中,页面的最终的内容肯定是确定的,所以可以根据界面反推 UIScrollView 的布局。但是就像上图中那样,如果一直给你显示布局错误,笔者和部分读者会觉得很烦。解决方法很简单:

直接添加内容视图的宽高约束等于 UIScrollView,然后将高度约束的优先级调整为小于 1000。

image

然后在内容视图上布局界面时根据子视图将内容视图高度确定就OK了,此时因为前面设置的高度约束优先级小于 1000 ,所以会优先使用子视图确定的高度。当然读者也可以在布局完成时将前面的高度约束删除掉。

还有就是可以将控制器的界面设置为 Freeform,对于一些超出屏幕的界面,很方便。

image

2.4 内存泄漏

最近导入了微信的一个三方内存泄漏检测工具。

MLeaksFinder

发现同事的代码中有很多的内存泄漏,经过一番排查,这里也小小总结一下常见的和遇到的不常见的内存泄漏情况。

2.4.1 常见的

  • 闭包循环引用
// 用来设置导航栏返回按钮的一个方法 
self.setUseCommonNavigationBackButtonWithHandler { (_) in
    self.navigationController?.popViewController(animated: true)
}

绝对多数读者肯定会避免这种问题,但我发现同事写了一个变种:

let vc = UIViewController()
vc.setUseCommonNavigationBackButtonWithHandler { (_) in
    vc.navigationController?.popViewController(animated: true)
}

这里的 vcself 是一回事。

  • 不会释放对象持有需要释放对象

场景: 单例持有外部需要释放的对象

笔者项目中使用的是 SVProgressHUD 这个三方来做的加载,其中有一个方法是用来设置加载控件的容器视图的:

+ (void)setContainerView:(nullable UIView*)containerView;   

项目中同事将当前控制器的视图作为了容器视图进行了配置,然后 SVProgressHUD 单例对象对其进行了持有,当控制器 pop 时,这个视图因为被单例持有,无法释放。

  • 对象循环持有

场景:子控制器持有父控制器

对于一些需要向控制器中添加子控制器的界面,点击子控制器的内容,然后进行 push操作,但因为这个场景真正需要进行 push 操作的其实是父控制器,所以往往都会将父控制器传给子控制器。

如果一不小心,声明了一个属性强持有了父控制器,就造成了循环持有。正确的应该是弱持有父控制器。

  • 监听和通知需要移除

这个没什么说的,项目中没发现,只是提一下

2.4.2 不常见的

这里的不常见定义为笔者以前不知道的

  • WKUserContentController移除位置

场景:WKWebView 进行 JS 交互

最初是在 deinit 方法中进行的移除操作,经过测试发现,WKUserContentController 实例对象进行了添加后,不会走 deinit 方法,坑爹!

目前采用的在 viewWillAppearviewWillDisappear 方法中分别添加和移除。

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    userContent.add(self, name: "xxx")
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    userContent.removeScriptMessageHandler(forName: "xxx")
}

  • UIAlertController内存泄漏
    直接模拟场景代码
class DetailViewController: UIViewController {
    var alertController: CustomViewController!

    override func viewDidLoad() {
        super.viewDidLoad()

        alertController = CustomViewController(title: nil, message: nil, preferredStyle: UIAlertControllerStyle.actionSheet)
        let textAction = UIAlertAction(title: "拍照", style: UIAlertActionStyle.default) { (action:UIAlertAction) in
        // 问题所在处
            self.title = "Test"
        }
        alertController.addAction(textAction)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        present(alertController, animated: true, completion: nil)
    }

    deinit {
        print("DetailViewController init")
    }
}

DetailViewController 持有了 alertController

alertController 添加 textAction 后持有了它

textAction 事件闭包中使用了 self, 于是持有了 DetailViewController

一个循环引用环形成,GG。

解决方法也很简单,闭包中使用 weak

2.5 swift协议默认实现的静态分发

详见忽略子类中的协议默认实现不参与动态分派

这里我项目中场景是定义了一个协议来控制当前控制器是否能够滑动返回

protocol NavigationControllerGestureAble: NSObjectProtocol  {
    var isCanSlidePop: Bool { get }
}

extension UIViewController: NavigationControllerGestureAble {
// 这里@objc需要注意
    @objc var isCanSlidePop: Bool {
        return true
    }
}

...其余的略

这里默认为 ture,因为 OC 中没有计算属性,其实就是一个 set&get 方法的语法糖。所以这里需要加 @objc(我是这样理解的),于是我们在需要关闭的控制器中重写这个并返回 false 就好了。

作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要这是一个我的iOS交流群:597268708,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家需要资料的加小编群哦!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • 群山连绵不绝,就如同棋盘上凸起的棋子一样,在这片广袤而又略带野性的原始村落,准确来说应该是在人类历史上不断进化,随...
    曾彧阅读 396评论 0 0
  • 还记得你十几岁时暗恋的那个男孩子吗? 上课时有心无意碰到一起的目光,会躲闪的不像样。别人不理解,可你就是喜欢...
    矫揉造作老阿姨阅读 237评论 0 1
  • 今天上班,早饭后跟大宝约好上午完成作业,下午玩,晚上回来做手工。谁知趁我上班不在家,玩伴们都找了家里,三个人又撑起...
    明懿妈妈阅读 189评论 0 3