Swift新手可能遇到的问题

这是用Swift做项目遇到的问题记录,主要是供自己记录,如果有人碰巧搜索看到,有些你可能看不懂。不过这也没关系,因为所有问题是基本都是在stackoverflow找到的答案,所以你去查就是了。

一些开发过程经验:
1)关于唯一识别的问题,通常使用 NSUUID, 例子: let uuid = NSUUID().UUIDString. 至于使用objectid作为唯一标示还未弄清楚,因为查询多个结果时,其objectid是编号的。

  1. 关于tableView的行删除,先要保证数据源的数据以删除才能删除行。否则出错“ Assertion failure in -[UITableView _endCellAnimationsWithContext:
    请参看帖子:http://blog.sina.com.cn/s/blog_7b9d64af0101b6se.html

3) 页面跳转方式:
a) 采用在storyboard跳转方式
let storyboard = UIStoryboard(name: "Main", bundle: nil); let vc = storyboard.instantiateViewControllerWithIdentifier("login") as UIViewController;
self.navigationController?.pushViewController(vc, animated: true) (push)
// self.presentViewController(vc, animated: true, completion: nil) (modal)
b)采用segue方式
self.performSegueWithIdentifier("segueShowRemind", sender: self)

c) 如果只是为了刷新数据,可以直接再次调用 viewdidload

4)ttt

5)获取coredata数据时的排序方式:1) http://stackoverflow.com/questions/25548587/sorting-array-received-from-core-data-in-swift ,2)http://www.bubuko.com/infodetail-566143.html, 3)http://www.linuxidc.com/Linux/2015-09/122778.htm

6)关于数据刷新,每次在viewWillAppear执行reload tableView是不合适的,性能影响大,应该用其他方式,比如 http://blog.sina.com.cn/s/blog_7b9d64af0101b82p.html

  1. 关于NSDate与String的转换,需要注意自定定义数据格式,否则从NSDate转不出字符。
    let dateFormat: NSDateFormatter = NSDateFormatter() dateFormat.dateFormat = "yyyy-mm-dd HH:mm:ss EEEE"
    var time:String = dateFormat.stringFromDate(date)

8)关于 coredata查询句子的语法, 条件查询是用 &&, || 等,代码参考:

9) 关于codedata的数据查找,注意条件的格式,对于整型、字符的条件,其使用格式不一样。比如下面错误提示,就是等号右侧未加引号,因为id定义是String。 Unable to parse the format string "uid = F657D3B0-F482-44B2-B0FC-5FC1FBFF28C4"'

10) 关于变量 optional定义,会引入optional字符,导致数据错误。如果打印输出发现有optional,在变量后增加!即可。

  1. 在vc隐藏tabbar,bottom bar的方法:http://segmentfault.com/a/1190000000327529
    a.最简单就是直接在storyboard 设置“hide bottom bar on push”,
    b. 在上级vc viewdidload增加 : self.hidesBottomBarWhenPushed = true //隐藏低栏

  2. 如何调整nav bar的高度,关联outlet,然后 navigationBar.frame = CGRectMake(0, 0, 100, 80)

13)设置static table,关联tableViewVC后,记得不里面关于表格的代码屏蔽,否则就不显示内容。

  1. 设置tableview的table的section的距离(间距) :http://blog.csdn.net/jimy86022/article/details/21702051

15)关于userdefault临时存储东西,在appdelegate先进行初始化,这样后面调用就不容易出现问题。

16)注意在auto layout情况下,如果没有设定好constraint在模拟器上显示不完整的,所以就看不到了。比如如果在tableView没有设定与view的constraint,滑动删除按钮因为在最右边,所以看不到。

17)登录界面的过渡(segue)用户modal,取消/成功用户unwind过渡,unwind是个IBAction 。 而一般表格点击到新页面用户prepareSegue。

18) 关于模拟器输入法选择,在模拟器中选择setting,即像手机那样操作。

关于蓝牙链接的文章:
a. 建立连接的文章:http://2goo.info/weblog/detail/232351
b. 最佳实践:http://southpeak.github.io/blog/2014/08/01/core-bluetoothkuang-jia-zhi-san-:zui-jia-shi-jian/

  1. 关于事件捕捉,比如关闭键盘;当tableview上的textField,用户touchEnd方法是没办法关闭键盘的,如下有两种方式可以通过识别手势从而触发关闭键盘代码:
    a: 通过捕捉tableview滚动的事件,然后触发(推荐)。
    func scrollViewWillBeginDragging(scrollView: UIScrollView)
    b: 通过 UITapGestureRecognizer 定义一个手势,然后绑绑定到tableview

20)用代码定义导航栏上的左右按钮,
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Refresh, target: self, action: "refresh")

关于蓝牙功能

服务UUID****:****Device Informationservice: <CBCharacteristic: 0x1653fd80, UUID = PnP ID, properties = 0x2, value = (null), notifying = NO>****
服务UUID****:FFE0

21) webView访问地址时,会涉及访问权限的错误,

22) 如何在auto layout把3个view平均分布在界面上 https://lvwenhan.com/ios/431.html

  1. 图表控件,charts, 用pod安装后,要先run一次,才能import,在github已经提过

  2. iOS 9 集成社会化分享的若干问题

http://wiki.mob.com/ios9-%E5%AF%B9sharesdk%E7%9A%84%E5%BD%B1%E5%93%8D%EF%BC%88%E9%80%82%E9%85%8Dios-9%E5%BF%85%E8%AF%BB%EF%BC%89/

当前还是用openshare比较简单,但还有集成问题为解决。

25)指定日期格式显示,可看看如下帖子:
http://my.oschina.net/yongbin45/blog/150667

  1. 关于“OBJC_CLASS”、“linker command failed with exit code1”的问题
    自己这边原因是引入openshare库的问题,用pod引入的并不生效,自己在xcode拷贝文件夹的方式就生效了。

  2. leanCloud的表在创建第一条数据时就已经明确了数据的类型,特别是索引,所以后续数据必须按照执行

28) 关于iOS信息推送设置:
a. 按照leanCloud的证书设置指南,把测试和生产的证书制作出来,即push service两个,app develop两个。
b. 按上面操作在网页生成cer文件,双击证书会添加到“钥匙串访问 ”。
c. 在xcode设置应用使用的证书(上iTunes要用正式证书),http://www.jianshu.com/p/986e02d38f1b
d. 在leanCloud导入证书,有一点要注意的是,测试时 LC和APP都用户测试证书,上线就都用正式证书。

29)从LC获取图片,使用下面方法
a. 通过Url方为
func demoCombineQiniuApi() {
getDemoFile { (file) -> Void in let thumbnailFile = AVFile(URL: "(file!.url)?imageView/1/w/50/h/100") thumbnailFile.getDataInBackgroundWithBlock({(data: NSData?, error: NSError?) in if self.filterError(error) { let image: UIImage = UIImage(data: data!, scale: UIScreen.mainScreen().scale)! self.showImage(image) self.log("成功用七牛接口获得缩略图") } }) }
}
b. 通过objectId
func getDemoFile(block : (file: AVFile!) -> Void) { AVFile.getFileWithObjectId("5573fddee4b06a32094af62b", withBlock: { (file: AVFile?, error: NSError?) -> Void in if self.filterError(error) { block(file:file) } })
}

30)关于图片压缩,

whatsapp的图片压缩: https://www.built.io/blog/2013/03/improving-image-compression-what-weve-learned-from-whatsapp/

  1. 关于图片的全屏展示,可参考leanStorageDemoSwift的“ showImage”方法

关于创建、修改提醒时,图片处理逻辑:
重点:要上传的图片应该放在userDefault的“upLoadImage”里。
0)按钮有默认的图片。
1)新创建提醒
a. 选择图片,把图片缓存到userDefault, 界面从useDefault读取显示

  1. 修改提醒
    a. 从网络获取图片,如果值不为nil,就赋值给userDefault

不管哪种情况,保存时判定一下userDefault的upLoadImage的值是为为空。

32) 关于segue返回上两步的方案, 见这个文章
http://stackoverflow.com/questions/7005787/how-to-identify-previous-view-controller-in-navigation-stack

33)UITextVIew的应用 (自动修改长度,自动判断连接、电话、email)

自动判断高度:直接autolayout就可以

识别连接:http://stackoverflow.com/questions/5964434/how-to-a-clickable-url-email-phone-number-on-uitextview

34) 自定义TabBar

http://www.jianshu.com/p/e81547c3eda7

插件:类instagram https://github.com/boctor/idev-recipes/tree/master/RaisedCenterTabBar

tabbar动态效果:https://github.com/Ramotion/animated-tab-bar

more插件: http://code4app.com/ios/Raised-Center-Tab-Bar/4f68162c6803fa791c000003

  1. 导航条的颜色修改,见下连接; 关于如何修改icon的颜色,可以修改图片也可以把它定义为模板,然后调整色值
    http://www.cocoachina.com/ios/20150703/12363.html

直接一次性修改导航背景颜色,用代码可看这里 :https://developer.xamarin.com/recipes/ios/content_controls/navigation_controller/change_the_nav_bar_color/

36) 在tableHeadView展示textView(自适应内容size)
a) 正常把textView拖到headView内,不勾选“scroll enabled”。
b ) 设置 上下左右的autolayout,注意不要设置高度。 就着两步,就可以实现textView的自适应。

 c )接下来的问题主要是如下使上层的view能够自适应高度,用下面两句代码就可以实现。
        let s = tableHeadView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
    print(s.height)
    tableHeadView.frame.size.height = s.height
        简单而已就是重新获取view内元素的高度,然后刷新view高度。 需要注意view内的其他元素,比uilabel如果显示多行的话,其高度需要被刷新,因为view并没有统计变化后的高度。
       如果UILabel超过1行,代码举例: remindTitle.sizeToFit()

37) 在tableHeadView展示图片,在autolayout下让图片在屏幕宽度基础上比例输出
1. 首先计算出原图片 高度、宽度和宽高比。 (例子: let imageHeight = imageView.image?.size.height)
2. 因为用户了autolayout,通过imageView.frame并不能获取图片在手机展示的真实尺寸,所以采用折中方法从screen获取,如 let rect = UIScreen.mainScreen().bounds.size.width
3. 屏幕的宽度与autolayout的imageView宽度差不多,所以就可以用屏幕宽度和图片比例计算出imageView的高度。
4.还有一个要注意,因为在autolayout为了避免constraint出错,所以给imageView设置了固定高度,并建立IBOutlet,如 @IBOutlet weak var imageHeightContraint:NSLayoutConstraint?, 所以步骤3计算的值就给这里赋值。

38) 关于tableViewCell插入图片时,其高度的问题,正常做法用subclass保存cell,然后在cell设置auto layout,在程序运行时修改constraint。 我目前做法没有设subclass,不设置image的高度,但auto layout就报红色,但目前运行没影响。

39) 在button增加action时,遇到crash情况,原因是对应方法如果有参数,就要增加冒号,如下所示。
func likeCheckIntemp(sender:AnyObject) {}
cell.likeButton.addTarget(self, action: "likeCheckIntemp:", forControlEvents: UIControlEvents.TouchUpInside)

40)UITableViewCell图片加载错乱问题
http://stackoverflow.com/questions/16663618/async-image-loading-from-url-inside-a-uitableview-cell-image-changes-to-wrong

  1. 用xib后,在checkIn列表点击comment按钮,sender的值不同,原来是button,用户xib后是整个VC
    貌似可以用如下方法解决,在button增加tag,传值时传过去:http://stackoverflow.com/questions/24814646/attach-parameter-to-button-addtarget-action-in-swift
    进展:暂还不要连接的解决方式,因为问题是自己在segue传值时没把值传过去,按下面传过去就好。
    func commentCheckIn(sender:AnyObject) { self.performSegueWithIdentifier("segueToComment", sender: sender)
    }
    42) 关于tableView的自动行高,如下面代码;如果label要多行,在storyboard上选line=0

    self.tableView.rowHeight = UITableViewAutomaticDimension;
    self.tableView.estimatedRowHeight = 44.0; // 设置为一个接近“平均”行高的值

  2. 在UITableViewController上定义底部toolbar问题: 1)toolbar有跳跃才回到底部。2)而且影响previous的view。经过多次尝试,最后在该tableViewVC定义其位置,在viewWillDisappear隐藏toolbar

44) 在tableView删除某行时,出错“ Invalid update: invalid number of rows in section 0 ...” 大概意思是删除时行数不一致造成错误

  1. 补充记录,如何使用XIB?
    1. 首先创建xib文件和对应swift文件
    2. 对应tableViewCell,要先在storyboard的cell上选择class和identifier与xib相一致
    3. 在swift文件的cellForRowIndexPath 注册xib文件,样式如下:
      tableView.registerNib(UINib(nibName: "RemindListTableViewCell", bundle: nil), forCellReuseIdentifier: "RemindListCell")
      let cell = tableView.dequeueReusableCellWithIdentifier("RemindListCell", forIndexPath: indexPath) as! RemindListTableViewCell

45)点back时的反向传参数 (通过代理实现实时传参数)
http://stackoverflow.com/questions/24298413/how-to-pass-information-back-in-ios-when-reversing-a-segue-using-swift

这个实现方式更代码更少
http://stackoverflow.com/questions/24318480/passing-data-in-swift/24318588#24318588

6步实现代理简单教程 http://www.jianshu.com/p/b077bcd4b168

46) 关于下级VC修改要同步到上级VC的问题,只要通过segue把数据传递,并且上级返回时没有重复取值,下级的修改会直接同步到上级VC,因为他们实际是同一值,存在同一个内存区。

46)触发提醒的最合适时机是基于使用场景。详细见文章:
http://techcrunch.com/2014/04/04/the-right-way-to-ask-users-for-ios-permissions/

47) iOS的推送问题排查,请看这里:
https://leancloud.cn/docs/push_guide.html#推送结果查询

48)如何在自己项目添加playground? 大概意思就是用playground调用项目函数
https://medium.com/@LogMaestro/adding-playgrounds-to-your-xcode-project-79d5ea0c7087#.n38qa9dfw

  1. 关于deviceToken获取,installation表更新逻辑
    a. 不管是在app调用注册通知,还是用户刚开始没注册,然后在setting点启动,app都会在调用appDelegate的registerRemoteNotification获取deviceToken
    b. 我们要做的是在启动和登录时增加一个判断,在installation表保证uid、deviceToken的对应上,并且是唯一性,老记录要删除。

50) 关于缓存方案, 有文章说,先在viewdidload加载所要的数据并且缓存,然后在viewwillappear

   思考: 1. 单个提醒信息,缓存5分钟;修改时直接修改变量并且异步保存到服务器。
  1. 由于保存图片出错,出现右边错误值Optional(<null>),在后台看是空,但又不是nil。 找了个判断方法,通过长度来判断。
    看下例子: //正常情况用不到,紧在保存照片时crash时才会导致出现null var imageNull = false if remindLC.valueForKey("image") is NSNull { imageNull = true
    }

52)关于在checkFlow页点击“评论”,在评论页不显示 toolbar的问题,经过反复尝试,目前找到解决方法是在checkFlow上层的navigation view的 storyboard设置 show toolbar, 然后后续push就有了。。但要注意后续想显示bar的页面需要hidden掉。

53) 经验:

  1. 自己项目在showRemind有设置unwind segue的IBAction “close”,然后在修改remind页只要设置segue并且指定“close”就能跳转showRemind,即使相隔了一个remindInfo的VC
    2.没有segue连接也能跳转,夸view的unwind segue: 在storyboard右键点击showRemindd”exit”,然后可以拖着连接任何VC的Action,估计连接后就能到showRemind。 (这个还木有时间试)
    关于unwind:http://stackoverflow.com/questions/12561735/what-are-unwind-segues-for-and-how-do-you-use-them

54) 关于在toolbar位置 发信对话框的实现经验。 这个问题最近修改时间花了1周,之前也折腾了1周, 总结教训是没有很好地从基层原理去了解,总希望找个控件就实现。 在实现过程中发信tableViewVC的实现比较麻烦,但由于不想切换到UIViewVC导致浪费了很多时间,其实在stackOverFlow的经验都是用UIView实现的。 不过经过这次,自己对frame位置变化,view什么时候加载、键盘变化、textViewChange等有比较深刻的认识。

  1. 修改app名字,

方法1:在info.plist文件修改 bundle display name https://developer.apple.com/library/ios/qa/qa1823/_index.html, 应该是

方法2:在target的build setting,可以设debug、release的名字,在Xcode是出debug名字,如何出release名字?

  1. 关于coreData数据保存: 只要创建了对象,数据库就会增加一行数据,所以如果remindId字段是在后续刷新,并且不能保证100%刷新,就会出现后续调用remindId出错crash情况。由于目前在保存是没找到处理该问题的好方法,所以统一在app启动时,把remind表中没有remindId的行删除。

57) 关于EULA, 好不容易找到一个用户协议的模板。 http://www.wandoujia.com/ios/eyepetizer/agreement.html ““开眼”软件用户协议”

  1. 如何使用SearchBar and Search Display Controller, 请看视频:https://www.youtube.com/watch?v=N9wcKc37ZXI,帖子: https://grokswift.com/swift-tableview-search-bar/

58) 水印功能实现,在简书找到别人共享代码,目前发现问题是 图片实际尺寸7501334,但在UIImage.size显示尺寸1/2, 即375667。。经过调试只用用10801920图图片放到x2位置,那么在不同尺寸模拟器运行时都会是540960的size。所以就用这尺寸来制作水印。

59) 关于调用其他VC的方法,之前不知道其实在Functions.swift里的functions就是VC方法,现在又增加了WaterMarkVC.swift,日后应用可以把以前访问checkInTableViewCell的那些请求做修改。

  1. 关于leanCloud的静态库、动态库引用问题: 之前一直是用静态库, 因为微信登录原因需要使用leanCloudSocial库,先引入静态发现无法引入,再引入动态发现一堆错误。后来经过与leancloud的人论坛交流,采用动态库后可用。

要注意:
1)相同的库,静态和动态只能选其一,因为是冲突的。
2)静态库的引用是在header文件上import(带路径),动态库是在每个文件头部import (无需路径)
注意:帖子上说 动态库不能用:https://forum.leancloud.cn/t/ios-sdk-swift/7589

61)可能是更新了cocoaPod引入问题,运行时有20多个错误,但在iPhone5模拟器、iPhone6s手机没有问题。感觉是跟armv7、i386架构相关,后来在building settings 的valid architectures 增加“x86_64, i386” 然后就可以了。

  1. 问题: ** a valid provisioning profile** for this excitable was not found,不知为为啥这个问题,实际上我的证书的木有问题的,自己处理是分别在project和target的 “Code Signing”重设一下就下,一般是选自动就好

推荐阅读更多精彩内容