• Swift3.0之cell的三种创建方式


      该文介绍Swift3.0中分别采用系统、xib、代码自定义三种方式创建UITableViewCell,并与Objective-C创建cell作对比,比较语法的不同之处

      下图是Objective-C编写的创建cell的项目结构:

     

      可以看到在APPDelegate中,我创建了一个继承UITableViewController的控制器,并作为根视图控制器显示

      以下是ViewController实现文件中的代码:

    //
    //  TableViewController.m
    //  20170317-cell系统方法调用顺序
    //
    //  Created by 柯其谱 on 17/3/18.
    //  Copyright © 2017年 柯其谱. All rights reserved.
    //
    
    #import "TableViewController.h"
    #import "SystemTableViewCell.h"
    #import "XibTableViewCell.h"
    #import "CustomTableViewCell.h"
    
    @interface TableViewController ()
    
    @end
    
    @implementation TableViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
    //    //系统创建的cell不用注册
    //    [self.tableView registerClass:[SystemTableViewCell class] forCellReuseIdentifier:SystemTableViewCellID];
        //xib和自定义cell创建的cell必须注册
        [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([XibTableViewCell class]) bundle:nil] forCellReuseIdentifier:XibTableViewCellID];
        [self.tableView registerClass:[CustomTableViewCell class] forCellReuseIdentifier:CustomTableViewCellID];
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    #pragma mark - Table view data source
    
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        return 3;
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return 1;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        if (indexPath.section == 0) {
            SystemTableViewCell *systemCell = [SystemTableViewCell cellWithTableView:tableView indexPath:indexPath];
            return systemCell;
        } else if (indexPath.section == 1) {
            XibTableViewCell *xibCell = [XibTableViewCell cellWithTableView:tableView indexPath:indexPath];
            return xibCell;
        } else {
            CustomTableViewCell *customCell = [CustomTableViewCell cellWithTableView:tableView indexPath:indexPath];
            return customCell;
        }
    }
    
    @end
    

     

      由于代码较为简单,我这里就不作解释,需要注意的是为了控制器的瘦身,我将cell的创建和内容显示全部放在了各自的cell实现文件中,且本文三种cell创建方式显示的cell为同一样式,这里是为了简单起见,到了复杂一点的项目就可将所有的有关cell代码全部写在cell文件中

      以下是SystemTableViewCell,即cell的系统样式的实现代码:

    //
    //  SystemTableViewCell.m
    //  20170317-cell系统方法调用顺序
    //
    //  Created by 柯其谱 on 17/3/17.
    //  Copyright © 2017年 柯其谱. All rights reserved.
    //
    
    #import "SystemTableViewCell.h"
    
    NSString * const SystemTableViewCellID = @"SystemCell";
    
    @implementation SystemTableViewCell
    
    + (instancetype)cellWithTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
        NSLog(@"%s", __func__);
        SystemTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SystemTableViewCellID];
        if (cell == nil) {
            cell = [[SystemTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SystemTableViewCellID];
        }
        cell.imageView.image = [UIImage imageNamed:@"image"];
        cell.textLabel.text = @"System";
        return cell;
    }
    
    //系统创建的cell调用,其他不调用
    - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
        if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
            NSLog(@"%s", __func__);
        }
        return self;
    }
    
    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
        if (self = [super initWithCoder:aDecoder]) {
            NSLog(@"%s", __func__);
        }
        return self;
    }
    
    - (void)awakeFromNib {
        [super awakeFromNib];
        // Initialization code
        NSLog(@"%s", __func__);
    }
    
    - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
        [super setSelected:selected animated:animated];
    
        // Configure the view for the selected state
    }
    
    @end
    

     

      本文也顺便研究了各种创建cell的方式的系统方法调用顺序,可以看到,控制台只打印了initWithStyle方法,也就是说,系统样式创建的cell只在cell未开始复用时调用该方法,其他方法不调用。

      以下是XibTableViewCell,即xib创建cell的方式,本文创建的cell内容视图都与系统的default样式相似,故xib的约束未贴出:

    //
    //  XibTableViewCell.m
    //  20170317-cell系统方法调用顺序
    //
    //  Created by 柯其谱 on 17/3/17.
    //  Copyright © 2017年 柯其谱. All rights reserved.
    //
    
    #import "XibTableViewCell.h"
    
    NSString * const XibTableViewCellID = @"XibCell";
    
    @implementation XibTableViewCell
    
    + (instancetype)cellWithTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
        NSLog(@"%s", __func__);
        XibTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:XibTableViewCellID];
        cell.xibImageView.image = [UIImage imageNamed:@"image"];
        cell.xibTextLabel.text = @"Xib";
        return cell;
    }
    
    - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
        if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
            NSLog(@"%s", __func__);
        }
        return self;
    }
    
    //xib创建cell先调用此方法,再调用awakeFromNib
    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
        if (self = [super initWithCoder:aDecoder]) {
            NSLog(@"%s", __func__);
        }
        return self;
    }
    
    - (void)awakeFromNib {
        [super awakeFromNib];
        // Initialization code
        NSLog(@"%s", __func__);
    }
    
    - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
        [super setSelected:selected animated:animated];
    
        // Configure the view for the selected state
    }
    
    @end
    

       控制台中,先打印initWithCoder方法名,再打印awakeFromNib方法名,也就是说用xib创建的cell会先后调用这两个方法,可以在awakeFromNib中作一些cell的初始化工作

       以下是CustomCell实现文件,即代码自定义创建cell的方式,由于内容视图较为简单,这里未做约束:

    //
    //  CustomTableViewCell.m
    //  20170317-cell系统方法调用顺序
    //
    //  Created by 柯其谱 on 17/3/17.
    //  Copyright © 2017年 柯其谱. All rights reserved.
    //
    
    #import "CustomTableViewCell.h"
    
    NSString * const CustomTableViewCellID = @"CustomCell";
    
    @implementation CustomTableViewCell
    
    + (instancetype)cellWithTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
        NSLog(@"%s", __func__);
        CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CustomTableViewCellID];
        cell.customImageView.image = [UIImage imageNamed:@"image"];
        cell.customTextLabel.text = @"Custom";
        return cell;
    }
    
    //代码自定义cell调用,其他不调用
    - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
        if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
            NSLog(@"%s", __func__);
            [self setupContentView];
        }
        return self;
    }
    
    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
        if (self = [super initWithCoder:aDecoder]) {
            NSLog(@"%s", __func__);
            [self setupContentView];
        }
        return self;
    }
    
    - (void)awakeFromNib {
        [super awakeFromNib];
        // Initialization code
        NSLog(@"%s", __func__);
    }
    
    - (void)setupContentView {
        UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(16, 0, self.contentView.frame.size.height, self.contentView.frame.size.height)];
        self.customImageView = imageView;
        [self.contentView addSubview:imageView];
        
        UILabel *textLabel = [[UILabel alloc]initWithFrame:CGRectMake(CGRectGetMaxX(imageView.frame)+16, 0, 100, CGRectGetHeight(imageView.frame))];
        self.customTextLabel = textLabel;
        [self.contentView addSubview:textLabel];
    }
    
    - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
        [super setSelected:selected animated:animated];
    
        // Configure the view for the selected state
    }
    
    @end
    

      代码自定义创建cell的方式与系统样式相似,会调用initWithStyle,重写此方法并添加内容视图,以及添加内容视图子视图的约束。

      以上是Objective-C语言编写的简单创建cell的代码,接下来介绍Swift3.0编写的创建cell的代码,代码实现的目标与Objective-C完全一致,只是部分代码发生了改变

      下图是Swift3.0代码的项目结构:

      需要注意的是在APPDelegate文件中,初始化UITableViewController子类的方法与Objective-C略有不同,UITableViewController子类中必须重写init(style: UITableViewStyle)方法才能顺利调用UITableViewController子类的空构造方法,否则编译器无法通过

      以下是UITableViewController子类中的代码:

    //
    //  TableViewController.Swift
    //  Swift demo - 三种cell创建方式
    //
    //  Created by 柯其谱 on 17/3/18.
    //  Copyright © 2017年 柯其谱. All rights reserved.
    //
    
    import UIKit
    
    class TableViewController: UITableViewController {
    
        //MARK: - View life cycle
        override func viewDidLoad() {
            super.viewDidLoad()
    
            //使tableView向下20个点
            tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0)
            print(NSStringFromClass(XibTableViewCell.self), XibTableViewCell.reuseIdentifier)
            //Swift有命名空间的概念,使得NSStringFromClass这个方法返回的不只是类名,签名还有类名所在文件相对路径
            tableView.register(UINib.init(nibName: "XibTableViewCell", bundle: nil), forCellReuseIdentifier: XibTableViewCell.reuseIdentifier)
            tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: CustomTableViewCell.reuseIdentifier)
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
        //MARK: - Construction method
        //必须重写此方法,UITableViewController才能成功调用空的构造方法
        override init(style: UITableViewStyle) {
            super.init(style: style)
            print(#function)
        }
        
        //必须重写此方法,否则编译无法通过
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            print(#function)
        }
    
        //重写此方法使得UITableViewController能够调用空的构造方法
        override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
            super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
            print(#function)
        }
        
    }
    
    extension TableViewController {
        //MARK: - UITableViewDelegate
        override func numberOfSections(in tableView: UITableView) -> Int {
            // #warning Incomplete implementation, return the number of sections
            return 3
        }
        
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            // #warning Incomplete implementation, return the number of rows
            return 1
        }
        
        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            switch indexPath.section {
            case 0:
                let systemCell = SystemTableViewCell.cell(tableView: tableView, indexPath: indexPath)
                return systemCell
            case 1:
                let xibCell = XibTableViewCell.cell(tableView: tableView, indexPath: indexPath)
                return xibCell
            default:
                let customCell = CustomTableViewCell.cell(tableView: tableView, indexPath: indexPath)
                return customCell
            }
        }
    }
    

       与Objective-C不同的是,Swift3.0需要重写一些构造方法,另外一点,在cell的nib注册方法中,Swift直接将cell的nib文件名作为参数传入,这是因为Swift的命名空间机制,使得每一个类都有一个唯一的命名空间,类名便多了一些诸如项目名的前缀,若此处坚持使用跟Objective-C注册cell 的方式一致,使用NSStringFromClass([XibTableViewCell class]方法作为参数传入,则运行会导致奔溃,cell始终是空值。其余代码与Objective-C大体一致。

      以下是SystemTableViewCell文件中的代码:

    //
    //  SystemTableViewCell.Swift
    //  Swift demo - 三种cell创建方式
    //
    //  Created by 柯其谱 on 17/3/18.
    //  Copyright © 2017年 柯其谱. All rights reserved.
    //
    
    import UIKit
    
    class SystemTableViewCell: UITableViewCell {
    
        static let reuseIdentifier = "SystemCell"
        
        static func cell(tableView: UITableView, indexPath: IndexPath) -> SystemTableViewCell{
            print(#function)
            var cell: SystemTableViewCell?
            cell = tableView.dequeueReusableCell(withIdentifier: SystemTableViewCell.reuseIdentifier) as! SystemTableViewCell?
            if cell == nil {
                cell = SystemTableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: SystemTableViewCell.reuseIdentifier)
            }
            cell?.imageView?.image = UIImage(named: "image")
            cell?.textLabel?.text = "System"
            return cell!
        }
        
        override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            print(#function)
        }
        
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            print(#function)
        }
        
        override func awakeFromNib() {
            super.awakeFromNib()
            // Initialization code
            print(#function)
        }
    
        override func setSelected(_ selected: Bool, animated: Bool) {
            super.setSelected(selected, animated: animated)
    
            // Configure the view for the selected state
        }
    
    }
    

      此处与Objective-C代码类似,这里不作赘述,调用方式也一致

      以下是XibTableViewCell文件代码:

    //
    //  XibTableViewCell.Swift
    //  Swift demo - 三种cell创建方式
    //
    //  Created by 柯其谱 on 17/3/18.
    //  Copyright © 2017年 柯其谱. All rights reserved.
    //
    
    import UIKit
    
    class XibTableViewCell: UITableViewCell {
    
        static let reuseIdentifier = "XibCell"
        
        @IBOutlet weak var xibImageView: UIImageView!
        
        @IBOutlet weak var xibTextLabel: UILabel!
        
        static func cell(tableView: UITableView, indexPath: IndexPath) -> XibTableViewCell {
            print(#function)
            var cell: XibTableViewCell?
            cell = tableView.dequeueReusableCell(withIdentifier: XibTableViewCell.reuseIdentifier) as! XibTableViewCell?
            cell?.xibImageView.image = UIImage(named: "image")
            cell?.xibTextLabel.text = "Xib"
            return cell!
        }
        
        override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            print(#function)
        }
        
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            print(#function)
        }
        
        override func awakeFromNib() {
            super.awakeFromNib()
            // Initialization code
            print(#function)
        }
    
        override func setSelected(_ selected: Bool, animated: Bool) {
            super.setSelected(selected, animated: animated)
    
            // Configure the view for the selected state
        }
        
    }
    

       最后是CustomTableViewCell文件:

    //
    //  CustomTableViewCell.Swift
    //  Swift demo - 三种cell创建方式
    //
    //  Created by 柯其谱 on 17/3/18.
    //  Copyright © 2017年 柯其谱. All rights reserved.
    //
    
    import UIKit
    
    class CustomTableViewCell: UITableViewCell {
    
        static let reuseIdentifier = "CustomCell"
        
        ///左侧imageView
        var customImageView: UIImageView!
        ///右侧text label
        var customTextLabel: UILabel!
        
        static func cell(tableView: UITableView, indexPath: IndexPath) -> CustomTableViewCell {
            print(#function)
            var cell: CustomTableViewCell?
            cell = (tableView.dequeueReusableCell(withIdentifier: CustomTableViewCell.reuseIdentifier) as! CustomTableViewCell)
            cell?.customImageView.image = UIImage(named: "image")
            cell?.customTextLabel.text = "Custom"
            return cell!
        }
        
        override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            print(#function)
            self.setupContentView()
        }
        
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            print(#function)
        }
        
        override func awakeFromNib() {
            super.awakeFromNib()
            // Initialization code
            print(#function)
        }
    
        override func setSelected(_ selected: Bool, animated: Bool) {
            super.setSelected(selected, animated: animated)
    
            // Configure the view for the selected state
        }
        
        ///添加内容视图
        private func setupContentView() {
            customImageView = UIImageView()
            self.contentView.addSubview(customImageView)
            
            customTextLabel = UILabel()
            self.contentView.addSubview(customTextLabel)
            
            let imageViewH: CGFloat = self.contentView.frame.size.height
            customImageView.frame = CGRect(x: 16, y: 0,  imageViewH, height: imageViewH)
            customTextLabel.frame = CGRect(x: customImageView.frame.maxX+16, y: customImageView.frame.minY,  200, height: customImageView.frame.height)
        }
    
    }
    

       此处内容视图的子视图未添加约束,只是简单地设置了frame,当然,在真实项目中可在此处用cocoapods导入snapkit框架作适配,即Objective-C语言masonry矿建的Swift版本。

  • 相关阅读:
    poj2976 Dropping tests (01分数规划)
    bzoj5281/luogu4377 Talent Show (01分数规划+背包dp)
    bzoj5280/luogu4376 MilkingOrder (二分答案+拓扑序)
    bzoj1492/luogu4027 货币兑换 (斜率优化+cdq分治)
    [模板]树状数组
    匿名函数 python
    yield解析你要知道的源自IBM
    stackoverflow yield 帖子
    pandas 生成器,生成大数据
    pd.contact,dataframe 拼接
  • 原文地址:https://www.cnblogs.com/keqipu/p/6580215.html
Copyright © 2020-2023  润新知