swift簡(jiǎn)單總結(jié)(六)—— 協(xié)議擴(kuò)展與泛型

版本記錄

版本號(hào) 時(shí)間
V1.0 2017.07.21

前言

我是swift2.0的時(shí)候開始接觸的,記得那時(shí)候還不是很穩(wěn)定,公司的項(xiàng)目也都是用oc做的,并不對(duì)swift很重視,我自己學(xué)了一段時(shí)間,到現(xiàn)在swift3.0+已經(jīng)出來了,自己平時(shí)也不寫,忘記的也差不多了,正好項(xiàng)目這段時(shí)間已經(jīng)上線了,不是很忙,我就可以每天總結(jié)一點(diǎn)了,希望對(duì)自己對(duì)大家有所幫助。在總結(jié)的時(shí)候我會(huì)對(duì)比oc進(jìn)行說明,有代碼的我會(huì)給出相關(guān)比對(duì)代碼。
1. swift簡(jiǎn)單總結(jié)(一)—— 數(shù)據(jù)簡(jiǎn)單值和類型轉(zhuǎn)換
2. swift簡(jiǎn)單總結(jié)(二)—— 簡(jiǎn)單值和控制流
3. swift簡(jiǎn)單總結(jié)(三)—— 循環(huán)控制和函數(shù)
4. swift簡(jiǎn)單總結(jié)(四)—— 函數(shù)和類
5. swift簡(jiǎn)單總結(jié)(五)—— 枚舉和結(jié)構(gòu)體

協(xié)議

說到協(xié)議,我們對(duì)oc中的協(xié)議再熟悉不過了,我們可以給任意類添加協(xié)議,然后別的類想實(shí)現(xiàn)這個(gè)類協(xié)議中的方法,就要先遵守這個(gè)協(xié)議,設(shè)置代理,然后實(shí)現(xiàn)協(xié)議中的方法,比較常見的應(yīng)用,就是UITableViewCell中生成協(xié)議,在控制器中遵守并實(shí)現(xiàn)協(xié)議中的代理方法,下面我們就看一下我們熟悉的oc中的協(xié)議。

#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;

//評(píng)論
- (void)zbShortVideoTeamMainZoneCell:(ZBShortVideoTeamMainZoneCell *)cell commentButton:(ZBUIButton *)button;

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

//點(diǎn)擊頭像查看個(gè)人信息
- (void)zbShortVideoTeamMainZoneCell:(ZBShortVideoTeamMainZoneCell *)cell avatarModel:(ZBGroupHomeShortVideo *)model;

//視頻封面被點(diǎn)擊了
- (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

上面是我自己定義的協(xié)議,具體如何定義這里就不多說了,下面我們?cè)僖豢匆幌孪到y(tǒng)中的協(xié)議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中如何定義和使用協(xié)議呢?我們往下看。

1. 協(xié)議的聲明

下面我們先看一下協(xié)議是如何聲明的。

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

2. 協(xié)議的使用

swift中與oc中不同的是,類、枚舉和結(jié)構(gòu)體都可以遵守并實(shí)現(xiàn)協(xié)議,下面我們繼續(xù)看代碼。

類實(shí)現(xiàn)協(xié)議

類可以實(shí)現(xiàn)協(xié)議,下面先看代碼。

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"
    }
}

看輸出結(jié)果

It is a simple class.Now 100% adjusted

結(jié)構(gòu)體實(shí)現(xiàn)協(xié)議

下面我們就看一下結(jié)構(gòu)體是如何實(shí)現(xiàn)協(xié)議的。


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

class JJStructVC: UIViewController
{

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        //結(jié)構(gòu)體協(xié)議的遵守
        var b = SimpleStructure(simpleDescription: "A simple structure")
        b.adjust()
        let desc = b.simpleDescription
        print(desc)
    }
}

下面看輸出結(jié)果

A simple structure(adjust)

枚舉實(shí)現(xiàn)協(xié)議

這個(gè)大家自己寫吧,練習(xí)一下。

需要注意的是:

  • 聲明SimpleStructure的時(shí)候關(guān)鍵字mutating用來標(biāo)記一個(gè)會(huì)修改結(jié)構(gòu)體的方法,SimpleClass的聲明不需要標(biāo)記任何方法,因?yàn)轭愔蟹椒ń?jīng)常會(huì)修改類。

擴(kuò)展

使用extension為現(xiàn)有的類型添加功能,比如新的方法和參數(shù),你可以使用擴(kuò)展類改造定義在別處,甚至是從外部庫或者框架引入的一個(gè)類型,使這個(gè)類型遵守某個(gè)協(xié)議。下面我們看一下swift中是如何擴(kuò)展的,看下面代碼。

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
    }
}

下面看輸出結(jié)果

The number is 7

這個(gè)和oc中的分類有點(diǎn)類似,在oc中分類就是補(bǔ)充本類不全的方法或者定義等,下面我們就簡(jiǎn)單的看一個(gè)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與手勢(shì)有關(guān)的分類。

這里擴(kuò)展先就簡(jiǎn)單的說這么多,后續(xù)還會(huì)繼續(xù)添加。


泛型

說到泛型大家都不陌生,在尖括號(hào)里面寫一個(gè)名字類創(chuàng)建一個(gè)泛型函數(shù)或者類型。

oc中我們經(jīng)常在模型數(shù)組里面加入泛型,加入泛型有幾個(gè)好處。

  • 給數(shù)組添加元素等操作時(shí),如果類型和泛型不一樣,會(huì)報(bào)警告,可以第一時(shí)間找到問題。
  • 特別是在數(shù)組遍歷的時(shí)候,obj前面會(huì)自動(dòng)加入泛型指定的類型,這樣取模型屬性或者實(shí)現(xiàn)對(duì)象獨(dú)有的方法會(huì)非常方便,不用二次修改。

下面我們看一下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];
        }];
 }

具體有什么好處,大家就自己體會(huì)吧。

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

1. 泛型函數(shù)

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;
    }
}

下面我們看輸出結(jié)果

a:20,b:10

這里, Swift是安全的語言,不允許兩個(gè)不同類型互換值,用來交換兩個(gè)同樣類型的值,但是這個(gè)函數(shù)用 T 占位符來代替實(shí)際的類型。并沒有指定具體的類型,但是傳入的a ,b 必須是同一類型T。在調(diào)用這個(gè)函數(shù)的時(shí)候才能指定 T 是那種具體的類型。還有函數(shù)名后跟的那個(gè) <T> 是函數(shù)定義的一個(gè)占位類型名,并不會(huì)查找T的具體類型。假如我們想交換兩個(gè)Double類型、或者是其他類型的值,就不需要針對(duì)每個(gè)類型寫不同的方法,只是參數(shù)類型不同。為了解決這個(gè)問題,Swift提供了泛型,幫助我們來解決這個(gè)問題。

2. 泛型類、枚舉和結(jié)構(gòu)體

除了上面的泛型函數(shù),也可以創(chuàng)建泛型類、枚舉還有結(jié)構(gòu)體,先看一下代碼。

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)
   }
}

下面看一下輸出結(jié)果

Some(100)

在類型后面使用where來指定對(duì)類型的需求,比如,限定類型實(shí)現(xiàn)某一個(gè)協(xié)議,限定兩個(gè)類型是相同的,或者限定某個(gè)類必須有一個(gè)特定的父類。

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

簡(jiǎn)單來說,還可以省略where,只在冒號(hào)后面寫協(xié)議或者類名,也就是說下面的兩種用法是等價(jià)的。

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

后記

未完,待續(xù)

唯美
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容