iOS-用作记忆

150 阅读6分钟

该文章仅作为个人对iOS开发的加深记忆。

开发语言 OC or Swift

OC

OC是一门动态语言。OC类的类型和变量的类型都是在运行时确定的。 OC利用Runtime机制,可以在运行期动态的添加变量、方法、类。

Swift

Swift则是一门静态语言。同时Swift也是一种强类型语言。变量一旦被定义了类型,将再也无法改变他的类型。

OC注重灵活。Swift则更加安全。

我个人而言,比较倾向于实用Swift.

因为Swift中有更多的开发技巧,而且可以面向协议编程,面向函数编程(swfit中注重函数式编程),也可以面向对象编程,而且Swift中的Extension特别好用。

当然在Swift也可以选择混合开发,可以同时使用到OC语言的灵活性(Runtime)。

UI

无论OC还是Swift, 使用的全部都是官方的UI,例如UIButton,UIView.当然也可以自定义View样式。

OC

1.新建一个控件的流程。TestOneView

    @implementation TestOneView
    //系统的初始化view方法
    - (instancetype)initWithFrame:(CGRect)frame{
        self = [super initWithFrame:frame];
        //初始化button
        UIButton * testButton = [UIButton buttonWithType:(UIButtonTypeSystem)];
        //设置frame 也就是控件的位置
        testButton.frame = CGRectMake(0, 0, 50, 40);
        //背景颜色
        testButton.backgroundColor = [UIColor redColor];
        //按钮内文字以及状态
        [testButton setTitle:@"点我啊" forState:(UIControlStateNormal)];
        //设置按钮点击事件,以及响应手势的类型.
        [testButton addTarget:self action:@selector(clickButton) forControlEvents:(UIControlEventTouchUpInside)];
        //添加button到self
        [self addSubview:testButton];
        return self;
    }
    //点击事件
    -(void)clickButton{
        NSLog(@"你还真点啊!");
    }
    @end

2.在ViewController中使用这个控件。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    //初始化View
    TestView * testView = [[TestView alloc] initWithFrame:(CGRectMake(100, 100, 100, 100))];
    //设置背景颜色
    [testView setBackgroundColor:[UIColor lightGrayColor]];
    //添加到当前控制器的view上
    [self.view addSubview:testView];
}

Swift

在Swift中 因为语言不同,所以初始化的写法也有所不同。当然只是写法有些不同“而已”,涉及到控制器与子view之间的关系和OC是一样的

1.新建一个控件的流程。TestOneView

class TestOneView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame);
        //初始化对象
        let testButton = UIButton(type: UIButton.ButtonType.system);
        //设置frame
        testButton.frame = CGRectMake(0, 0, 50, 40);
        //设置按钮文字
        testButton.setTitle("快点我", for: UIControl.State.normal);
        //添加点击事件
        testButton.addTarget(self, action: #selector(clickButton), for: UIControl.Event.touchUpInside);
        //把testButton 添加到 self
        self.addSubview(testButton);
    }
    //button点击事件
    @objc func clickButton(){
        print("你还真点啊");
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

2.在ViewController中使用这个控件。

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        //初始化
        let testView = TestView(frame: CGRectMake(100, 100, 100, 100));
        //设置背景颜色
        testView.backgroundColor = UIColor.lightGray;
        //添加到当前控制器的view上
        self.view.addSubview(testView);
    }

布局

在上面的UI中可以看到,是使用的Frame对控件进行定位。这种方式也可以,不过多个UI控件之间需要做相对位置移动时,处理起来就会相当的麻烦。
所以在iOS开发中,大家使用的基本都是AutoLayout布局。各种第三方布局库也是基于AutoLayout进行的二次开发。

OC 以Masonry为例。

上面 TestOneView中的布局 可以修改为这样。具体使用方法可以去github(网上文章也很多)查看文档,这里只是说可以使用这个库做布局。

 [testButton mas_makeConstraints:^(MASConstraintMaker *make) {
            //距离自己父视图左边0
            make.left.equalTo(self).with.offset(0);
            //距离自己父视图顶部0
            make.top.equalTo(self).with.offset(0);
            //宽度50
            make.height.mas_equalTo(50);
            //高度40
            make.width.mas_equalTo(40);
        }];

Swift 以SnapKit为例

上面 TestOneView中的布局 可以修改为这样。该布局库具体使用方法,可以去github(网上文章也很多)查看文档。

  testButton.snp.remakeConstraints { (make) in
        //也可以指定left距离某控件的left or right的距离 make.left.equalTo(iconImageView.snp.right).offset(8)
        make.left.equalTo(0)
        make.top.equalTo(0)
        make.width.equalTo(50)
        make.height.equalTo(40)
  }

页面数据处理

iOS中没有web中的双向数据绑定功能。都是单向的。

非列表的情况

这里OC和Swift区别不大,所以就拿Swift来做例子。

创建 TestTwoView

class TestTwoView: UIView {
    
    var name:String = ""
    var age:Int = 0;
    var heigh:Float = 0;
    var weight:Float = 0;
    lazy var nameLabel: UILabel = {
        let l = UILabel(frame: CGRectMake(10, 10, 100, 20));
        return l
    }()
    
    lazy var ageLabel: UILabel = {
        let l = UILabel(frame: CGRectMake(10, 40, 100, 20));
        
        return l
    }()
    
    
    var heighLabel: UILabel = {
        let l = UILabel(frame: CGRectMake(10, 70, 100, 20));
        
        return l
    }()
    
    
    var weightLabel: UILabel = {
        let l = UILabel(frame: CGRectMake(10, 100, 100, 20));
        
        return l
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame);
        
        self.addSubview(self.nameLabel);
        self.addSubview(self.ageLabel);
        self.addSubview(self.heighLabel);
        self.addSubview(self.weightLabel);
    }
    
    func setData(name: String, age: Int, heigh: Float, weight: Float){
        self.name = name
        nameLabel.text = "姓名: \(name)"
        self.age = age
        ageLabel.text = "年龄: \(age)"
        self.heigh = heigh
        heighLabel.text = "身高: \(heigh)"
        self.weight = weight
        weightLabel.text = "体重: \(weight)"
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

ViewController 中 使用它

    override func viewDidLoad() {
        super.viewDidLoad()
        let testTwoView = TestTwoView(frame: CGRect(x: 50, y: 100, width: 200, height: 150));
        testTwoView.setData(name: "张三", age: 18, heigh: 175.5, weight: 80)
        self.view.addSubview(testTwoView);
    }

这是你如果想更改这个用户体重怎么办? 最简单的方法就是找出展示体重的label,然后:

testTwoView.weightLabel.text = "体重: \(70)"

但是这样用起来不够优雅,而且把内部的控件/逻辑暴露了出来。

还有以下几种选择, 1.在 TestTwoView 内添加一个weightChange方法,专门用来修改体重(在OC中通常使用这种方式)。 2.可以在 TestTwoView 暴露出一个属性,然后通过Swift中的属性观察方法(在Swift中推荐使用这种方式,更加的方便),代码如下。

    var weight:Float = 0{
        didSet{
            weightLabel.text = "体重: \(oldValue)";
        }
    }

View暴露一个weight属性给外界,外界在修改这个weight属性时,会触发didSet,然后你可以在didSet中通过oldValue获取到刚修改的值,然后做一些你想做的事情。这样内部的处理逻辑外界并不用关心。

weight属性使用方法:

testTwoView.weight = 70;

列表中刷新数据

例如: UITableView UICollectionView 他们有一个 reloadData方法来刷新页面。数据源发生变化之后调用即可。

页面导航

iOS中的导航,无论OC还是Swift都是一样的.因为这是UI框架提供的功能.

页面的跳转需要使用到导航控制器UINavigationController,将一个UIViewController设置成他的rootViewController即可。 然后就可以通过这个 rootViewController 跳转到别的 UIViewController

页面的跳转分为push和present两种。

需要注意的是,如果需要底部Tabbar来管理多个页面吧,那么就需要在Tabbar中创建多个导航控制器,具体使用方法,可以通过官方文档查看UITabBarController的使用方法。

页面之间数据/事件传递。

数据传递

  • 从上往下

直接属性赋值或者通过方法调用传值即可。例如:

     let view = TestThreeView(frame: CGRect(x: 50, y: 100, width: 200, height: 150));
        //属性传值
        view.count = 10;
        //方法传值
        view.changCount(10);
        self.view.addSubview(view);
  • 从下往上

使用 block、代理、KVO 都可以。这些不写了 网上可以了查到

子组件的引用方式

OC

需要使用

#import "XXX.h"

Swift

不需要主动引入、直接可以使用

也就是说,你创建的所有Swift对象、类,都是全局的。

如果你要创建一个全局属性。只需要在任意页面,创建一个不属于任何类的变量即可,

而且Swift中单例的创建也很简单:

创建一个全局的属性,然后使用let声明。那么他就是一个单例。

let SCREEN_HEIGHT = UIScreen.main.bounds.height