iOS开发-周复盘·分享-20180727

作者: 07e819eca0df | 来源:发表于2018-07-29 18:50 被阅读4次

    今天给大家分享下面几点内容。

    【1】在swift中,如何实现数组的深拷贝。

    【2】如何一键 让 tableview header 取消悬停。

    【3】为什么我们明明设置了headerview,它却迟迟不出现?

    【4】如何优雅地刷新 tableview cell 里的内容?

    【5】如何优雅地卸载 cocoaPod ?

    【6】如何解决如下报错:“ ld: 3 duplicate symbols for architecture … … error: linker command failed with exit code 1 (use -v to see invocation) ” ?

    【7】如果优雅地实现 date 与 string 的互相转换(双向)。



    下面我们来一个一个说。

    【1】在swift中,如何实现数组的深拷贝。

    ——————
    「在上一讲《iOS开发-每周五复盘·分享-20180713》里的第【8】点,我们谈到了:
    一句话概括·Swift数组的值拷贝与引用传递的区别:
    只有在数组长度发生变化时,才会发生 值拷贝,否则都是 引用传递。
    今天我们来详细说一说:“ 在swift中,如何实现数组的深拷贝 ”」
    ——————


    接着上一讲的话来说,“只有在数组长度发生变化时,才会发生 值拷贝,否则都是 引用传递”,而现在说的这个“数组的深拷贝”,指的就是上面说的 值拷贝 。


    在swift中,如何实现数组的深拷贝(值拷贝)。
    对于由“整形数组、字符型数组,等简单数据类型”作为元素,组成的数组,适用于上一讲说的:“只有在数组长度发生变化时,才会发生 值拷贝,否则都是 引用传递”,详见上一讲的分享文章:《iOS开发-每周五复盘·分享-20180713》。 此处不再赘述。
    而对于由“类的实例”作为元素,组成的数组,上述方式就不适用了。
    你会发现,即使你改变了数组长度,没有直接 a=b,而是a.append(…),a数组和b数组之间依旧发生的是引用传递,不是深拷贝(值拷贝)。
    即:a数组和b数组始终指向同一片内存区域,不管修改a的元素还是b的元素,都会把另一个数组里的元素同步修改掉(因为是指向同一片内存区域,数据只有一份,没有拷贝)。


    那么如果我们就是需要这类「 由“类的实例”作为元素,组成的数组 」,做深拷贝(值拷贝),要怎么办呢?
    可以这么办:
    方案一:
    把 「由“类的实例”作为元素,组成的数组」里面的类改为结构体(class -> 改为 -> struct),即可解决这个数组无法拷贝的问题。
    ps.
    熟悉结构体struct和类class的区别的同学都知道:

    class A {…}
    let a = A()
    let a2 = a
    //vs
    struct B {…}
    let b = B()
    let b2 = b
    

    上述代码中,
    a和a2,指向的是同一片内存区域,它们之间发生的操作是 “引用传递”
    而,
    b和b2,指向的是同两片不同的内存区域,它们之间发生的操作是 “深拷贝(值拷贝)”
    方案二:
    在你定义的类里面,增加一个自定义的 copySelf方法:

    class A {
        var name: String? = nil
        …
        
        func copySelf() -> A {
            let a = A()
            a.name = self.name
            …
            return a
        }
    }
    let a = A()
    let a2 = a.copySelf()
    

    这样,就可以实现:
    a和a2,指向同两片不同的内存区域,使得它们之间发生的操作是 “深拷贝(值拷贝)”了。

    【2】如何一键 让 tableview header 取消悬停。

    ——————
    「当我们的需求,不需要 tableview header 自动悬停功能时,该如何一键处理解决?」
    ——————


    使用过 tableView 里面的 headerView 的同学都是知道,该 headerView 会自带一个默认属性,就是当 tableView 滑上去时,它会自动悬停在屏幕上方,不会跟着tableView 的 cell 一起被滑上去,
    而当 tableView 滑回来(下来)时,当滑倒该 headerView 对应的 section 的 row == 0 那一行出现时,它又会自动跟着 tableView 一起滑下来,恢复出在原来对应 section 顶部的位置。
    当我们的需求和这个一样时,那这个 tableView 的 headerView 自带的自动悬停功能(属性)会极大的方便我们开发。
    但是,若我们的需求和这个不一样,不允许 headerView 自动悬停,该怎么办呢?
    有两种解决方案:
    方案一:
    不使用 headerView ,把该行的内容,用一个自定义的 cell 来实现。
    方案二:(推荐)
    设置 tableview 的 style 属性(UITableViewStyle) 为 .grouped 即可
    (其默认值为 .plain)

    【3】为什么我们明明设置了headerView,它却迟迟不出现?

    ——————
    「使用过 tableView 里的 headerView 的同学,可能遇到过这个问题,就是:
    “ 我们明明设置了headerView,它却迟迟不出现 ”,怎么解决呢?」
    ——————


    原因分析:
    我们都知道,要设置 tableView 里的 headerView ,需要在 tableViewDelegate 里的

     func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {}
    

    这个代理方法里做相应设置。
    但为什么,我们明明在这里面设置了headerView,它却迟迟不出现呢?
    那是因为:
    headerview 的 viewForHeaderInSection 代理,会被 heightForHeaderInSection 代理约束。
    即,不管你在 viewForHeaderInSection 里怎么设置 headerview 的 frame、样式 ,等等,它都会在最后一步,被 heightForHeaderInSection 代理,在约束一遍。
    也就是说,如果在 heightForHeaderInSection 代理里,你没有设置 headerview 的高度(默认值为0),或者,把它设为了零。
    那么 headerview 肯定是 不管你在viewForHeaderInSection里怎么设置,都是不会出现的。
    解决方案:

    //同时设着下述两个代理里的实现内容:
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {}
    
    //该 height 设为 所需 headerview 的实际 height 值
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {}
    

    【4】如何优雅的刷新 tableview cell 里的内容?

    ——————
    「使用过 tableview 的同学都知道,如果要刷新 tableview cell 里的内容,
    可以调用 tableview.reloadData()方法。
    那么有没有更优雅的实现方式,不需要去做 reload 操作就可以实现,tableview cell 里的内容得以刷新的效果呢?」
    ——————


    答案是肯定的:
    解决方案:
    比如,实现如下功能:
    “在点击某一行后,修改改行的已读状态(取消显示小红点)”
    不使用 tableview.reloadData() 方法的
    实现代码如下:

        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            
               let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? Cell
                
                            …
                            …
                            …
                    if dataArryIndex < mCellArray.count {
                        mCellArray.count[indexPath.row] = cell
                    }
                }
                return cell!
            }
    }
    
    
     override  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            let dataArryIndex = indexPath.row
            if dataArryIndex < mCelllArray.count {
              mCellArray[dataArryIndex]?.setReadStatus(true)
            }
        }
    

    【5】如何优雅地卸载 cocoaPod ?

    ——————
    「使用 “cocoapods-deintegrate”」
    ——————


    使用方式:
    终端命令行,输入如下命令即可:

    sudo gem install cocoapods-deintegrate
    pod deintegrate
    

    ps.
    该 cocoapods-deintegrate 的 github地址:
    https://github.com/CocoaPods/cocoapods-deintegrate

    【6】如何解决如下报错:“ ld: 3 duplicate symbols for architecture … … error: linker command failed with exit code 1 (use -v to see invocation) ” ?

    ——————
    「为什么会这个错呢?主要原因是,在 project.pbxproj 中重复引用了同一个文件」
    ——————


    解决方案:
    打开 project.pbxproj 文件,
    找到你重复引用的文件(该文件的文件名,在你的报错信息里有显示,对应着找即可),
    删除重复,只保留一份。
    ps.
    该报错,常出现于合并分支解决冲突后(没解决好,重复引用了同一个文件)。

    【7】如果优雅地实现 date 与 string 的互相转换(双向)

    ——————
    「如何优雅的实现呢?」
    ——————


    实现方案如下:

        static func timeStampToString(_ timeStamp: String, format: String) -> String {
            if let timeInterval: TimeInterval = TimeInterval(timeStamp) {
                let date = Date(timeIntervalSince1970: timeInterval)
                let formatter = DateFormatter()
                formatter.dateFormat = format
                
                return formatter.string(from: date)
            }
            
            return ""
        }
        
        static func StringToTimeStamp(_ currDate: String, currformat: String, locale: String = "en_US_POSIX") -> TimeInterval?{
            var result: TimeInterval? = nil
            let formatter = DateFormatter()
            formatter.dateFormat = currformat
            formatter.locale = Locale(identifier: locale)
            if let date = formatter.date(from: currDate) {
                let dateStamp = date.timeIntervalSince1970
                result = dateStamp
            }
            return result
        }
    
    
        static func StringToString(currDate: String, currformat: String = "MMM dd, yyyy hh:mm:ss a", targetformat: String = "MM-dd HH:mm") -> String {
            var targetDateAfterformat = ""
            if let transferResult = BaseTimeProcessingUtility.StringToTimeStamp(currDate, currformat: currformat) {
                targetDateAfterformat = BaseTimeProcessingUtility.timeStampToString(transferResult, format: targetformat)
            }
            return targetDateAfterformat
        }
    



    ——————

    ~ ^_^ ~
    

    —— zeroOS 复盘于 2018/07/29
    「zeroOS·简书号」
    © 著作权归作者所有

    相关文章

      网友评论

        本文标题:iOS开发-周复盘·分享-20180727

        本文链接:https://www.haomeiwen.com/subject/tjltvftx.html