目录
前言
因为我在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