swift简单总结(六)—— 协议扩展与泛型

版本记录

版本号 时间
V1.0 2017.07.21

前言

我是swift2.0的时候开始接触的,记得那时候还不是很稳定,公司的项目也都是用oc做的,并不对swift很重视,我自己学了一段时间,到现在swift3.0+已经出来了,自己平时也不写,忘记的也差不多了,正好项目这段时间已经上线了,不是很忙,我就可以每天总结一点了,希望对自己对大家有所帮助。在总结的时候我会对比oc进行说明,有代码的我会给出相关比对代码。
1. swift简单总结(一)—— 数据简单值和类型转换
2. swift简单总结(二)—— 简单值和控制流
3. swift简单总结(三)—— 循环控制和函数
4. swift简单总结(四)—— 函数和类
5. swift简单总结(五)—— 枚举和结构体

协议

说到协议,我们对oc中的协议再熟悉不过了,我们可以给任意类添加协议,然后别的类想实现这个类协议中的方法,就要先遵守这个协议,设置代理,然后实现协议中的方法,比较常见的应用,就是UITableViewCell中生成协议,在控制器中遵守并实现协议中的代理方法,下面我们就看一下我们熟悉的oc中的协议。

#import <UIKit/UIKit.h>

@class ZBShortVideoModel;
@class ZBShortVideoTeamMainZoneCell;
@class ZBGroupHomeShortVideo;

@protocol ZBShortVideoTeamMainZoneCellDelegate <NSObject>

//播放代理
- (void)zbShortVideoTeamMainZoneCell:(ZBShortVideoTeamMainZoneCell *)cell playModel:(ZBGroupHomeShortVideo *)model;

//赞
- (void)zbShortVideoTeamMainZoneCell:(ZBShortVideoTeamMainZoneCell *)cell praiseButton:(ZBUIButton *)button;

//评论
- (void)zbShortVideoTeamMainZoneCell:(ZBShortVideoTeamMainZoneCell *)cell commentButton:(ZBUIButton *)button;

//分享
- (void)zbShortVideoTeamMainZoneCell:(ZBShortVideoTeamMainZoneCell *)cell shareModel:(ZBGroupHomeShortVideo *)model;

//点击头像查看个人信息
- (void)zbShortVideoTeamMainZoneCell:(ZBShortVideoTeamMainZoneCell *)cell avatarModel:(ZBGroupHomeShortVideo *)model;

//视频封面被点击了
- (void)zbShortVideoTeamMainZoneCell:(ZBShortVideoTeamMainZoneCell *)cell coverPlayModel:(ZBGroupHomeShortVideo *)model;

@end

@interface ZBShortVideoTeamMainZoneCell : UITableViewCell

@property (nonatomic, weak) id <ZBShortVideoTeamMainZoneCellDelegate> delegate;
@property (nonatomic, strong) ZBShortVideoModel *model;
@property (nonatomic, strong) ZBGroupHomeShortVideo *homeShortVideoModel;

@end

上面是我自己定义的协议,具体如何定义这里就不多说了,下面我们再一看一下系统中的协议UITableViewDelegate

//_______________________________________________________________________________________________________________
// this represents the display and behaviour of the cells.

@protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>

@optional

// Display customization

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);

// Variable height support

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;

// Use the estimatedHeight methods to quickly calcuate guessed values which will allow for fast load times of the table.
// If these methods are implemented, the above -tableView:heightForXXX calls will be deferred until views are ready to be displayed, so more expensive logic can be placed there.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(7_0);
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0);
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0);

// Section header & footer information. Views are preferred over title should you decide to provide both

- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;   // custom view for header. will be adjusted to default or specified header height
- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;   // custom view for footer. will be adjusted to default or specified footer height

// Accessories (disclosures). 

- (UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath NS_DEPRECATED_IOS(2_0, 3_0) __TVOS_PROHIBITED;
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath;

// Selection

// -tableView:shouldHighlightRowAtIndexPath: is called when a touch comes down on a row. 
// Returning NO to that message halts the selection process and does not cause the currently selected row to lose its selected look while the touch is down.
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);

// Called before the user changes the selection. Return a new indexPath, or nil, to change the proposed selection.
- (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- (nullable NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);
// Called after the user changes the selection.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);

// Editing

// Allows customization of the editingStyle for a particular cell located at 'indexPath'. If not implemented, all editable cells will have UITableViewCellEditingStyleDelete set for them when the table has editing property set to YES.
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
- (nullable NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0) __TVOS_PROHIBITED;
- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED; // supercedes -tableView:titleForDeleteConfirmationButtonForRowAtIndexPath: if return value is non-nil

// Controls whether the background is indented while editing.  If not implemented, the default is YES.  This is unrelated to the indentation level below.  This method only applies to grouped style table views.
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;

// The willBegin/didEnd methods are called whenever the 'editing' property is automatically changed by the table (allowing insert/delete/move). This is done by a swipe activating a single row
- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath __TVOS_PROHIBITED;
- (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(nullable NSIndexPath *)indexPath __TVOS_PROHIBITED;

// Moving/reordering

// Allows customization of the target row for a particular row as it is being moved/reordered
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath;               

// Indentation

- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath; // return 'depth' of row for hierarchies

// Copy/Paste.  All three methods must be implemented by the delegate.

- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(5_0);
- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender NS_AVAILABLE_IOS(5_0);
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender NS_AVAILABLE_IOS(5_0);

// Focus

- (BOOL)tableView:(UITableView *)tableView canFocusRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0);
- (BOOL)tableView:(UITableView *)tableView shouldUpdateFocusInContext:(UITableViewFocusUpdateContext *)context NS_AVAILABLE_IOS(9_0);
- (void)tableView:(UITableView *)tableView didUpdateFocusInContext:(UITableViewFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator NS_AVAILABLE_IOS(9_0);
- (nullable NSIndexPath *)indexPathForPreferredFocusedViewInTableView:(UITableView *)tableView NS_AVAILABLE_IOS(9_0);

@end

那么swift中如何定义和使用协议呢?我们往下看。

1. 协议的声明

下面我们先看一下协议是如何声明的。

protocol ExampleProtocol {
    var simpleDescription : String { get }
    mutating func adjust()
}

2. 协议的使用

swift中与oc中不同的是,类、枚举和结构体都可以遵守并实现协议,下面我们继续看代码。

类实现协议

类可以实现协议,下面先看代码。

import UIKit

protocol ExampleProtocol {
    var simpleDescription : String { get }
    mutating func adjust()
}

class JJStructVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()

        let a = SimpleClass()
        a.adjust()
        let desc = a.simpleDescription
        print(desc)
    }
}

class SimpleClass : ExampleProtocol {

    var simpleDescription: String = "It is a simple class."
    var anotherProperty  : Int = 733800
    
    func adjust() {
        simpleDescription += "Now 100% adjusted"
    }
}

看输出结果

It is a simple class.Now 100% adjusted

结构体实现协议

下面我们就看一下结构体是如何实现协议的。


struct SimpleStructure : ExampleProtocol {
    var simpleDescription: String
    mutating func adjust() {
        simpleDescription += " (adjust)"
    }
}

class JJStructVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        //结构体协议的遵守
        var b = SimpleStructure(simpleDescription: "A simple structure")
        b.adjust()
        let desc = b.simpleDescription
        print(desc)
    }
}

下面看输出结果

A simple structure(adjust)

枚举实现协议

这个大家自己写吧,练习一下。

需要注意的是:

  • 声明SimpleStructure的时候关键字mutating用来标记一个会修改结构体的方法,SimpleClass的声明不需要标记任何方法,因为类中方法经常会修改类。

扩展

使用extension为现有的类型添加功能,比如新的方法和参数,你可以使用扩展类改造定义在别处,甚至是从外部库或者框架引入的一个类型,使这个类型遵守某个协议。下面我们看一下swift中是如何扩展的,看下面代码。

protocol ExampleProtocol {
    var simpleDescription : String { get }
    mutating func adjust()
}

class JJStructVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        let a = 7.simpleDescription
        print(a)
    }
}

extension Int : ExampleProtocol {

    var simpleDescription : String{
        return "The number is \(self)"
    }
    mutating func adjust() {
        self += 42
    }
}

下面看输出结果

The number is 7

这个和oc中的分类有点类似,在oc中分类就是补充本类不全的方法或者定义等,下面我们就简单的看一个oc中的分类。

@interface UIView (UIViewGestureRecognizers)

@property(nullable, nonatomic,copy) NSArray<__kindof UIGestureRecognizer *> *gestureRecognizers NS_AVAILABLE_IOS(3_2);

- (void)addGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer NS_AVAILABLE_IOS(3_2);
- (void)removeGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer NS_AVAILABLE_IOS(3_2);

// called when the recognizer attempts to transition out of UIGestureRecognizerStatePossible if a touch hit-tested to this view will be cancelled as a result of gesture recognition
// returns YES by default. return NO to cause the gesture recognizer to transition to UIGestureRecognizerStateFailed
// subclasses may override to prevent recognition of particular gestures. for example, UISlider prevents swipes parallel to the slider that start in the thumb
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer NS_AVAILABLE_IOS(6_0);

@end


上面的就是UIView与手势有关的分类。

这里扩展先就简单的说这么多,后续还会继续添加。


泛型

说到泛型大家都不陌生,在尖括号里面写一个名字类创建一个泛型函数或者类型。

oc中我们经常在模型数组里面加入泛型,加入泛型有几个好处。

  • 给数组添加元素等操作时,如果类型和泛型不一样,会报警告,可以第一时间找到问题。
  • 特别是在数组遍历的时候,obj前面会自动加入泛型指定的类型,这样取模型属性或者实现对象独有的方法会非常方便,不用二次修改。

下面我们看一下oc中泛型的例子。

@property (nonatomic, strong) NSMutableArray <UILabel *> *labelArrM;

if (self.labelArrM.count > 0) {
        [self.labelArrM enumerateObjectsUsingBlock:^(UILabel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            [obj removeFromSuperview];
        }];
 }

具体有什么好处,大家就自己体会吧。

下面我们就看一下swift中的泛型。

1. 泛型函数

class JJStructVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        var a = 10;
        var b = 20;
        swapTwoValue(a: &a, b: &b)
        print("a:\(a),b:\(b)")
    }

    func swapTwoValue<T>(a : inout T, b : inout T){
        let tempValue = a;
        a = b;
        b = tempValue;
    }
}

下面我们看输出结果

a:20,b:10

这里, Swift是安全的语言,不允许两个不同类型互换值,用来交换两个同样类型的值,但是这个函数用 T 占位符来代替实际的类型。并没有指定具体的类型,但是传入的a ,b 必须是同一类型T。在调用这个函数的时候才能指定 T 是那种具体的类型。还有函数名后跟的那个 <T> 是函数定义的一个占位类型名,并不会查找T的具体类型。假如我们想交换两个Double类型、或者是其他类型的值,就不需要针对每个类型写不同的方法,只是参数类型不同。为了解决这个问题,Swift提供了泛型,帮助我们来解决这个问题。

2. 泛型类、枚举和结构体

除了上面的泛型函数,也可以创建泛型类、枚举还有结构体,先看一下代码。

enum OptionalValue <T>
{
    case None
    case Some(T)
}

class JJEnumVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        //泛型枚举
        var possibleInteger : OptionalValue<Int> = .None
        possibleInteger = .Some(100)
        print(possibleInteger)
   }
}

下面看一下输出结果

Some(100)

在类型后面使用where来指定对类型的需求,比如,限定类型实现某一个协议,限定两个类型是相同的,或者限定某个类必须有一个特定的父类。

func anyCommonElement<T, U where T : SequenceType,  U : SequenceType >

简单来说,还可以省略where,只在冒号后面写协议或者类名,也就是说下面的两种用法是等价的。

<T where T : SequenceType>
<T : SequenceType>

后记

未完,待续

唯美
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,290评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,399评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,021评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,034评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,412评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,651评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,902评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,605评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,339评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,586评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,076评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,400评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,060评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,851评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,685评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,595评论 2 270

推荐阅读更多精彩内容