• swift

    2018-11-22 15:43:42
    iOS 跳转到任意某个rootViewController     x 代表第几个根视图,任意视图跳转哦   self.tabBarController.selectedViewController = self.tabBarController.childViewControllers[X];...[self....

    iOS 跳转到任意某个rootViewController

     

     

    x 代表第几个根视图,任意视图跳转哦

     

    self.tabBarController.selectedViewController = self.tabBarController.childViewControllers[X];

     

    [self.navigationController popToRootViewControllerAnimated:YES];

     

    iOS ViewController 截屏方法

    vc.backimage = self.snapView(targetView: self.view)截屏方法

    //截屏
    func snapView(targetView: UIView) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(targetView.bounds.size, false, 0)
    // iOS7.0 之后系统提供的截屏的功能
    targetView.drawHierarchy(in: targetView.bounds, afterScreenUpdates: false)

    let snapdImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return snapdImage!

    }

    //改变状态栏颜色

        override var preferredStatusBarStyle: UIStatusBarStyle {

            if statusBarShouldLight {

                return .lightContent

            } else {

                return .default

            }

        }

     

        /// 更改图片颜色

        public func imageWithTintColor(color : UIColor) -> UIImage{

            UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)

            let context = UIGraphicsGetCurrentContext()

            context?.translateBy(x: 0, y: self.size.height)

            context?.scaleBy(x: 1.0, y: -1.0)//kCGBlendModeNormal

            context?.setBlendMode(.normal)

            let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)

            context?.clip(to: rect, mask: self.cgImage!)

            color.setFill()

            context?.fill(rect)

            let newImage = UIGraphicsGetImageFromCurrentImageContext()

            UIGraphicsEndImageContext()

            return newImage!

        }

    //scrollView偏移问题

    只要scrollView是其父视图上的第一个子视图,且navigationBar不隐藏的情况下,添加到scrollView里的视图,都会默认下移64个像素。ios11好像没问题,解决冲突 在前面加个view或禁止系统偏移  vc.automaticallyadjustsScrollviewInsets =NO 这个好像不行

     

     

     

     

    ///hidesBottomBarWhenPushed push跳转时隐藏/显示UITabBar

    self.hidesBottomBarWhenPushed = false

    //关闭视图过渡动画 

            UIView.performWithoutAnimation {

    tableView刷新会跳动之类的这些奇怪的动画,把刷新方法放在这里就可以了

            }

     

     

     

     

    展开全文
  • 1.从视图A中navigation controller push到视图B,当视图B navigationcontroller pop回到视图A时,并不会调用A的viewDidLoad,但是会调用viewWillAppear,所以如果视图A有需要变更的内容应该在viewWillAppear中实现。...

    1.从视图A中navigation controller push到视图B,当视图B navigationcontroller pop回到视图A时,并不会调用A的viewDidLoad,但是会调用viewWillAppear,所以如果视图A有需要变更的内容应该在viewWillAppear中实现。


    2.当一个视图生成时是先调用viewDidLoad,再调用viewWillAppear的。


    3.如果视图刷新时,其中的内容没有改变,要考虑内容的数据源是否被变更了。

    展开全文
  • POP是一个来自于Facebook,在iOS与OSX上通用的极具扩展性的动画引擎。它在基本的静态动画的基础上增加的弹簧动画与衰减动画,使之能创造出更真实更具物理性的交互动画。 Pop Animation在使用上和Core Animation很...

    • POP是一个来自于Facebook,在iOS与OSX上通用的极具扩展性的动画引擎。它在基本的静态动画的基础上增加的弹簧动画与衰减动画,使之能创造出更真实更具物理性的交互动画。
    • Pop Animation在使用上和Core Animation很相似,都涉及Animation对象以及Animation的载体的概念
    • 关于Core Animation的相关详解, 可参考我的上一篇文章Core Animation(核心动画)
    • 不同的是Core Animation的载体只能是CALayer,而Pop Animation可以是任意基于NSObject的对象
    • POP 使用 Objective-C++ 编写,Objective-C++ 是对 C++ 的扩展

    GitHub项目地址

    一. POP自我介绍

    • POP 目前由四部分组成:1. Animations;2. Engine;3. Utility;4. WebCore。
    • POP 动画极为流畅,主要在于Enimator 里,POP 通过 CADisplayLink 高达 60 FPS 的特性,打造了一个游戏级的动画引擎。
    • CADisplayLink 是类似 NSTimer 的定时器,不同之处在于,NSTimer 用于我们定义任务的执行周期、资料的更新周期,他的执行受到 CPU 的阻塞影响,而 CADisplayLink 则用于定义画面的重绘、动画的演变,他的执行基于 frames 的间隔。
    • 通过 CADisplayLink,Apple 允许你将 App 的重绘速度设定到和屏幕刷新频率一致,由此你可以获得非常流畅的交互动画,这项技术的应用在游戏中非常常见,著名的 Cocos-2D 也应用了这个重要的技术。
    • WebCore 里包含了一些从 Apple 的开源的网页渲染引擎里拿出的源文件,与 Utility 里的组件一并,提供了 POP 的各项复杂计算的基本支持

    二. POP参数介绍

    POP默认支持三种动画,但同时也支持自定义动画
    • POPBasicAnimation //基础动画
    • POPSpringAnimation //弹簧动画
    • POPDecayAnimation //衰减动画
    • POPCustomAnimation //自定义动画

    1、相关属性介绍

    1-1、属性简单介绍

    • POP动画大部分属性和CoreAnimation(核心动画)的含义和用法一样
    • 具体可参考Core Animation(核心动画)
    • 每种动画的特殊属性会在下文中继续介绍

    1-2、动画可配置属性

    • CALayer层各属性(比较简单,就不加注释了)
    /**
     Common CALayer property names.
     */
    extern NSString * const kPOPLayerBackgroundColor;
    extern NSString * const kPOPLayerBounds;
    extern NSString * const kPOPLayerCornerRadius;
    extern NSString * const kPOPLayerBorderWidth;
    extern NSString * const kPOPLayerBorderColor;
    extern NSString * const kPOPLayerOpacity;
    extern NSString * const kPOPLayerPosition;
    extern NSString * const kPOPLayerPositionX;
    extern NSString * const kPOPLayerPositionY;
    extern NSString * const kPOPLayerRotation;
    extern NSString * const kPOPLayerRotationX;
    extern NSString * const kPOPLayerRotationY;
    extern NSString * const kPOPLayerScaleX;
    extern NSString * const kPOPLayerScaleXY;
    extern NSString * const kPOPLayerScaleY;
    extern NSString * const kPOPLayerSize;
    extern NSString * const kPOPLayerSubscaleXY;
    extern NSString * const kPOPLayerSubtranslationX;
    extern NSString * const kPOPLayerSubtranslationXY;
    extern NSString * const kPOPLayerSubtranslationY;
    extern NSString * const kPOPLayerSubtranslationZ;
    extern NSString * const kPOPLayerTranslationX;
    extern NSString * const kPOPLayerTranslationXY;
    extern NSString * const kPOPLayerTranslationY;
    extern NSString * const kPOPLayerTranslationZ;
    extern NSString * const kPOPLayerZPosition;
    extern NSString * const kPOPLayerShadowColor;
    extern NSString * const kPOPLayerShadowOffset;
    extern NSString * const kPOPLayerShadowOpacity;
    extern NSString * const kPOPLayerShadowRadius;
    
    复制代码
    • UIVIew层
    /**
     Common UIView property names.
     */
    extern NSString * const kPOPViewAlpha;
    extern NSString * const kPOPViewBackgroundColor;
    extern NSString * const kPOPViewBounds;
    extern NSString * const kPOPViewCenter;
    extern NSString * const kPOPViewFrame;
    extern NSString * const kPOPViewScaleX;
    extern NSString * const kPOPViewScaleXY;
    extern NSString * const kPOPViewScaleY;
    extern NSString * const kPOPViewSize;
    extern NSString * const kPOPViewTintColor;
    
    复制代码
    • 其他层视图层
    /**
     Common UINavigationBar property names.
     */
    extern NSString * const kPOPNavigationBarBarTintColor;
    
    /**
     Common UIToolbar property names.
     */
    extern NSString * const kPOPToolbarBarTintColor;
    
    /**
     Common UITabBar property names.
     */
    extern NSString * const kPOPTabBarBarTintColor;
    
    /**
     Common UILabel property names.
     */
    extern NSString * const kPOPLabelTextColor;
    
    复制代码

    以上仅仅列出了常用的一些属性,更多控件/更多参考框架里面类 POPAnimatableProperty.h

    1-3、POPBasicAnimation可配置的属性与默认值为

    POPBasicAnimation *basic = [POPBasicAnimation linearAnimation];
    basic.fromValue = @(0);//从0开始    basic.toValue = @(3*60);//180秒后结束
    basic.duration = 3*60;//持续3分钟
    [lab pop_addAnimation:basic forKey:nil];
    
    复制代码
    let basic1 = POPBasicAnimation(propertyNamed: kPOPLayerPositionX)
    basic1?.fromValue = redView.layer.position.x
    basic1?.toValue = 300
    basic1?.beginTime = CFTimeInterval() + 1.0
    redView.pop_add(basic1, forKey: "position.x")
    
    复制代码

    三. POPBasicAnimation基础动画

    1. 先看一下效果, 其动画效果如下

    2. 示例代码

    let basic1 = POPBasicAnimation(propertyNamed: kPOPLayerPositionX)
    basic1?.toValue = 300
    //开始时间
    basic1?.beginTime = CFTimeInterval() + 1.0
    redView.pop_add(basic1, forKey: "position.x")
    复制代码

    3. 可以看到,添加一个动画最少仅需三步

    • 1)定义一个animation对象,并指定对应的动画属性(kPOPLayerPositionX
    • 2)设置初始值结束值(初始值可以不指定,会默认从当前值开始)
    • 3)添加到想产生动画的对象上

    4. Core Animation 和 POP 运行动画对比

    • 由于 POP 是基于定时器定时刷新添加动画的原理,那么如果将动画库运行在主线程上,会由于线程阻塞的问题导致动画效果出现卡顿、不流畅的情况。
    • 更为关键的是,你不能将动画效果放在子线程,因为你不能将对 view 和 layer 的操作放到主线程之外
    • POP 受主线程阻塞的影响很大,在使用过程中,应避免在有可能发生主线程阻塞的情况下使用 POP ,避免制作卡顿的动画效果,产生不好的用户体验

    四. POPSpringAnimation弹性动画

    1. 属性介绍

    • velocity: 设置动画开始速度
    • springBounciness: 振幅, 可以设置的范围是0-20,默认为4。值越大振动的幅度越大
    • springSpeed: 速度, 可以设置的范围是0-20,默认为12.值越大速度越快,结束的越快
    • dynamicsMass: 质量, 质量越大,动画的速度越慢,振动的幅度越大,结束的越慢
    • dynamicsTension: 拉力 拉力越大,动画的速度越快,结束的越快
    • dynamicsFriction: 摩擦力, 摩擦力越大,动画的速度越慢,振动的幅度越小。

    注意: 以上的六个属性中一般只会设置springBouncinessspringSpeed, 如有特殊需求才会设置其他属性

    2. 代码示例

    let spring = POPSpringAnimation(propertyNamed: kPOPViewScaleXY)
    //注意: 这里改变的是x和y的比例,参数赋值也要传两个; 若只需要其中一个,则可设置
    //`spring?.fromValue = 0.4`即可
    spring?.fromValue = CGSize(width: 0.3, height: 0.3)
    spring?.toValue = CGSize(width: 2, height: 2)
    spring?.springSpeed = 5
    spring?.springBounciness = 15
    lightBlue.pop_add(spring, forKey: "scale")
    
    复制代码

    五. POPDecayAnimation

    • POPDecayAnimation提供一个过阻尼效果(其实Spring是一种欠阻尼效果)可以实现类似UIScrollView的滑动衰减效果(是的你可以靠它来自己实现一个UIScrollView

    属性介绍

    • deceleration (负加速度, 衰减系数(越小则衰减得越快)) 是一个你会很少用到的值,默认是就是我们地球的 0.998,如果你开发APP给火星人用,那么这个值你使用 0.376 会更合适
    • velocity 也是必须和你操作的属性有相同的结构,如果你操作的是 bounds, 传CGRect类型;如果 velocity 是负值,那么就会反向递减

    代码示例

    let decay = POPDecayAnimation(propertyNamed: kPOPViewSize)
    decay?.velocity = CGSize(width: 300, height: pictureBtn.frame.height)
    //延迟1秒后执行
    decay?.beginTime = CACurrentMediaTime() + 1.0
    pictureBtn.pop_add(decay, forKey: "size")
    
    复制代码

    六. 自定义属性

    POP默认支持的三种动画都继承自POPPropertyAnimation, POPPropertyAnimation中定义了一个叫property的属性(之前没有用到它是因为POP根据不同的默认动画属性帮你生成了默认的property这个属性则是用来驱动POP的动画效果中的重要一环

    1. 实力模块

    if let proper = POPAnimatableProperty.property(withName: "prop", initializer: { (prop) in
        guard let prop = prop else { return }
        //read
        prop.readBlock = { (obj, values) in
                    
        }
                
        //write
        prop.writeBlock = {(obj, values) in
                    
        }
        prop.threshold = 0.01
                
    }) as? POPAnimatableProperty {
        anim.property = proper
    }
    复制代码

    2. 属性介绍

    其组成就是一个readBlock一个writeBlock和一个threashold

    • readBlock告诉POP当前的属性值
    • writeBlock中修改变化后的属性值
    • threashold决定了动画变化间隔的阈值 值越大writeBlock的调用次数越少

    POPAnimatableProperty其实是POP中一个比较重要的东西 像上面提到的POP自带的动画属性 查看源代码可以看到也只是POP自动帮你设置好了POPAnimatableProperty而已 其作用就是当动画的某个时间片被触发时 告诉系统如何根据当前时间片做出变化

    还是以一个实际的例子来说明如何使用自定义属性 比如我们要实现一个像系统的时钟APP里秒表计时的一个效果

    3. 完整代码示例

    if let proper = POPAnimatableProperty.property(withName: "prop", initializer: { (prop) in
        guard let prop = prop else { return }
        //read
        prop.readBlock = { (obj, values) in
            guard let array = values else { return }
            print(array[0])
        }
        
        //write
        prop.writeBlock = {(obj, values) in
            guard let button = obj as? UIButton, let array = values else { return }
            let value = array[0]
            button.setTitle(String(format: "%02d:%02d:%02d", Int(value / 60), Int(value.truncatingRemainder(dividingBy: 60)), Int((value * 100).truncatingRemainder(dividingBy: 100))), for: .normal)
        }
        prop.threshold = 0.01
        
    }) as? POPAnimatableProperty {
        if let popBasic = POPBasicAnimation.linear() {
            //秒表用线性的时间函数初始化
            popBasic.property = proper
            popBasic.fromValue = 0 //从0开始
            popBasic.toValue = 18  //到18秒
            popBasic.duration = 18 //持续18秒
            popBasic.beginTime = CACurrentMediaTime() + 2 //延迟2秒开始
            pictureBtn.pop_add(popBasic, forKey: "linear")
        }
    }
    
    复制代码

    4. 注意:

    • 在Swift4.0版本(4.0之前版本未知)中,初始化出来的对象都是可选类型
    • POP官方的建议是添加if条件判断,详情可到GitHub上查看示例
    • 正如上段代码所示: 闭包中涉及的可选类型都添加了guard判断

    七. 类似微博中间发布按钮弹出动画

    先看一下效果吧

    动画分为两个部分

    • 中间六个按钮依次执行动画弹出
    • 上面标题图片最后动画落下

    下面来看一下部分的核心代码

    1. 六个按钮的弹出和消失动画
    for i in 0..<titles.count {
        let button = BaseButton()
        button.setTitle(titles[i], for: .normal)
        button.setImage(UIImage(named: images[i]), for: .normal)
        button.addTarget(self, action: #selector(buttonClick(button:)), for: .touchUpInside)
        addSubview(button)
        
        //计算X/Y
        let row = i / maxCols
        let col = i % maxCols
        let buttonX = btnStsrtX + CGFloat(col) * (xMargin + buttonW)
        let buttonEndY = btnStartY + CGFloat(row) * buttonH
        let buttonStartY = buttonEndY - kScreenHeight
        
        //按钮动画
        let popSpring = POPSpringAnimation(propertyNamed: kPOPViewFrame)
        popSpring?.fromValue = CGRect(x: buttonX, y: buttonStartY, width: buttonW, height: buttonH)
        popSpring?.toValue = CGRect(x: buttonX, y: buttonEndY, width: buttonW, height: buttonH)
        popSpring?.springBounciness = kSpringFactor
        popSpring?.springSpeed = kSpringFactor
        popSpring?.beginTime = CACurrentMediaTime() + kAnimationDelay * Double(i)
        button.pop_add(popSpring, forKey: "spring")
    }
    
    复制代码
    2. 最上部分标语的弹出和消失
    //z执行动画
    let imagePOP = POPSpringAnimation(propertyNamed: kPOPViewCenter)
    imagePOP?.fromValue = CGPoint(x: kScreenWidth * 0.5, y: 0.2 * kScreenHeight - kScreenHeight)
    imagePOP?.toValue = CGPoint(x: kScreenWidth * 0.5, y: 0.2 * kScreenHeight)
    imagePOP?.springSpeed = kSpringFactor
    imagePOP?.springBounciness = kSpringFactor
    imagePOP?.beginTime = CACurrentMediaTime() + Double(btnCount) * kAnimationDelay
    imagePOP?.completionBlock = { popAnim, finished in
        //所有动画执行完毕,回复View点击事件
        kRootView?.isUserInteractionEnabled = true
        self.isUserInteractionEnabled = true
    }
    topImage.pop_add(imagePOP, forKey: nil)
    
    复制代码

    以上是类似微博动画的部分核心代码, 具体代码详见GitHub项目, 喜欢请star

    github项目介绍

    • 折叠图片
    • 音量震动条
    • 活动指示器
    • 微博动画
    • 倒计时-计时器
    • 类似QQ信息条数的粘性动画
    • 类似雷达-水波纹动画

    注: 项目持续更新中......

    展开全文
  • Swift 开源项目汇总

    2019-09-16 16:07:05
    Swift 开源项目汇总

    1. 完整项目

    1.1 直播类App

    1. XJ直播是一款基于Swift3.0开发的直播平台,
    2. 整个项目使用MVVM架构 + 响应式编程 + Swift3.0进行编写,主要是练习swift3.0语法以及MVVM的使用;
    3. 本项目用到了视频的采集,编码,解码等技术,采用的是目前主流的第三方框架IJKMediaFramework;
    4. 在本地利用Socket搭建一个简易的服务器,用来模拟客户端和服务器之间的交互;
    5. 项目中主要用到了图文混排、弹幕、粒子动画、自定义动画等技术。
    6. Xib、Storyboard、Storyboard Reference、自动布局高级使用。
    7. UITabbarController、UICollectionView、UIScrollView高级使用。
    8. 下载地址:https://pan.baidu.com/s/1pKYx8Sj 密码: jkri
    • Swift 精仿有妖气漫画:90%精仿原版有妖气漫画(登录,充值等涉及版权或者会员等功能均不作实现),使用三方框架,感谢 SnapKit, Then, Moya, HandyJSON, Kingfisher, Reusable, LLCycleScrollView, MJRefresh, MBProgressHUD, HMSegmentedControl, IQKeyboardManagerSwift, EmptyDataSet-Swift

    Swift 精仿有妖气漫画

    1.2 安防类App

    1.3 新闻类App

    • xx头条:款专注郸城老家本地生活服务APP,集信息发布、商家品牌推广、相亲交友、求职招聘、找同学、吃喝玩乐等便民信息。(简述
    • DesignerNewsApp: Simple iOS client for Designer News, by the creator of Design+Code and the team, written in Swift.
    • SwiftHN: 一款新闻app. A Hacker News reader in Swift
    • 糗百客户端:基于swift,用糗事百科的API简单做了一个糗百客户端,可以浏览各种段子,浏览搞笑图片,查看精彩评论等.
    • 仿知乎日:用Swift实现的仿知乎日报应用
    • TodayNews: 高仿今日头条swift版本。
    • Swift 高仿喜马拉雅FM

      OC 版本:下载点击这里

    1.4 电商类App

    • 单糖:良品生活指南:家居零食、礼物美妆、海淘购物。(介绍文档

    单糖

    爱鲜蜂

    高仿小日子Swift2.0

    模仿“妙汇”电商项目

    Swift高仿项目,堆糖

    1.5 跨平台App

    1.6 工具类App

    1.7 游戏类App

    1.8 社交类App

    The Wire mobile app has an architectural layer that we call sync engine . It is the client-side layer that processes all the data that is displayed in the mobile app. It handles network communication and authentication with the backend, push notifications, local caching of data, client-side business logic, signaling with the audio-video libraries, encryption and decryption (using encryption libraries from a lower level) and other bits and pieces.

    • Yep: 一款轻量级社交app MVC + Rxswift编写

    Yep is a nifty and lightweight social networking app, revolving around the theme of “Meeting Genius”, enabling users to find experts or other learners of a particular domain.
    The project’s architecture is easy to understand, following the common software pattern MVC, separating UI, business logic and data model. Now, let’s dive into the Yep project!

    特色:

    1. 可以发送富文本,表情,图片还有声音。
    2. TSChatImageCell 中显示的图片使用 Mask Layer 进行绘制,你可以自由的切换聊天背景图,这样看上去 UI 也不会糟糕。
    3. 自定义的表情键盘,自定义的工具键盘。
    4. 录音的 wav 文件会被自动转换成 amr文件,这样可以方便和 Android 设备进行文件传输。这两种文件都已做了缓存。上传使用 amr 文件,播放使用 wav 文件。
    5. 当你点击声音 TSChatVoiceCell 的时候,它会自动检测缓存,如果没有那么会使用 Alamofire 自动进行下载。
    6. 当你发送图片的时候,系统会使用 Kingfisher 缓存机制存放在本地,上传成功后会自动修改成图片链接的 MD5 值文件名字。
    7. 数据是从 JSON 文件里面加载来的, 所有的 Model 是使用 ObjectMapper 创建的。
    • 聊天应用Acani Chats: Acani Chats是一款非常简单而又优雅的聊天应用,界面清爽明了。不过,别小看这一“简单”,通过它托管在Github上的源代码,你可以学习和探索类似应用开发所必须的语法。Acani Chats支持基础性的一些事件,比如联系人头像和现代化的iOS用户界面,绝对是你着手学习开发聊天应用的一个超好的案例。
      聊天应用Acani Chats

    1.9 音视频app

    1.10 图像处理app

    • PixPic: 一款swift编写的图像,相册处理app
    • Surge(Swift + Accelerate):Surge基于Accelerate框架开发,用于执行矩阵数学、数字信号处理以及图像处理等方面。换句话说,它可以快速处理复杂的数学、语音以及图像信号。并且依然来自于大神级人物mattt。
    • 图片查看器SwiftFlickrApp: SwiftFlickrApp是使用Swift编写的Flickr照片查看器。你可以在单独的页面上以网格或列表的形式浏览照片,或进行缩放处理。Github上托管的源码涉及不少知识点,会给你一些如何使用 UICollectionView和AFNetworking的见解和看法。

    1.11 生活助手类app

    花田小憩3.0.1

    1.12 支付app

    • Viewfinder : 移动支付公司 Square 将去年收购的照片应用 Viewfinder 开源了,包含服务端、iOS 和 Android 应用代码

    1.13 AR/VR 项目App

    在这里插入图片描述

    1.14 通讯录相关

    • 联系提醒应用iContactU:ContactU是一款用于提醒你联系指定人员的应用。在联系人中选择人员,设置提醒时间和内容,到了时间iContactU会提醒你,你可以直接在应用中通过邮件、短信、电话等方式联系对方。

    1.15 彩票类

    1.16 股票类

    1.17 摄像类

    1.18 阅读器类

    • Hacker News阅读器: Hacker News来自YCombinator,所以一直以来都有顶级创业者参与讨论,用户创造的内容质量也远高于其他创业者主题网站。最可贵的是Hacker News没有任何盈利企图,唯一的目的就是吸引和配有下一代创业者。而这里介绍的就是一款Hacker News阅读器,使用Swift语言编写,提供了一个不错的无缝用户界面,可以查看最新及最受喜欢的信息,并能够从中直接读取内容。

    2. 网络库

    基础网络框架

    1. Alamofire:著名的AFNetworking网络基础库Swift语言版

    2.1 Socket

    2.2 TCP/IP

    2.3 Websocket

    1. starscream:WebSocket客户端类库.

    2.4 WebRTC

    3. 数据处理

    3.1 Json数据解析

    • SwiftyJSON:GitHub上最为开发者认可的JSON解析类

    3.2 xml数据解析

    • AEXML:简单又易于的XML解析类及示例

    3.3 DB存储框架

    3.3.1 DB 处理框架

    • SQLite.swift:纯swift实现的类型安全的SQLite3封装,简单、轻量,使用上最SQL的SQLite封装库。特点:

    (1)简单的查询和参数绑定接口,
    (2)安全、自动类型数据访问
    (3)隐式提交和回滚接口
    (4)开发者友好的错误处理和调试
    (5)文档完善
    (6)通过广泛测试
    (7)支持全文检索
    (8)支持SQLCipher

    • Realm:志向代替Core Data和SQLite的移动数据库.Realm 是一个移动数据库,可运行于手机、平板和可穿戴设备之上。可以让你的应用更快速,带来难以想象的体验。其目标是为了代替 CoreData 和 SQLite 数据库。
      目前支持 iOS/OS X/Android 平台,提供 Swift/Objective-C/Java 语言的 API

    • WCDB.swift : 腾讯开发的,微信使用的开源框架。非常简单易用。

    • RealmIncrementalStore.swift - RealmIncrementalStore.swift:集 Realm 数据库和 CoreData 对象模型两者优势的 Realm 数据库访问类库。

    • fluent.swift - 纯swift实现的类型安全的SQLite3封装,数据存储和JSON解析是永恒的话题。

    • swiftydb - 是一个第三方 SQLite 工具,能够大大简化数据库操作。如果你不放心 Realm,那就用 SwiftyDB 吧。使用教程demo

    • SwiftStore - Key-Value store for Swift backed by LevelDB ?

    • SQL 数据库抽象层 API 库 Swift-Kuery

    Swift-Kuery是一个可插拔的SQL数据库驱动程序/ SDK抽象层。 其主要思想是提供一套API,能操作各种关系型数据库,目前支持PostgreSQL、SQLite、MySQL。
    虽然Swift-Kuery不是对象关系映射(ORM),但它为构建ORM提供了很大的基础。 如果您不想使用特定的数据库,允许在不同数据库之间轻松切换, Swift-Kuery将会很有用。

    • SQLite数据库工具包GRDB.swift: GRDB.swift是一个SQLite数据库工具包,主要用于应用程序的开发。
      与SQLite.swift或FMDB相比,GRDB可以为您提供大量的胶水代码。 与Core Data或Realm相比,它可以简化您的多线程应用程序。
    • Swift SQLite O-R 映射工具类库 swiftydb: swiftydb 是一个类型安全、基于协议的 SQLite 数据库工具类库,可以轻松的持久化任何对象,纯 Swift 实现。
    • Swift ORM框架 SwiftyDB: SwiftyDB是一个基于SQLite数据库的ORM框架,用Swift语言编写,同时支持Objective-C语言。
      其特性为:线程安全、嵌套事物、模型操作、支持迁移、使用方便。
    • Swift 面向协议的 Keychain 类库 Locksmith: Locksmith 是一个强大的,面向协议的类库,用于在 Swift 中使用 Keychain 。
    • 持久化类库Pantry: 可以持久化基础类型变量值的类库。

    3.3.2 CoreData 处理框架

    • Breeze - 用Swift写的一个轻量级的CoreData管理工具,并且还支持iCloud 。
    • AlecrimCoreData - Swift,更容易地访问 CoreData 对象封装类库。除了 CRUD,还提供指针定位,强大的排序、筛选,异步数据获取,以及独立线程后台存取数据。
    • Graph.swift - 设计新颖、使用简单基于 Core Data 的数据驱动框架库 (作者Daniel Dahan)
    • Swift 简便的 CoreData 查询类库 QueryKit: QueryKit,一种简便的类型安全的CoreData查询语言。支持Swift和Objective-C两种语言。
    • CoreValue: CoreValue是Core Data的轻量级封装框架。它也包含了一些简单的抽象,便于查询,更新,保存和删除。
    • SwiftRecord: 基于 Core Data 极为轻量、易用的对象持久化工具库。
    • AlecrimCoreData: AlecrimCoreData 是强大而简单的 Core Data 封装框架,使用 Swift 编写,灵感来自于MagicalRecord 和 LINQ。它提供了多种功能来获取、创建、更新以及保存实体,如果需要还可以在后台线程中获取和保存实体对象。未来将会为SQLite储存类型添加iCloud支持,添加聚合和迁移方法,添加文档源码,创建单元测试以及创建示例工程等。

    3.4 缓存处理

    • Cache.swift - 一款简单、易用的缓存库。支持 MemoryCache, DiskCache 以及前两项组合的 MultiCache。

    4. 图形处理

    4.1 图片处理

    • GPUImage2.swift - Swift 版基于 GPU 图像和视频处理框架库。
    • ShinpuruImage - Syntactic Sugar for Accelerate/vImage and Core Image Filters ?
    • core-image-explorer - Core Image 滤镜处理图片– swift ,Core Image 介绍
    • AAFaceDetection - AAFaceDetection–swift,简单、实用的面部识别封装库。虽然该技术从 iOS 5 发展,不过真正有趣的应用还不多。
    • Concorde - swift, Concorde, 一个可用于下载和解码渐进式 JPEG 的库, 可用来改善应用的用户体验。
    • ZoomTransition - swift, 通过手势操控图片的放大、缩小、旋转等自由变化效果的组件及示例。
    • AFImageHelper - swift,一套针对 UIImage 和 UIImageView 的实用扩展库,功能包含填色和渐变、裁剪、缩放以及具有缓存机制的在线图片获取。
    • PinterestSwift - swift,Pinterest 风格图片缩放、切换示例。
    • PhotoStackView-Swift - PhotoStackView——照片叠放视图,使用说明
    • MPParallaxView - 是用 Swift 写的类似 Apple TV Parallax 效果的视图。
    • SDECollectionViewAlbumTransition - 用自定义的 push 和 pop 实现了有趣的 iOS 相册翻开动画效果。
    • SKPhotoBrowser.swift - swift中规中矩、实用的图片浏览类库。示例也很完整。
    • Nuke.swift - 完整、强大、实用的图片管理类库。主要功能包括可定制装载,缓存,滤镜及尺寸变换。
    • PagingView.swift - 注重细节的自动布局分页视图组件。
    • SwViewCapture.swift - SwViewCapture.swift一个用起来还不错的iOS截图库.(支持截取所有内容, 适用于所有ScrollView组成的视图, 包括WebView)。
    • Filterpedia.swift - 强大的图片滤镜库演示。
    • preview-transition.swift - 通过向导式代码实现步骤,实现完整、自然流畅的图片预览及转场功能。
    • CartoonEyes.swift - 前置摄像头捕获图像后,采用 Core Image 脸部识别 CIDetector 和漫画效果滤镜复合出卡通效果眼睛。

    4.2 压缩

    4.3 svg图片处理

    4.4 统计图等绘制

    4.5 gif图片处理

    • gifu:高性能GIF显示类库

    4.6 网络图片处理

    • HanekeSwift:轻量带缓存高性能图片加载组件
    • Toucan:小而美的图片变换及处理类
    • DominantColor:提取图片主色示例项目
    • ImageScout:最小网络代价获得图片大小及类型

    5. 动画

    5.1 简单动画

    6. UI控件

    6.1 自动布局

    6.2 UI 适配

    6.3 UI 组件

    6.3.1 UILabel自定义

    6.3.2 UIButton自定义

    6.3.3 UISwitch自定义

    6.3.4 UIScroll自定义

    6.3.5 tabbar自定义

    6.3.6 UIProgress 进度条

    6.3.7 UIAlert 自定义

    6.3.8 图表绘制

    6.3.9 下拉刷新

    6.3.10 模糊效果

    6.3.11 自动布局

    6.3.12 富文本

    6.4 UI 地图类

    7. 框架类

    7.1 响应式框架

    • RxSwift - RxSwift:函数响应式编程框架。
    • RxPermission.swift - 通过绑定 RxSwift 实现的 RxPermission。
    • Permission.swift - 统一的 API 请求 iOS 本地设备及资源权限类库。
    • ReactiveAnimation - ReactiveCocoa 推出了一个叫 ReactiveAnimation 的子项目,直接用完全用 Swift 来实现了。

    8. 音视频处理

    8.1 音频处理

    • AudioKit: 音频合成、加工及分析平台(支持 iOS、OS X、tvOS)框架库。无论其易用性,还是功能性及专业性。

    8.2 视频处理

    8.2.1 摄像照相视频音频处理

    • CameraManager - 相机管理封装类库。看着极好用的样子—-swift。
    • recordDemo.swift - 一个Swift语言实现直接可以用的录音Demo
    • Swift-Radio-Pro - 集成 LastFM 的专业电台应用(基于 Swift 2.0)。
    • mobileplayer-ios.swift - 很不错的高度可定制播放器项目
    • Periscope-VideoViewController.swift - 简洁实用的视频快进、倒带控制视图类库。
    • SkfSwiftCammer - 一个相机demo,在oc里面调用了swift。
    • BMPlayer.swift - 基于 AVPlayer 使用 Swift 封装的视频播放器,方便快速集成,支持横屏、竖屏,上下滑动调节音量、屏幕亮度,左右滑动调节播放进度。

    9. 工具类

    9.1 “轮子”工具类

    • SwiftyJSON:GitHub上最为开发者认可的JSON解析类
    • Dollar.swift:Swift版Lo-Dash(或underscore)函数式工具库
    • OAuthSwift:国外主流网站OAuth授权类库
    • PathKit:小而美的路径管理类
    • XCGLogger:功能完整的日志管理类库
    • Surge:基于苹果Accelerate高性能计算框架封装库
    • Async:简洁的后台执行代码封装库
    • Euler:直观、简洁的数学表达式∛27÷3+∑[3,1,2]
    • LocationManager:地理位置管理封装库
    • Siren:当应用更新时,通知用户并提供App Store链接
    • BrightFutures:漫长或复杂计算由独立线程异步来完成
    • Design-Patterns:如何使用常用设计模式及示例

    9.2 框架类

    • AsyncDisplayKit:提供界面的高流畅性切换及更灵敏的响应
    • Cartography:基于代码级的自动布局封装框架
    • MMWormhole:iOS扩展与宿主应用的通讯框架
    • NetworkObjects:轻量版HttpServer框架,跨平台解决方案
    • ExSwift:包含一组标准类型和类的Swift扩展。
    • SwiftTask:SwiftTask是用Swift编写的状态机,综合了Promise+ progress + pause + cancel,使用SwiftState( Swift 编写的优雅的状态机)。
    • HanekeSwift:Haneke 是一个用 Swift 编写的轻量级iOS通用缓存,易于使用。

    9.3 PDF处理

    9.4 调式,测试

    • Sleipnir:Sleipnir是一个适用于Swift的BDD(Behavior Driven Development)风格框架,灵感来自于Cedar(一款BDD风格的Objective-C测试框架)。核心原则:Sleipnir不依赖NSObject,是纯Swift BDD测试框架;Sleipnir不使用XCTest;有着很好的命令行输出,支持自定义测试报告,等等。
    • Quick: Quick是一个适用于Swift和Objective-C的行为驱动开发测试框架。借鉴了RSpec,Specta以及Ginkgo

    9.5 函数响应式框架

    • Dollar.swift:Dollar是一个Swift库,提供了有用的函数式编程辅助方法,无需扩展任何内置对象。Dollar类似于Lo-Dash或者Javascript中的Underscore。

    10. 第三方框架,库

    11. MVVM框架项目

    11.1 RxSwift + Moya + MVVM + Realm项目

    swift文档资料类

    swift学习资料

    1. 苹果官方Swift文档《The Swift Programming Language》
    2. 苹果开发者Swift文档及介绍
    3. 网友整理的Swift中文文档《 Apple Swift编程语言入门教程中文版Apple官方Swift教程(Github协作翻译中)
    4. Apple Swift编程语言入门教程
    5. Swift语言概览中文版
    6. Swift英文文档markdown版
    7. Swift开发视频教程【入门篇】
    8. letsswift 编译的Swift中文教程
    9. Github上的Swift开源项目列表
    10. 国内第一个Swift社区
    11. SwiftGuide 很赞 的Swift学习资料
    展开全文
  • WWDC2015已经过去一段时间了,我发现自从更新了Swift2.0到现在的Swift2.2,我只是跟着版本更新了所有需要更新的语法,依旧自以为是很熟练的Swift程序员。刚入职比较闲碰巧看到了1月份的中国首届Swift大会上大牛们的...

    本人原创,长文慎入,但此文可能会改写你的编程风格。我认为数据和模型交互的关键问题是如何处理数据源和视图源本身的异构性。通过面向协议编程的不断实践,总结他人的理论经验,我发现了使用两个极简的通用协议可以完美破解异构的问题,也就是本文想要介绍的MV架构。在最初版的版本中我想把这个架构命名为MVP(Model-View-Protocol),因为本文浏览的人比较多,这个命名容易和现有的MVP(Model-View-Presenter)造成混淆,但其实二者有着天壤之别,由于在本架构中Protocol部分的语法非常简短精炼,数据的处理分发给了Model和View本身,所以我觉得P可以去掉了,这个架构就叫MV,如幽灵般鬼魅。下面是原文内容:
    WWDC2015已经过去一段时间了,我发现自从更新了Swift2.0到现在的Swift2.2,我只是跟着版本更新了所有需要更新的语法,依旧自以为是很熟练的Swift程序员。刚入职比较闲碰巧看到了1月份的中国首届Swift大会上大牛们的分享,突然陷入了思考,有了很多新想法又重温了几遍WWDC2015大会的视频,尤其是408和414号视频!!!我下定决心重构自己的代码,下面步入正题,结合Swift开发大会的一些分享,让我们谈谈架构。
    通过一个简单的Demo:一个事件提醒的小应用。
    这个应用会使用一个TableView混合展示一个时间段的所有待办事宜和这个时间段的节日提醒,由于待办事件和节日的数据构成是不同的,所以需要创建两个模型,它们在TableView上展示的样式也应该有所不同,很常规的我们还需要一个TableViewCell的子类。
    现在数据工程里面的目录是这样的:
    这里写图片描述

    模型代码:

    struct Event {
        var date = ""
        var eventTitle = ""
        init(date:String,title:String){
            self.date = date
            self.eventTitle = title
        }
    }
    
    struct Festival {
        var date = ""
        var festivalName = ""
        init(date:String,name:String){
            self.date = date
            self.festivalName = name
        }
    }

    为了简单我都使用了String类型的数据,至于为什么要使用struct而不使用class,大家可以参考WWDC2015的414号视频,讲的非常清楚,我自己的项目中的数据模型已经全部转成struct了,我会在后面专门写博文讲解struct,这里就不赘述了。这里需要啰嗦一下,注意创建的时候使用的是字面量的方法,而不是可选型,我一直认为使用字面量的方法是更好的选择,可选型很容易被当做语法糖滥用。尤其是数据的初始化中,你确定你真的需要一个空值?拿一个空值能做什么?做某种标志位么?请和你的后台开发人员商议,让他给你一个Bool类型的标志位,而不是一个空值。在可能的情况下,给你的数据模型的属性赋一个语义明确的字面量初始值,比如这里我们使用空字符串作为初始值。如果你的数据只是做展示的不会存在修改情况,你也可以使用如下的方法做初始化,以达到效率的最大化:

    struct Event {
        let date:String
        let eventTitle:String
        init(date:String = "",eventTitle:String = ""){
            self.date = date
            self.eventTitle = eventTitle
        }
    }

    在Swift1.2版本之后,let定义的数据也支持延迟加载了,这里使用了默认参数值做非空的保障。
    模型否则在创建一个实例的时候各种可选型的解包或可选绑定会让你吃尽苦头,空值的访问是程序carsh的元凶!
    如果如果你更新了Xcode7.3,你会发现在创建一个属性的时候Xcode的提示是“ =“,没错,Xcode推荐你用字面量去做初始化。
    有了数据模型后,在Cell上创建两个Label

    class ShowedTableViewCell: UITableViewCell {
        //用来展示事件主题或节日名称的Label
        @IBOutlet weak var MixLabel: UILabel!
        //用来展示日期的Label
        @IBOutlet weak var dateLabel: UILabel!
    
    
    }

    MVC架构:
    从这里我们将展示传统的MVC的写法,但是包含了一些关键的知识点,所以还是建议您不要跳过。我们通过控制器中的代码去控制数据的展示,由于数据源包含两种数据类型,可以构造两个数组避免数组的异构:

        var eventList = [Event]()
        var festivalList = [Festival]()
        let loadedEventList = [Event(date: "2月14", eventTitle: "送礼物")]
        let loadedFestivalList = [Festival(date: "1月1日", festivalName: "元旦"),Festival(date: "2月14", festivalName: "情人节")]

    这里使用了struct的默认构造器构造对象,有两个节日提醒:元旦节和情人节,元旦节没什么事情做,情人节那天有个事件提醒”送礼物“,我们使用GCD去模拟数据刷新,整个控制器的代码如下:

    import UIKit
    
    let cellReusedID = "ShowedTableViewCell"
    class ShowedTableViewController: UITableViewController {
    
        var eventList = [Event]()
        var festivalList = [Festival]()
        let loadedEventList = [Event(date: "2月14", eventTitle: "送礼物")]
        let loadedFestivalList = [Festival(date: "1月1日", festivalName: "元旦"),Festival(date: "2月14", festivalName: "情人节")]
        override func viewDidLoad() {
            super.viewDidLoad()
            let delayInSeconds = 2.0
            let popTime = dispatch_time(DISPATCH_TIME_NOW,
                Int64(delayInSeconds * Double(NSEC_PER_SEC)))
            dispatch_after(popTime, dispatch_get_main_queue()) { () -> Void in
                self.eventList = self.loadedEventList
                self.festivalList = self.loadedFestivalList
                self.tableView.reloadData()
            }
        }
    
    
    
        // MARK: - Table view data source
    
        override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
            // #warning Incomplete implementation, return the number of sections
            return 1
        }
    
        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            // #warning Incomplete implementation, return the number of rows
            return eventList.count + festivalList.count
        }
    
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCellWithIdentifier(cellReusedID, forIndexPath: indexPath) as! ShowedTableViewCell
            //传统的MVC,你需要在这里处理数据本身的同构与异构情况,还得处理数据与视图的逻辑关系
            //这里我们把事件提醒放在节日的前面展示
            if indexPath.row > eventList.count - 1{
                cell.MixLabel.text = festivalList[indexPath.row - eventList.count].festivalName
                cell.dateLabel.text = festivalList[indexPath.row - eventList.count].date
                cell.backgroundColor = UIColor.whiteColor()
                return cell
            } else {
                cell.MixLabel.text = eventList[indexPath.row].eventTitle
                cell.dateLabel.text = eventList[indexPath.row].date
                cell.backgroundColor = UIColor.redColor()
                return cell
            }
        }
    
    
    }

    运行一下看看:
    这里写图片描述

    似乎还不错,我们把两个不同的数据结构展现在一张页面上了,并且复用了cell,但是设置cell的代理方法中的代码似乎有点多,而且如果我需要按照时间去排序,那么两个同构的数组作为数据源不好排序,那么重构首先从把同构变成异构开始。由于struct没有继承,按照Swift2.0的精神,此时我们需要提炼两个数据模型的共性,方法是利用protocol,观察到Event和Festival都有date属性,所以写一个协议:

    protocol HasDate{
        var date:String {get}
    }

    这里这个协议只有一个属性date,Swift协议中定义的属性只有声明,遵守协议的对象必须实现这个属性,但是不限于存储属性还是计算属性。协议中定义的属性必须指定最低的访问级别,这里的date必须是可读的,至于可写的权限取决于实现该协议的数据类型中的定义。由于我们的Event和Festival都具有了date属性,直接让二者遵守HasDate协议,不要用扩展的方式让二者遵守协议,编译器报错的,很怪0 0.
    修改并化简控制器中的数据源,使用异构数据源,现在控制器的代码如下:

    import UIKit
    
    let cellReusedID = "ShowedTableViewCell"
    class ShowedTableViewController: UITableViewController {
    
        var dataList = [HasDate]()
        var loadeddataList:[HasDate] = [Event(date: "2月14", eventTitle: "送礼物"),Festival(date: "1月1日", festivalName: "元旦"),Festival(date: "2月14", festivalName: "情人节")]
        override func viewDidLoad() {
            super.viewDidLoad()
            let delayInSeconds = 2.0
            let popTime = dispatch_time(DISPATCH_TIME_NOW,
                Int64(delayInSeconds * Double(NSEC_PER_SEC)))
            dispatch_after(popTime, dispatch_get_main_queue()) { () -> Void in
                //注意这里,我故意把loadeddataList中的数据打乱了,为了实现异构数据的按照某个公共类型的属性的排序,使用了Swift内置的sort函数,String遵守了Compareable协议,这里为了简单吧date指定为String类型,如果是NSDate,你可以在sort的闭包中指定合适的排序规则。
                self.dataList = self.loadeddataList.sort{$0.date < $1.date}
                self.tableView.reloadData()
            }
        }
    
    
    
        // MARK: - Table view data source
    
        override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
            return 1
        }
    
        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return dataList.count
        }
    
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCellWithIdentifier(cellReusedID, forIndexPath: indexPath) as! ShowedTableViewCell
            //注意这里,通过可选绑定进行异构数据的类型控制
            if let event = dataList[indexPath.row] as? Event{
                cell.MixLabel.text = event.eventTitle
                cell.dateLabel.text = event.date
                cell.backgroundColor = UIColor.redColor()
                return cell
            } else if let festival = dataList[indexPath.row] as? Festival{
                cell.MixLabel.text = festival.festivalName
                cell.dateLabel.text = festival.date
                cell.backgroundColor = UIColor.whiteColor()
                return cell
            } else {
                return cell
            }
        }
    }

    运行一下:
    这里写图片描述
    没有任何问题。对异构数组的类型判断的写法来自于WWDC2015上的408号视频,现在控制器里的代码已经精简了很多了,我们解决了异构的问题,对于MVC来说,这似乎已经精简到极限了。这是一个简单的Demo,在真正的工程中一个控制器当中的代码可能有几百上千行,或者有多个TableView,这个时候MVC的弊端就显现了,在几百行代码中可能有一百行都用来做数据与视图的绑定,而数据模型和视图本身的代码定义中却只有寥寥数十行,控制器的负担太重了!因此有人提出了将控制器中有关模型与视图的逻辑的代码提出到一个单独的区域进行处理,这就是MVVM架构的由来。
    MVVM架构
    对MVVM架构的解读我想引用Swift开发者大会上李信洁前辈的示例写法,通过POP来实现一个MVVM,并且对其写法进行了一些精简。我们先不修改View和Modal的代码,因为需要更新的是一个cell,所以首先需要写一个传递Modal中数据的协议:

    protocol CellPresentable{
        var mixLabelData:String {get set}
        var dateLabelData:String {get set}
        var color: UIColor {get set}
        func updateCell(cell:ShowedTableViewCell)
    }

    这个协议的思想是显示地声明一个更新cell的方法,并根据cell需要的数据声明两个属性,我们并不关心mixLabel和dateLabel的数据从哪里来,叫什么名字,但他们的功能是确定的,Swift2.0之后可以扩展协议,下面通过协议扩展给这个协议增加默认的实现,这样在绑定数据时可以减少代码量:

    extension CellPresentable{
        func updateCell(cell:ShowedTableViewCell){
            cell.MixLabel.text = mixLabelData
            cell.dateLabel.text = dateLabelData
            cell.backgroundColor = color
        }
    }

    好了,我们写好了,下一步我们要修改cell的代码,增加一个方法接受一个CellPresentable:

    class ShowedTableViewCell: UITableViewCell {
        //用来展示事件主题或节日名称的Label
        @IBOutlet weak var MixLabel: UILabel!
        //用来展示日期的Label
        @IBOutlet weak var dateLabel: UILabel!
    
        func updateWithPresenter(presenter: CellPresentable) {
            presenter.updateCell(self)
        }
    }

    这里也做了一些改进,李信洁前辈的示例中是针对每一个控件去定义方法的,其实对一个View的所有IBOutlet做更新不就是更新它自己么,所以这里我的写法是直接传入self。然后(我也不想多说然后,但是步骤就是这么多)为了绑定异构的Model和View你还需要定义一个ViewModel,并且通过定义不同的init实现数据绑定:

    struct ViewModel:CellPresentable{
        var dateLabelData = ""
        var mixLabelData = ""
        var color = UIColor.whiteColor()
        init(modal:Event){
            self.dateLabelData = modal.date
            self.mixLabelData = modal.eventTitle
            self.color = UIColor.redColor()
        }
        init(modal:Festival){
            self.dateLabelData = modal.date
            self.mixLabelData = modal.festivalName
            self.color = UIColor.whiteColor()
        }
    }

    最后我们终于可以去修改我们的控制器了,控制器中需要更改的是与cell有关的datasource方法:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCellWithIdentifier(cellReusedID, forIndexPath: indexPath) as! ShowedTableViewCell
            if let event = dataList[indexPath.row] as? Event{
                let viewModel = ViewModel(modal: event)
                cell.updateWithPresenter(viewModel)
                return cell
            } else if let festival = dataList[indexPath.row] as? Festival{
                let viewModel = ViewModel(modal: festival)
                cell.updateWithPresenter(viewModel)
                return cell
            } else {
                return cell
    
            }
        }
    }

    这段代码写的我满头大汗,编译运行,幸运的是运行的结果是正确的:
    这里写图片描述

    我在想MVVM模式的意义是什么?我在使用MVVM之前甚至需要考虑一下值不值得花时间去写成MVVM的模样,因为MVVM需要给所有的view提供协议,并且将所有的数据模型的绑定过程写进一个新的数据结构ViewModal中,但其实这个ViewModel的价值非常之小,除了数据绑定,没有其他作用了,里面甚至只有空洞的init构造器,我想我已经决定放弃这个思路了。
    MV的萌芽阶段
    我继续着自己的思考,大会上傅若愚前辈分享的示例给了我很大的启发,因为他提供了一个没有中间层的模型!我一直在思考这个模型,并且在入职的第一个项目中一直在按照他的模型来组织自己的代码,直到我顿悟了自己的MV模型。下面简单介绍一下傅若愚前辈的思路,这个思路的优势在于所有的数据和模型绑定都只需要两个通用的协议:

    //视图使用的协议
    protocol RenderContext{
        func renderText(texts:String...)
        func renderImage(images:UIImage...)
    }
    //数据使用的协议
    protocol ViewModelType{
        func renderInContext(context:RenderContext)
    }

    上面是大会上傅若愚前辈的原版,在介绍这个协议的用法之前,我觉得应该先做一点点改进,ViewModalType应该改成:

    protocol ViewModelType{
        func renderInContext<R:RenderContext>(context:R)
    }

    这两个版本都可以通过编译,差别在运行的效率上,下面我在playground中展示一个示例,这个示例来源于《Advanced Swift》这本书,其实苹果的WWDC2015 408号视频中也明确表述了不要把协议当做参数类型,而写成泛型的约束,但是没有详细讲解为什么,下面是示例:

    func takesProtocol(x: CustomStringConvertible) { //
        print ( sizeofValue(x))
    }
    func takesPlaceholder<T: CustomStringConvertible>(x: T) {
        print ( sizeofValue(x))
    }

    两个方法,前者使用协议作为参数的类型,后者使用协议作为泛型的约束条件,两个方法都会打印参数的长度,调用一下试试:

    takesProtocol(1 as Int16)
    takesPlaceholder(1 as Int16)

    打印结果:
    这里写图片描述
    换成类再打印一次:
    这里写图片描述
    没错,由于协议本身既可以被类遵守、也可以被结构体、枚举遵守,也就是说既可以被引用类型遵守也可以被值类型遵守,把协议当做参数类型,实际上会创造一个Box类型,里面会为引用类型遵守者预留地址也会为值类型遵守者预留地址,甚至需要存储一个指针长度找到协议的真正继承类型。而Swift2.0之后编译器得到了加强,具有了泛型特化的功能,对代码中的泛型在编译时就会确定其真正的类型,不耗费任何性能。
    下面我们用改造后的傅若愚前辈的协议来改造Demo,你需要让你的数据模型去遵守RenderContext,然后根据模型的参数类型将每一个参数存入对应类型方法的参数列表中,这些方法都是可变参数,不限制数量,但是参数的类型是确定的。这种使用参数类型做通用类型的写法消灭了中间的ViewModel层,把Model和View直接对接了。由于Swift要求每一个协议的遵守者都必须实现协议的全部方法,而有些方法的数据模型并没有,所以你在使用之前需要使用协议扩展为这些方法实现一个空的实现:

    protocol RenderContext{
        func renderText(texts:String...)
        func renderImage(images:UIImage...)
    }
    
    extension RenderContext{
        func renderText(texts:String...){
    
        }
        func renderImage(images:UIImage...){
    
        }
    }

    现在你的模型应该是下面这样:

    struct Event:HasDate,ViewModelType{
        var date = ""
        var eventTitle = ""
        func renderInContext<R : RenderContext>(context: R) {
            context.renderText(date,eventTitle)
        }
    }
    
    struct Festival:HasDate,ViewModelType{
        var date = ""
        var festivalName = ""
        func renderInContext<R : RenderContext>(context: R) {
            context.renderText(date,festivalName)
        }
    }

    视图的代码应该是这样的:

    class ShowedTableViewCell: UITableViewCell,RenderContext {
        //用来展示事件主题或节日名称的Label
        @IBOutlet weak var MixLabel: UILabel!
        //用来展示日期的Label
        @IBOutlet weak var dateLabel: UILabel!
    
        func renderText(texts: String...) {
            dateLabel.text = texts[0]
            MixLabel.text = texts[1]
        }
    }

    由于遵守了多个协议,所以控制器中原本的异构类型不合适了,此时可以给多个协议类型写一个别名方便使用,记得顺便更新一下你的Model,提高可读性:

    typealias DateViewModel = protocol<HasDate,ViewModelType>

    现在控制器中的数据源可以使用新的异构类型了:

    var dataList = [DateViewModel]()
        var loadeddataList:[DateViewModel] = [Event(date: "2月14", eventTitle: "送礼物"),Festival(date: "1月1日", festivalName: "元旦"),Festival(date: "2月14", festivalName: "情人节")]

    然后更新cell的代理方法:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCellWithIdentifier(cellReusedID, forIndexPath: indexPath) as! ShowedTableViewCell
            dataList[indexPath.row].renderInContext(cell)
            return cell
        }

    不错,代码简洁了很多,运行一下:
    这里写图片描述
    等等,我们似乎遗漏了一些东西,cell的背景颜色呢?好吧让我们加上,可是我该去哪里加呢?去控制器中吗?不不坚决不能碰控制器,那么只能去cell中了,现在问题出现了,当两个模型共享一个视图的时候,我该如何判断数据源从哪里来?renderText(texts: String…)这样的写法已经完全失去了异构的特性,那么试着这样写,在数据传递参数的时候多传一个String好了,反正参数是我们的自由:

    struct Event:DateViewModel{
        var date = ""
        var eventTitle = ""
        func renderInContext<R : RenderContext>(context: R) {
            context.renderText(date,eventTitle,"red")
        }
    }

    这样在检验的时候就看最后一个参数就好了:

    class ShowedTableViewCell: UITableViewCell,RenderContext {
        //用来展示事件主题或节日名称的Label
        @IBOutlet weak var MixLabel: UILabel!
        //用来展示日期的Label
        @IBOutlet weak var dateLabel: UILabel!
    
        func renderText(texts: String...) {
            dateLabel.text = texts[0]
            MixLabel.text = texts[1]
            if texts[2] == "red"{
                backgroundColor = UIColor.redColor()
            }
        }
    }

    这里有个语法糖,可变参数的方法,在取参时不会发生越界,因为Festival的renderText方法只传了两个值,运行结果又正常了。那么如果我粗心把参数写错顺序了呢?结果成了这样:
    这里写图片描述
    如果我的Festival中多了一个Int类型,而Event中恰巧没有呢?按照值去区分参数不是一个好主意,因为你用下标从一个数组中取值的时候除了它的类型不能得到任何信息,甚至都不知道这个值存不存在!我再次陷入了思考,既然View需要的是Model中的属性,这不就等于需要Model自己么,那么为什么我们不能直接传递Modal自己呢?
    MV!
    所以我再次改造了傅若愚前辈的协议,顺便把名字改的好辨认一点,原来的名字太容易出错了- -现在它是这样子的:

    //视图使用的协议
    protocol ViewType{
        func getData<M:ModelType>(model:M)
    }
    //数据使用的协议
    protocol ModelType{
        func giveData<V:ViewType>(view:V)
    }

    不需要在扩展中写默认实现,因为传值是相互且确定的,所以方法一定会被实现。
    模型是这样子的:

    typealias DateViewModel = protocol<HasDate,ModelType>
    struct Festival:DateViewModel{
        var date = ""
        var festivalName = ""
        func giveData<V : ViewType>(view: V) {
            view.getData(self)
        }
    }
    
    struct Event:DateViewModel{
        var date = ""
        var eventTitle = ""
        func giveData<V : ViewType>(view: V) {
            view.getData(self)
        }
    }

    视图:

    class ShowedTableViewCell: UITableViewCell,ViewType {
        //用来展示事件主题或节日名称的Label
        @IBOutlet weak var MixLabel: UILabel!
        //用来展示日期的Label
        @IBOutlet weak var dateLabel: UILabel!
    
        func getData<M : ModelType>(model: M) {
            //这里不能写成guard let dateModel = model as? DateViewModel else{}令我有些意外
            guard let dateModel = model as? HasDate else{
                //不满足Cell基本需求的Model直接淘汰掉
                return
            }
            //处理相同属性
            dateLabel.text = dateModel.date
            //处理数据源异构
            if let event = dateModel as? Event{
                MixLabel.text = event.eventTitle
                backgroundColor = UIColor.redColor()
            } else if let festival = dateModel as? Festival{
                MixLabel.text = festival.festivalName
                backgroundColor = UIColor.whiteColor()
            }
        }
    }

    再次用苹果官方给出的异构判断方法解决异构,协议不同于类,没有那么多继承上的检查,所以使用as?是很高效的,最后只要给控制器中的代码换个名字就够了:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCellWithIdentifier(cellReusedID, forIndexPath: indexPath) as! ShowedTableViewCell
            dataList[indexPath.row].giveData(cell)
            return cell
        }

    完成,运行效果:
    这里写图片描述
    你会发现即便你删掉你的控制器代码,View和Model中的逻辑也不会发生改变,而在控制器中进行数据绑定的时候,因为使用了协议来实现数据源的异构,你甚至不需要对数据源做筛选,只要它们是使用相同的cell来做展示。
    等等,还没完!即便这个架构已经非常精简了,但是你也许发现了在Model中我们写了很多重复的代码,也就是giveData的实现部分,这个实现是完全相同的,而且我们不希望这个方法被复习,所以,最后的优化,把giveData的定义和实现放在ModelType的协议扩展中:

    //视图使用的协议
    protocol ViewType{
        func getData<M:ModelType>(model:M)
    }
    //数据使用的协议
    protocol ModelType{
    }
    //ModelType的默认实现
    extension ModelType{
        func giveData<V:ViewType>(view:V){
            view.getData(self)
        }
    }

    现在你可以删掉Event和Festival中的giveData的实现了,Model、View、Controller和Protocol的代码都变得极其简单,依靠Swift强大的语言特性,让数据的传递与异构的处理似乎看不见摸不着,却又真实地发生了,幽灵般鬼魅。寥寥数行代码解决了MVC和MVVM争论多年的问题,运行一下,享受幽灵架构MV吧!
    在项目的最初阶段,开发人员拿到的是原型和设计图,即便我们不清楚该如何开始编写复杂的处理逻辑,但是数据的状态与视图的样式的对应关系是大致确定的,因此可以直接使用MV架构绑定数据源和视图的逻辑,即便后台开发者提供的最终接口里有数据的改变,那么在我们修改对应的Model的时候,View中的代码也会以报错的形式提示你修改,开发的效率会得到一个显著的提升!
    代码打包了一份,放这里了:http://pan.baidu.com/s/1qYTAs3M
    有需要的自取
    写在后面:
    博主欠了欠身子,从吃完晚饭写到了半夜,一口气完成了本文,如果你喜欢我的文章并且得到了启发,欢迎转载传阅,注明出处即可。在Swift1.X时代我觉得Swift脆弱的像只小猫,Swift2.0之后我才突然发现苹果缔造的是一只野兽。苹果很聪明,在推进Swift替代OC的道路上采取了温柔的手段:仅仅是让Swift变得更优秀。通过不断锻炼自己面向协议编程的能力,我有了很多新的体会,想起了迪杰斯特拉老爷子著名的goto有害论,请准许我大胆预言一下,在面向协议的世界中AnyObject也是有害的,点到为止。

    关于博主本人:
    《Swift开发手册:技巧与实战》作者。国内计算机领域的某名校毕业,学习不差,初入社会,曾只身离校北漂妄图以退学抗议畸形的研究生教育,后心疼父母返校完成学业。从2014年底开始接触Swift后一发不可收拾,至今保持狂热,小人物大梦想,孜孜不倦致力于改善iOS编程体验。欢迎大家留言交流,力所能及之处,必倾囊相授。

    展开全文
  • 背景: 现在越来越多的公司会尝试用 Swift 做 native 的开发了,很多之前习惯用 Objective-C 的开发,有新项目启动的时候,也会想说用 Swift 试试。如果从 2020年编程语言排行榜 上看的话,Swift的热度也...
  • Swift 写一个简单界面

    2016-08-15 15:29:26
    在这篇博文中你可以看到那些内容呢, 首先这是一个用tableView纯代码Swift写的简单界面, 你可以看到下面这些 - 使用Alamofire 进行网络请求 - 使用MJExtension 进行字典转模型 - 使用HanekeSwift 进行图片的赋值 ...
  • view B tableview中的cell...view A pop回来的时候,我想reload view B中的tableview 在B视图 -(void)viewDidAppear:(BOOL)animated{} 这个方法里面重新[self.tableview reloadData]; 要注意 刷新数据 不然没有效果
  • 1.针对某些场景下关于使用iOS UINavigation pop 时界面卡顿问题的解决?有时会遇到UINavigationController popViewController的时候,会发现pop没有反应,等了大概6~8秒才有pop的效果,1.分析原因自己是在一个回调里...
  • Swift学习资料@SwiftGuide很赞 的Swift学习资料leetcode一个练习、评估自己水平的代码平台,跟ACM有点类似完整App@Swift 30 Projects- 最新 Swift 3.0 的30个小App,更注重代码规范和架构设计(故胤道长)V2ex-Swift- ...
  • Swift 开源项目精选

    2016-03-24 23:20:57
    基于《Swift 语言指南》开源项目收录,做了一个甄别和筛选,并辅以一句话介绍。 @SwiftLanguage 更新至 2016-3-31,最近新收录 Duration, Bolts-Swift, Fusuma, sweetcorn, Kingsroad, react-native-ios-...
  • Swift常用第三方库

    2019-02-16 14:50:16
    网络 ... Moya:这是一个基于Alamofire的更高层网络请求封装抽象层。 Reachability.swift:用来检查应用当前的网络连接状况。 ...Perfect:swift的服务器端开发...函数响应式编程框架,是ReactiveX的swift版本,可以简化...
  • GitHub第三方资源库整理(Swift篇) Jisen 关注2016.05.30 18:04* 字数 2226 阅读 8734评论 4喜欢 103之前做了OC的整理,这一篇是Swift的第三方资源库整理。同样的,有好的项目我就会加进来,并把更新说明写在文末...
  • 更新:所有代码已经更新到Swift4.1,请移步github下载 ======================================================= iOS开发已经做了快4年了,听说Swift也已经有两年多,但是一直都只是把学习停留在表面。无意中听说了...
  • swift 框架大全

    2017-06-26 11:27:09
    版本:Swift github排名 https://github.com/trending,github搜索:https://github.com/search 主要工作说明:  1. 将Swift从Objective-C混合的md文件中抽出(正在进行…) 使用方法:根据目录关键字...
  • swift 学习资料大全

    2017-07-15 18:22:50
    版本:Swift github排名 https://github.com/trending,github搜索:https://github.com/search 主要工作说明:  1. 将Swift从Objective-C混合的md文件中抽出(正在进行…) 使用方法:根据目录关键字...
  • 关于下拉刷新和上拉加载,项目中一直使用MJRefresh(原先还用过EGOTableViewPullRefresh,MJRefresh更好用些),今天就分析下如何用Swift来实现这个功能。 关于如何下拉刷新和上拉加载,认识到两点就可以了: 0....
1 2 3 4 5 ... 20
收藏数 904
精华内容 361
关键字:

pop如何刷新 swift