版本记录
版本号 | 时间 |
---|---|
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>
后记
未完,待续