让oc像swift那样给@protocol协议添加方法的默认实现教程加demo

18 篇文章 0 订阅
5 篇文章 0 订阅

前言

因为我在swift里面封装了大量的工具类,但是oc下却很少,网上很多第三方框架的demo,使用的时候都是给的oc代码,如果我要把它封装成swift 的话,如果是简单例子还好,可是碰到那种已经做得很好的demo,复杂的有800行代码,我逐条转换成swift再封装的话,时间太长,所以我就使用oc代码把他们封装成xib的UIView.这样使用的时候可以直接在xib里面填写封装的类名就能用了,用MVVM的话,比原始的代码创建和xib的控制器更方便,但是当我封装这些oc的View的时候,我以前已经封装好的swift协议,却不能直接使用,因为swift的协议是可以给方法添加默认实现方法的.

swift可以直接给协议方法设置默认方法

例如下面代码:setXib()方法的默认实现可以直接给从xib文件加载封装好的UIView,而我在自定义Xib的UIView的时候只需要继承协议,然后再调用setXib()

//
//  TDWXIBSet.swift
//  XibInXibDemo
//
//  Created by tdw on 2021/2/12.
//  Copyright © 2021 谭迪文. All rights reserved.
import UIKit
import Foundation
protocol TDWXIBSet where Self:UIView {
}

extension TDWXIBSet {
    func setXib(){
        // 需要这句代码,不能直接写UINib(nibName: "MyView", bundle: nil),不然不能在storyboard中显示
        let bundle = Bundle(for: type(of: self))
        let className = "\(Self.self)"
        let nib = UINib(nibName: className, bundle: bundle)
        let view = (nib.instantiate(withOwner: self, options: nil)[0] as! UIView)
        view.frame = bounds
        self.addSubview(view)
    }
}

UIView中调用的时候只要遵守协议,然后调用写好的setXib()

import UIKit
class View1: UIView,TDWXIBSet {
    @IBOutlet weak var btn1: UIButton!
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setXib()
    }
    var title = "+"
    override init(frame: CGRect) {
        super.init(frame: frame)
        setXib()
    }
}

为什么要使用协议而不是使用父类继承写好的方法呢?

使用父类写好的方法,然后让子类继承再调用父类写好的方法,这样只能单独继承一个类的时候行得通,因为swift和oc都是只能继承一个父类,也就是说如果我把自定义的setXib()方法,写在一个父类里面,那么我再用他,必须继承这个父类,就不能继承别的父类了,.但是协议是网状继承的.可以同时遵守多个协议.
举个例子:

假如说上面的TDWXIBSet 改成class,而不是协议,那么如果我的子类必须继承自UIView,那么我就没法同时继承UIView和 TDWXIBSet,编译报错,提示不能多重继承:Multiple inheritance from classes ‘UIView’ and ‘TDWXIBSet’.
但是如果你让父类 TDWXIBSet继承UIView,然后再继承父类TDWXIBSet,就行了,但是,父类TDWXIBSet也只能继承一个父类UIView,如果我下次想要继承NSObject,或者其他自定义的类,那么你的父类每次都要改动,都要继承别的类.这样太麻烦了.把TDWXIBSet改成协议就完美解决了单独继承的问题.每次你要用的时候,只要把你新建的类,继承UIView或者其他的,然后遵守协议,就能同时满足UIView和协议里的方法,而不是每次都要新创建一个父类.而协议,你写好一次以后放那里啥都不用动,每次直接遵守协议就能调用写好的默认方法.

oc中如何让协议@protocol 里的方法拥有默认实现过程呢?

设计思路

语法里面并没有像swift那种,协议的扩展,swift里面直接用extension关键字扩展协议,然后在{}大括号里面给协议定义实现过程
格式如下: extension 协议名字{ 协议方法的实现过程 }
oc里面没有这种扩展协议的语法,但是借鉴与swift里面有where 语法的骚操作 ,就是限定被继承的类,必须等于某个类的时候才能有协议里的属性和方法.

//这段swift语法让被继承的类被判断是否是UIView类型才被让使用里面的方法setXib()
protocol TDWXIBSet where Self:UIView {  
}
extension TDWXIBSet {
    func setXib(){
    }
}

把上面代码改成oc,的原理是,让oc写一个UIView的类扩展,然后让类扩展遵守协议,再再类扩展中给协议的方法写默认实现.操作如下:

oc添加协议

oc的协议格式:@protocol 协议名字 {属性 和 方法 } @end

//
//  TDWXibSetOc.h
//  OCXibViewDemo
//
//  Created by tdw on 2021/3/15.
//
#import <Foundation/Foundation.h>
@protocol TDWXibSetOc 
-(void)setXib;
@end

oc添加类扩展,让类扩展遵守协议

建立一个类扩展,这里就按照上面swift的例子,建立UIView的类扩展,这样只能继承自UIView可以使用,不会污染全局

//
//  UIView+TDWXib.h
//  OCXibViewDemo
//
//  Created by tdw on 2021/3/15.
//

#import <UIKit/UIKit.h>
#import "TDWXibSetOc.h"
NS_ASSUME_NONNULL_BEGIN

@interface UIView (TDWXib)<TDWXibSetOc>

@end

NS_ASSUME_NONNULL_END
//
//  UIView+TDWXib.m
//  OCXibViewDemo
//
//  Created by tdw on 2021/3/15.
//

#import "UIView+TDWXib.h"

@implementation UIView (TDWXib)
-(void)setXib{
    NSLog(@"setXib");
    //从File's Owner加载xib
    NSBundle * bundle = [NSBundle bundleForClass:[self class]];
    UINib* nib = [UINib nibWithNibName:NSStringFromClass( [self class]) bundle:bundle];
    UIView* view =  [[nib instantiateWithOwner:self options:nil]firstObject];
    view.frame = self.bounds;
    [self addSubview:view];
}

@end

oc让自己的类调用协议里的默认方法

下面的oc类 .h文件中遵守协议 .m文件中直接调用协议里的方法 [self setXib];,而且方法已经被实现过了.


//
//  OcView1.h
//  OCXibViewDemo
//
//  Created by tdw on 2021/3/15.
//

#import <UIKit/UIKit.h>
#import "TDWXibSetOc.h"
NS_ASSUME_NONNULL_BEGIN

@interface OcView1 : UIView<TDWXibSetOc>  
@property (weak, nonatomic) IBOutlet UIButton *btn1;

@end

NS_ASSUME_NONNULL_END
//
//  OcView1.m
//  OCXibViewDemo
//
//  Created by tdw on 2021/3/15.
//

#import "OcView1.h"
@interface OcView1(){
}
@end
@implementation OcView1
- (instancetype)initWithCoder:(NSCoder *)coder //xib里使用 UIView类名填写
{
    self = [super initWithCoder:coder];
    if (self) {
        [self setXib];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame   //代码创建 let v = ()
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setXib];
    }
    return self;
}
@end

demo下载地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值