项目源码下载地址:

  https://github.com/ShayneYeorg/Meditashayne

1、首先一开始设计这个App的时候,我就希望它能比系统自带的备忘录更方便:比如备忘录需要手动去点击一下保存,我希望我的App可以省略掉点击保存这一步,只需要退出随笔的详情页面便可自动保存内容。

  那么退出详情页面有两种方式:左上角的“返回”以及UIViewController自带的左划退出。

  (1)、在处理完“返回”按钮之后,发现了第一个问题:自定义NavigationController上的BarButtonItem后,UIViewController自带的左划手势失效了。

  最后处理方法是在MDSNavigationController(自定义的NavigationController)里增加以下方法,并在viewDidLoad中调用,左划手势重新生效:

  (2)、考虑到刚进入随笔详情页面的时候,页面里还未有内容,这时就不应该存储没有内容的随笔,即是不能允许使用“返回”按钮或左划返回上一页面。

  然后使用了以下方法来灵活地开启或关闭当前控制器的左划功能

  (3)、然后发现把退出和保存两个功能捆绑在一起这种处理方式存在问题:

  如果我是不小心点到“新建”按钮进入新建随笔详情页面的,那么根据(2)我需要填写点内容才能退出,而退出的时候我填写的这些内容会被自动保存,可是我一开始是误点进来的,我并不想保存任何内容的,这就出现了矛盾。

  或者当我点击某篇随笔进入编辑随笔详情页面并做了改动之后,如果我想放弃这些改动,我发现此时就找不到方法来放弃了,直接退出会把我所做的改动保存起来,这也是一样的矛盾。

  即是说,当把退出和保存两个功能捆绑在一起之后,App便丧失了“退出但不保存”的功能。虽然可以通过退出的时候弹框提示是否要保存来处理,但是这样的话就会使得退出操作更繁琐,与设计这个功能时为了操作更简便的初衷相违背了。

  基于以上考虑,最终去除了“退出同时保存”的功能,使用了在NavigationController上的按钮来进行保存。

2、关于上拉加载更多控件,这个控件仿写公司项目使用的上拉加载更多控件的,使用的时候需要注意:在ScrollView或者TableView有数据之后,即是有了contentSize.height之后,需要再去调用一下控件的setState方法(直接或间接调用),方能让控件显示正确的状态。

3、在随笔列表页面,我希望App能全量展示所有的随笔内容,不希望点击某一条随笔进入随笔详情才看到所有内容。那么cell的高度便是不固定的了,需要用到动态高度的cell。

  (1)、为cell定义一个属性article,用来存放随笔模型,然后在setArticle方法内,使用以下方法来动态计算cell的高度,其中contentView是显示内容的TextView:

  之所以高度要加1是为了给下分割线空出空间。

  这个功能的参考文档:http://www.cocoachina.com/industry/20140604/8668.html

  (2)、然后发现,虽然cell能动态计算高度了,但是计算只是依据随笔内容的段落数。即是如果随笔内容是两段,而每一段文字的长度都超过了屏幕的宽度,那么cell计算出来的内容高度只是两行的高度。因为systemLayoutSizeFittingSize:方法并不知道TextView的宽度,也就无法知道在哪里需要换行。于是将计算cell高度的代码修改如下:

4、在进行3(2)的操作时,约束也要相应配合更改。我一开始给UITextView添加了宽度约束后,忘了将UITextView与右边的边距约束去掉,导致执行时出现了以下约束冲突的错误

2016-02-21 15:21:03.443 Meditashayne[4685:225763] Unable to simultaneously satisfy constraints.

                  Probably at least one of the constraints in the following list is one you don't want.

                  Try this:

                                    (1) look at each constraint and try to figure out which you don't expect;

                                    (2) find the code that added the unwanted constraint or constraints and fix it.

                  (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)

(

    "<NSAutoresizingMaskLayoutConstraint:0x7fbf4b5b5ec0 h=-&- v=-&- MDSSearchView:0x7fbf4b5ec510.width == UIView:0x7fbf4b41cd10.width>",

    "<NSLayoutConstraint:0x7fbf4b5ee5a0 H:[UITextField:0x7fbf4b5ed780(264)]>",

    "<NSLayoutConstraint:0x7fbf4b5f1490 H:|-(8)-[UITextField:0x7fbf4b5ed780]   (Names: '|':UIView:0x7fbf4b5ed610 )>",

    "<NSLayoutConstraint:0x7fbf4b5f14e0 H:[UITextField:0x7fbf4b5ed780]-(8)-|   (Names: '|':UIView:0x7fbf4b5ed610 )>",

    "<NSLayoutConstraint:0x7fbf4b5cdb40 H:[UIView:0x7fbf4b5ed610]-(20)-|   (Names: '|':UIView:0x7fbf4b5ed4a0 )>",

    "<NSLayoutConstraint:0x7fbf4b5a62a0 H:|-(20)-[UIView:0x7fbf4b5ed610]   (Names: '|':UIView:0x7fbf4b5ed4a0 )>",

    "<NSLayoutConstraint:0x7fbf4b5fa280 H:[UIView:0x7fbf4b5ed4a0]-(0)-|   (Names: '|':MDSSearchView:0x7fbf4b5ec510 )>",

    "<NSLayoutConstraint:0x7fbf4b5ed140 H:|-(0)-[UIView:0x7fbf4b5ed4a0]   (Names: '|':MDSSearchView:0x7fbf4b5ec510 )>",

    "<NSLayoutConstraint:0x7fbf4b616a70 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7fbf4b41cd10(375)]>"

)

Will attempt to recover by breaking constraint

<NSLayoutConstraint:0x7fbf4b5ee5a0 H:[UITextField:0x7fbf4b5ed780(264)]>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.

The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

  原因就在于UITextView设置了与superView的左右边距,又设置了宽度为264,导致了冲突。

5、在动态计算高度的cell里面,要把UITextView的Scrolling Enable设为NO,否则TextView的高度不会跟着内容变化,只会取一个最小的高度;同时也要把UITextView的user interaction enable也设为NO,否则TextView会拦截掉cell的点击事件,选中cell变成了编辑TextView。

6、在做完动态高度的cell之后,发现在真机上App打开后加载数据的时候非常慢。我一开始以为是Core Data的问题,于是自定义了一个加载的浮框控件,在打开App的时候,新开一条线程去Core Data取数据,主线程显示加载控件,样式如下:

  但是发现问题仍然存在,打开App之后仍然是会卡住一段时间,并且卡住的是主线程上的加载控件,甚至当时页面上只有1个cell,都整整卡住了8秒钟。那就很明显问题不在于Core Data了,而在于主线程上。

  于是我一步一步排查,首先发现耗时操作主要在于获取到数据后刷新TableView的reloadData方法上,再进一步排查发现耗时主要发生在这个方法里:

  reloadData方法会调用tableView:cellForRowAtIndexPath:方法,下一步就有可能会调用到上面的loadNibName:owner:options:方法,而主要的耗时就发生在这个方法里。于是着重研究这个xib文件,最后发现问题出在两个地方:

  (1)、xib里显示随笔标题的UILabel使用了“苹方”这种字体,而真机是iOS 8系统的,手机系统里匹配不到“苹方”字体,最终使用了系统默认的字体,这个匹配的过程造成了大部分的耗时,最终将UILabel的字体设为系统默认字体,解决了这部分耗时;

  (2)、xib里显示随笔内容的UITextView默认的text写了中文,导致了小部分的耗时,将默认text改成英文就解决了这部分耗时。

  然后发现仍然有改进的空间:

  现在cell的高度cellHeight是在cell设置随笔模型的setArticle:方法里去计算的,每次调用setArticle:方法都会计算一次,而setArticle:方法调用在tableView:cellForRowAtIndexPath:方法里,即是,每次调用tableView:cellForRowAtIndexPath:都会计算一次cell高度。

  进入App的时候,在tableView:heightForRowAtIndexPath:会去根据IndexPath取出对应cell,再返回它的高度,这个方法这里也是调用了tableView:cellForRowAtIndexPath:方法去取cell的,所以就造成了这么个情况:进入App的时候,每个cell的高度都会被计算两次。

  (3)、于是就使用了以下这个方法预估cell的高度,减少了一次cell高度的计算,又优化了一小部分耗时:

  做完这些优化之后,发现加载数据的时间已经非常短了,以至于根本不需要一个加载浮框了,于是就把加载浮框移除掉了。

7、在真机上跑App的时候发现了另一个问题:拖动TableView的时候会卡顿。原因还是在于cell高度的计算上,由于拖动TableView的时候,哪怕这个cell之前已经显示过了,新出现的cell还是会调用tableView:cellForRowAtIndexPath:方法,这样就多次计算了一个cell的高度。而这些能耗在iOS 8系统的iPhone 4S上显得特别明显。

  于是我开始思考是否有办法让所有cell都只计算一次,毕竟对于已经计算过高度的cell,是完全没有必要再重复去计算高度的了。最终使用了以下的方法来处理:

  (1)、在cell里单独提供一个计算高度的方法,不再在设置随笔模型的setArticle:方法里去计算cell的高度:

  (2)、在随笔列表控制器里新增一个属性:

  这个属性用来存放cell的高度,以IndexPath.row为key,对应cell的高度为value存在这个字典里。

  (3)、然后将tableView:cellForRowAtIndexPath:方法修改如下:

  (4)、最后将tableView:heightForRowAtIndexPath:修改如下,这样,所有的cell就只会计算一次了:

8、创建了搜索栏之后,我希望能只点击搜索栏右上方的Handler拖动这个搜索栏,而在Handler左右方的透明部分则不拦截任何手势

  在搜索栏中重写了这个方法完成了这个功能:

9、当搜索栏调出了键盘后,控制器接收到UIKeyboardWillShowNotification通知后在self.view上会添加一层蒙板,用以点击时收起键盘,同时也将蒙板自身remove掉。但是在真机上,发现点击了蒙板后虽然键盘会收起,但是self.view却没有任何点击反应了,似乎它并没有将自身remove掉。

  最终排查之后发现,问题出在UIKeyboardWillShowNotification通知上。在iOS 8 系统下,中文键盘出现时会发送3次UIKeyboardWillShowNotification通知,这样就使得页面上添加了3层蒙板,导致了页面点击无反应。

  最终在UIKeyboardWillShowNotification通知的处理方法里,处理成先移除已有蒙板再添加新蒙板,解决了这个问题。

所闻所获6:meditashayne项目总结的更多相关文章

  1. 所闻所获5:关于iOS的证书

    去年做ondine时,被iOS的证书搞得很是头大,做完了之后感觉一片混乱,印象也不是很深.最近又发布了meditashayne,个人的第二个App,也就重温了一下证书的一些相关操作.这一次的理解比较深 ...

  2. VS Bug 当获取其他项目的代码时, F5 无法进入调试模式. 也不报错....

    在64位的机子下, 被获用的项目使用X86时会出现. 就会出现   F5 无法进入调试模式. 也不报错.... 打断点也没有用. 在不加入X86项目的代码时, 又可以运行..   解决方案:   检查 ...

  3. BPM始终服务于人,落脚于人

    数字经济时代下,云计算.大数据.移动互联已经成为当下企业必须采取的武装力量.随着互联网+.中国制造2025.工业4.0等国家战略的引导与支持,无数的企业在这场数字化浪潮中使尽浑身解数,想要抓住机遇奋力 ...

  4. 20145227《Java程序设计》课程总结

    20145227<Java程序设计>课程总结 每周读书笔记链接汇总 20145227 <Java程序设计>第1周学习总结 20145227 <Java程序设计>第2 ...

  5. PSP总结报告1

    回答作业问题 1.回想一下你曾经对计算机专业的畅想 我高考后报考的是计算机科学与技术,当时对计算机技术基本了解为零,当时以为什么东西都会用到计算机,学计算机以后不会找不到工作,刚开学的时候对计算机一窍 ...

  6. Prism 4 文档 ---第7章 组成用户界面

    一个应用程序的用户界面(UI)可以通用以下几种模式之一来构建: 窗体所需要所有的控件都包含在一个单独的XAML文件中,在设计时组合这个窗体. 窗体的逻辑区域被分割到单独的部分中,通常指哟过户控件.这些 ...

  7. 走,去出海,一起“Copy to World” | 36氪出海行业报告

    http://www.sohu.com/a/200845344_114778 从工具类产品在海外聚集大量流量到新闻.社交游戏等内容类产品在海外取得优异成绩,中国正在完成从Copy to China向C ...

  8. 2017年度最具商业价值人工智能公司TOP50 榜单发布

    2017年度最具商业价值人工智能公司TOP50 榜单发布 未来最有赚钱潜力的50个人工智能项目都在这里了. 经过了60年的发展,人工智能在2017年,正式走向应用的元年. 从今年起,人工智能首次被写入 ...

  9. 华策光通信: LED可见光通信室内定位项目获最具投资价值奖

    3月21日上午,一场持续3个多小时的O2O领域的创业DemoShow在深圳科兴科学园会议中心激烈上演.来自华策光通信的基于LED可见光通信室内精准定位项目作为LED与室内定位领域的跨界融合项目经过精彩 ...

随机推荐

  1. 表单javascript checkbox全选 反选 全不选

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  2. chroot 与 jail

    所谓“监牢”就是指通过chroot机制来更改某个进程所能看到的根文件夹,即将某进程限制在指定文件夹中,保证该进程仅仅能对该文件夹及其子文件夹的文件有所动作,从而保证整个server的安全. 创建chr ...

  3. js校验

    判空 function check(s) { return (s == null || typeof (s) == "undefined" || s == "" ...

  4. CentOs7下systemd管理知识要点

    centOs7的一个巨大的变动就是用systemd取代了原来的System V init.systemd是一个完整的软件包,安装完成后有很多物理文件组成,大致分布为,配置文件位于/etc/system ...

  5. EffectiveC#8--确保0对于值类型数据是有效的(初始化问题)

    1.决不要创建一个不包括0在内的枚举类型 2.举例如下: public enum Planet { Mercury = 1, Venus = 2, Earth = 3, Mars = 4, Jupit ...

  6. ASP.NET开发学习视频教程大全(共800集)

    ASP.NET是微软.NET平台的支柱之一,被广泛应用在WEB等互联网开发领域,因此它的强大性和适应性,可以使它运行在Web应用软件开发者的几乎全部的平台上.这里整理了最全的ASP.NET开发学习视频 ...

  7. 细讲encodeURI和encodeURIComponent以及escape的区别与应用

    首先,我们都知道这三个东西都是用来编码的 先来说encodeURI()和encodeURIComponent() 这两个是在转换url时候用来编码解码用的. 有编码就会有解码, 解码就是decodeU ...

  8. VB短信猫开发包,支持超长短信

    一.短信猫开发包(长短信/异步调用)说明:   短信猫开发包以OCX控件的形式提供,支持Windows平台下常用的开发工具:如VB.VB.net.VC++.Power Builder.C#.DELPH ...

  9. Sql server 数据库 单用户切换为多用户

    使用master 下的sysprocesses 查询 db正在使用的spid 如 select spid from sysprocesseswhere dbid=DB_ID('DbName') 然后执 ...

  10. SQL Server 本地时间和UTC时间的相互转换的代码

    DECLARE @LocalDate DATETIME, @UTCDate DATETIME, @LocalDate2 DATETIME   SET @LocalDate = GETDATE() SE ...