as! ios swift

2017-07-02 17:29:17 robinson_911 阅读数 3149
  • The as! Operator!

    让我们来操作as吧!

  • 说明

    因为最近在学习Swift,这里根据苹果官方文档加上自己的理解,总结了下常用的as、as!、as? 这三种类型转换操作符的异同和使用方式。
  • 正文

    • as
      keywordGuaranteed conversion、 Upcasting
      理解:字面理解就是有保证的转换,从派生类转换为基类的向上转型
      著名代码:
      // 将1转成float
      let num = 1 as CGFloat
      |------------------------
      // dog转换到父类animal
      class Animal {}
      class Dog: Animal {}
      let d = Dog()
      d as Animal
    • as!
      keywordForced conversion、 Downcasting
      理解:字面理解就是有强项转换,即向下转型,子类(派生类)向父类转换,官方解释说这是一个不被保证的转换,可能会因为强转的失败而会导致崩溃。同时 是一个陷阱的标志,就像⚠️一样,用起来存在一定危险性
      著名代码:
      // Dog到Animal的转化
      class Animal {}
      class Dog: Animal {}
      let a: Animal = Dog()
      a as Dog        // as不能将a转成Dog,即不能向下转换
      a as! Dog    // as!能强行将a转成Dog -> Bingo
    • as?
      keyword Optional、 Nil
      理解:Swfit代码写一段时间后会发现到处都是  ,这预示着如果转换不成功的时候便会返回一个 nil 对象。成功的话返回可选类型值(optional)。
      著名代码:
      // Dog、Cat和Animal的转换关系
      class Animal {}
      class Cat: Animal {}
      class Dog: Animal {
      var name = "Spot"
      }
      let dog: Dog? = nil
      dog?.name        // 选择调用,返回空值nil
      dog!.name        // 强行调用,报错
      let animal: Animal = Cat()
      animal as? Dog    // 猫转狗失败,返回nil
      animal as! Dog    // 猫强行转狗,失败报错
  • 引用参考

2016-08-16 16:24:27 zhanglizhi111 阅读数 2051

转自:http://www.111cn.net/sj/iOS/104115.htm


应网友要求,我这里总结了下 as、as!、as? 这三种类型转换操作符的异同,以及各自的使用场景。

1,as使用场合

(1)从派生类转换为基类,向上转型(upcasts)

class Animal {}
class Cat: Animal {}
let cat = Cat()
let animal = cat as Animal

(2)消除二义性,数值类型转换


let num1 = 42 as CGFloat
let num2 = 42 as Int
let num3 = 42.5 as Int
let num4 = (42 / 2) as Double

(3)switch 语句中进行模式匹配

如果不知道一个对象是什么类型,你可以通过switch语法检测它的类型,并且尝试在不同的情况下使用对应的类型进行相应的处理。


switch animal {
case let cat as Cat:
    print("如果是Cat类型对象,则做相应处理")
case let dog as Dog:
    print("如果是Dog类型对象,则做相应处理")
default: break
}

2,as!使用场合

向下转型(Downcasting)时使用。由于是强制类型转换,如果转换失败会报 runtime 运行错误。


class Animal {}
class Cat: Animal {}
let animal :Animal  = Cat()
let cat = animal as! Cat

3,as?使用场合

as? 和 as! 操作符的转换规则完全一样。但 as? 如果转换不成功的时候便会返回一个 nil 对象。成功的话返回可选类型值(optional),需要我们拆包使用。
由于 as? 在转换失败的时候也不会出现错误,所以对于如果能确保100%会成功的转换则可使用 as!,否则使用 as?


let animal:Animal = Cat()
 
if let cat = animal as? Cat{
    print("cat is not nil")
} else {
    print("cat is nil")
}


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


1,支持排序的多列表格(multi-column sortable table control)效果图
    原文:Swift - 多列表格组件的实现(样例2:带排序功能)      原文:Swift - 多列表格组件的实现(样例2:带排序功能)
 
2,功能说明:
(1)表格列头文字增加下划线样式,表示可以点击。
(2)点击列头标题,内容条目便会根据该列数据进行排序显示(先升序、后降序,依次交替)
(3)排序列背景色会变为蓝色,同时列头会显示上下箭头表示排列顺序。

(4)这里排序的上下箭头不是图片,而是使用 Font Awesome 图标字体库。优点是可以很轻松地设置颜色和大小,而不会失真

 

3,项目代码
(代码中高亮部分表示新增的排序相关的代码) 

--- UICollectionGridViewController.swift(组件类) --


-- UICollectionGridViewController.swift(组件类) ---

import Foundation
import UIKit
 
//表格排序协议
protocol UICollectionGridViewSortDelegate {
    func sort(colIndex: Int, asc: Bool, rows: [[AnyObject]]) -> [[AnyObject]]
}
 
//多列表格组件(通过CollectionView实现)
class UICollectionGridViewController: UICollectionViewController {
    //表头数据
    var cols: [String]! = []
    //行数据
    var rows: [[AnyObject]]! = []
     
    //排序代理
    var sortDelegate: UICollectionGridViewSortDelegate!
    //选中的表格列(-1表示没有选中的)
    private var selectedColIdx = -1
    //列排序顺序
    private var asc = true
    //单元格内容居左时的左侧内边距
    private var cellPaddingLeft:CGFloat = 5
     
    init() {
        //初始化表格布局
        let layout = UICollectionGridViewLayout()
        super.init(collectionViewLayout: layout)
        layout.viewController = self
        collectionView!.backgroundColor = UIColor.whiteColor()
        collectionView!.registerClass(UICollectionViewCell.self,
            forCellWithReuseIdentifier: "cell")
        collectionView!.delegate = self
        collectionView!.dataSource = self
        collectionView!.directionalLockEnabled = true
        collectionView!.contentInset = UIEdgeInsetsMake(0, 10, 0, 10)
        collectionView!.bounces = false
    }
     
    required init?(coder aDecoder: NSCoder) {
        fatalError("UICollectionGridViewController.init(coder:) has not been implemented")
    }
     
    //设置列头数据
    func setColumns(columns: [String]) {
        cols = columns
    }
     
    //添加行数据
    func addRow(row: [AnyObject]) {
        rows.append(row)
        collectionView!.collectionViewLayout.invalidateLayout()
        collectionView!.reloadData()
    }
     
    override func viewDidLoad() {
        super.viewDidLoad()
    }
     
    override func viewDidLayoutSubviews() {
        collectionView!.frame = CGRectMake(0, 0, view.frame.width, view.frame.height)
    }
     
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
     
    //返回表格总行数
    override func numberOfSectionsInCollectionView(collectionView: UICollectionView)
        -> Int {
        if cols.isEmpty {
            return 0
        }
        //总行数是:记录数+1个表头
        return rows.count + 1
    }
     
    //返回表格的列数
    override func collectionView(collectionView: UICollectionView,
        numberOfItemsInSection section: Int) -> Int {
        return cols.count
    }
     
    //单元格内容创建
    override func collectionView(collectionView: UICollectionView,
        cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell",
            forIndexPath: indexPath) as UICollectionViewCell
        //单元格边框
        cell.layer.borderWidth = 1
        cell.backgroundColor = UIColor.whiteColor()
        cell.clipsToBounds = true
         
        //先清空内部原有的元素
        for subview in cell.subviews {
            subview.removeFromSuperview()
        }
         
        //添加内容标签
        let label = UILabel(frame: CGRectMake(0, 0, cell.frame.width, cell.frame.height))
         
        //第一列的内容左对齐,其它列内容居中
        if indexPath.row != 0 {
            label.textAlignment = NSTextAlignment.Center
        }else {
            label.textAlignment = NSTextAlignment.Left
            label.frame.origin.x = cellPaddingLeft
        }
         
        //设置列头单元格,内容单元格的数据
        if indexPath.section == 0 {
            let text = NSAttributedString(string: cols[indexPath.row], attributes: [
                NSUnderlineStyleAttributeName:NSUnderlineStyle.StyleSingle.rawValue,
                NSFontAttributeName:UIFont.boldSystemFontOfSize(15)
                ])
            label.attributedText = text
        } else {
            label.font = UIFont.systemFontOfSize(15)
            label.text = "\(rows[indexPath.section-1][indexPath.row])"
        }
        cell.addSubview(label)
         
        //列排序
        if indexPath.row == selectedColIdx {
            //排序列的单元格背景会变色
            cell.backgroundColor = UIColor(red: 122/255, green: 186/255, blue: 255/255,
                alpha: 1)
            //排序列列头显示升序降序图标,并调整列头标签相关位置
            if indexPath.section == 0 {
                let imageWidth: CGFloat = 14
                let imageHeight: CGFloat = 14
                let labelHeight = label.frame.height
                label.sizeToFit()
                label.frame = CGRectMake(cellPaddingLeft, 0, min(label.frame.width,
                    cell.frame.width - imageWidth), labelHeight)
      
                let iconType = asc ? FAType.FALongArrowUp : FAType.FALongArrowDown
                let imageView = UIImageView()
                imageView.frame = CGRectMake(label.frame.width+3,
                    cell.frame.height/2 - imageHeight/2, imageWidth, imageHeight)
                 
                imageView.setFAIconWithName(iconType, textColor: UIColor.blueColor())
                 cell.addSubview(imageView)
            }
        }
        return cell
    }
     
    //单元格选中事件
    override func collectionView(collectionView: UICollectionView,
        didSelectItemAtIndexPath indexPath: NSIndexPath) {
        //打印出点击单元格的[行,列]坐标
        print("点击单元格的[行,列]坐标: [\(indexPath.section),\(indexPath.row)]")
        if indexPath.section == 0 && sortDelegate != nil {
            //如果点击的是表头单元格,则默认该列升序排列,再次点击则变降序排列,以此交替
            asc = (selectedColIdx != indexPath.row) ? true : !asc
            selectedColIdx = indexPath.row
            rows = sortDelegate.sort(indexPath.row, asc: asc, rows: rows)
            collectionView.reloadData()
        }
    }
}

--- UICollectionGridViewLayout.swift(布局类) ---

import Foundation
import UIKit
 
//多列表格组件布局类
class UICollectionGridViewLayout: UICollectionViewLayout {
    private var itemAttributes: [[UICollectionViewLayoutAttributes]] = []
    private var itemsSize: [NSValue] = []
    private var contentSize: CGSize = CGSizeZero
    //表格组件视图控制器
    var viewController: UICollectionGridViewController!
     
    //准备所有view的layoutAttribute信息
    override func prepareLayout() {
        if collectionView!.numberOfSections() == 0 {
            return
        }
         
        var column = 0
        var xOffset: CGFloat = 0
        var yOffset: CGFloat = 0
        var contentWidth: CGFloat = 0
        var contentHeight: CGFloat = 0
         
        if itemAttributes.count > 0 {
            for var section = 0; section < collectionView?.numberOfSections(); section++ {
                let numberOfItems = collectionView?.numberOfItemsInSection(section)
                for var index = 0; index < numberOfItems; index++ {
                    if section != 0 && index != 0 {
                        continue
                    }
                     
                    let attributes = layoutAttributesForItemAtIndexPath(
                        NSIndexPath(forItem: index, inSection: section))!
                    if section == 0 {
                        var frame = attributes.frame
                        frame.origin.y = collectionView!.contentOffset.y
                        attributes.frame = frame
                    }
                }
            }
            return
        }
         
        itemAttributes = []
        itemsSize = []
         
        if itemsSize.count != viewController.cols.count {
            calculateItemsSize()
        }
         
        for var section = 0; section < collectionView?.numberOfSections(); section++ {
            var sectionAttributes: [UICollectionViewLayoutAttributes] = []
            for var index = 0; index < viewController.cols.count; index++ {
                let itemSize = itemsSize[index].CGSizeValue()
                 
                let indexPath = NSIndexPath(forItem: index, inSection: section)
                let attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath:
                    indexPath)
                //除第一列,其它列位置都左移一个像素,防止左右单元格间显示两条边框线
                if index == 0{
                    attributes.frame = CGRectIntegral(CGRectMake(xOffset, yOffset,
                        itemSize.width, itemSize.height))
                }else {
                    attributes.frame = CGRectIntegral(CGRectMake(xOffset-1, yOffset,
                        itemSize.width+1, itemSize.height))
                }
                 
                if section == 0 && index == 0 {
                    attributes.zIndex = 1024
                } else if section == 0 || index == 0 {
                    attributes.zIndex = 1023
                }
                 
                if section == 0 {
                    var frame = attributes.frame
                    frame.origin.y = collectionView!.contentOffset.y
                    attributes.frame = frame
                }
                 
                sectionAttributes.append(attributes)
                 
                xOffset = xOffset+itemSize.width
                column++
                 
                if column == viewController.cols.count {
                    if xOffset > contentWidth {
                        contentWidth = xOffset
                    }
                     
                    column = 0
                    xOffset = 0
                    yOffset += itemSize.height
                }
            }
            itemAttributes.append(sectionAttributes)
        }
         
        let attributes = itemAttributes.last!.last! as UICollectionViewLayoutAttributes
        contentHeight = attributes.frame.origin.y + attributes.frame.size.height
        contentSize = CGSizeMake(contentWidth, contentHeight)
    }
     
    //需要更新layout时调用
    override func invalidateLayout() {
        itemAttributes = []
        itemsSize = []
        contentSize = CGSizeZero
        super.invalidateLayout()
    }
     
    // 返回内容区域总大小,不是可见区域
    override func collectionViewContentSize() -> CGSize {
        return contentSize
    }
     
    // 这个方法返回每个单元格的位置和大小
    override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath)
        -> UICollectionViewLayoutAttributes? {
         return itemAttributes[indexPath.section][indexPath.row]
    }
     
    // 返回所有单元格位置属性
    override func layoutAttributesForElementsInRect(rect: CGRect)
        -> [UICollectionViewLayoutAttributes]? {
        var attributes: [UICollectionViewLayoutAttributes] = []
        for section in itemAttributes {
            attributes.appendContentsOf(section.filter(
                {(includeElement: UICollectionViewLayoutAttributes) -> Bool in
                return CGRectIntersectsRect(rect, includeElement.frame)
            }))
        }
        return attributes
    }
     
    //当边界发生改变时,是否应该刷新布局。
    //本例在宽度变化时,将重新计算需要的布局信息。
    override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
        let oldBounds = self.collectionView?.bounds
        if CGRectGetWidth(oldBounds!) != CGRectGetWidth(newBounds) {
            return true
        }else {
            return false
        }
    }
     
    //计算所有单元格的尺寸(每一列各一个单元格)
    func calculateItemsSize() {
        var remainingWidth = collectionView!.frame.width -
            collectionView!.contentInset.left - collectionView!.contentInset.right
         
        for var index = viewController.cols.count-1; index >= 0; index-- {
            let newItemSize = sizeForItemWithColumnIndex(index,
                remainingWidth: remainingWidth)
            remainingWidth -= newItemSize.width
            let newItemSizeValue = NSValue(CGSize: newItemSize)
            //由于遍历列的时候是从尾部开始遍历了,因此将结果插入数组的时候都是放人第一个位置
            itemsSize.insert(newItemSizeValue, atIndex: 0)
        }
    }
     
    //计算某一列的单元格尺寸
    func sizeForItemWithColumnIndex(columnIndex: Int, remainingWidth: CGFloat) -> CGSize {
        let columnString = viewController.cols[columnIndex]
        //根据列头标题文件,估算各列的宽度
        let size = NSString(string: columnString).sizeWithAttributes([
            NSFontAttributeName:UIFont.systemFontOfSize(15),
            NSUnderlineStyleAttributeName:NSUnderlineStyle.StyleSingle.rawValue
            ])
         
        //如果有剩余的空间则都给第一列
        if columnIndex == 0 {
            return CGSizeMake(max(remainingWidth, size.width + 17), size.height + 10)
        }
        //行高增加10像素,列宽增加17像素(为了容纳下排序图表)
        return CGSizeMake(size.width + 17, size.height + 10)
    }
}

--- ViewController.swift(测试类) ---

import UIKit
 
class ViewController: UIViewController, UICollectionGridViewSortDelegate {
     
    var gridViewController: UICollectionGridViewController!
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        gridViewController = UICollectionGridViewController()
        gridViewController.setColumns(["客户", "消费金额", "消费次数", "满意度"])
        gridViewController.addRow(["hangge", "100", "8", "60%"])
        gridViewController.addRow(["张三", "223", "16", "81%"])
        gridViewController.addRow(["李四", "143", "25", "93%"])
        gridViewController.addRow(["王五", "75", "2", "53%"])
        gridViewController.addRow(["韩梅梅", "43", "12", "33%"])
        gridViewController.addRow(["李雷", "33", "27", "45%"])
        gridViewController.addRow(["王大力", "33", "22", "15%"])
        gridViewController.sortDelegate = self
        view.addSubview(gridViewController.view)
    }
     
    override func viewDidLayoutSubviews() {
        gridViewController.view.frame = CGRectMake(0, 50, view.frame.width,
            view.frame.height-60)
    }
     
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
         
    }
     
    //表格排序函数
    func sort(colIndex: Int, asc: Bool, rows: [[AnyObject]]) -> [[AnyObject]] {
        let sortedRows = rows.sort { (firstRow: [AnyObject], secondRow: [AnyObject])
            -> Bool in
            let firstRowValue = firstRow[colIndex] as! String
            let secondRowValue = secondRow[colIndex] as! String
            if colIndex == 0 {
                //首例姓名使用字典排序法
                if asc {
                    return firstRowValue < secondRowValue
                }
                return firstRowValue > secondRowValue
            } else if colIndex == 1 || colIndex == 2 {
                //中间两列使用数字排序
                if asc {
                    return Int(firstRowValue)! < Int(secondRowValue)!
                }
                return Int(firstRowValue)! > Int(secondRowValue)!
            }
            //最后一列数据先去掉百分号,再转成数字比较
            let firstRowValuePercent = Int(firstRowValue.substringToIndex(
                firstRowValue.endIndex.advancedBy(-1)))
            let secondRowValuePercent = Int(secondRowValue.substringToIndex(
                secondRowValue.endIndex.advancedBy(-1)))
            if asc {
                return firstRowValuePercent < secondRowValuePercent
            }
            return firstRowValuePercent > secondRowValuePercent
             
        }
        return sortedRows
    }
}


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



UITextField、UITextView组件系统原生就支持文字的复制,但有时我们需要让其他的一些组件也能实现复制功能,比如点击复制UILabel上的文字、UIImageView中的图片、UITableView里单元格的内容、或者点击按钮把文字或图片自动复制到粘贴板中等等。
这些我们借助 UIPasteboard 就可以实现。

一,将内容写入到剪贴板中

1,复制字符串


UIPasteboard.generalPasteboard().string = "欢迎访问 hangge.com"

2,复制字符串数组


UIPasteboard.generalPasteboard().strings = ["hellow", "hangge.com"]

3,复制图片


let image = UIImage(named: "logo.png")
UIPasteboard.generalPasteboard().image = image

4,复制二进制数据(NSData)


let path = NSBundle.mainBundle().pathForResource("logo", ofType: "png")!
let fileData = NSData(contentsOfFile: path)!
UIPasteboard.generalPasteboard().setData(fileData, forPasteboardType: "public.png")

注:从剪贴板获取二进制数据(NSData)


let myData = UIPasteboard.generalPasteboard().dataForPasteboardType("public.png")


二,常见组件增加复制功能

1,让文本标签(UILabel)支持复制功能

我们自定义一个可复制的标签类 UICopyLabel(继承UILabel),其内部能响应 Touch 事件并显示复制菜单


import UIKit
 
class UICopyLabel: UILabel {
     
    override init(frame: CGRect) {
        super.init(frame: frame)
        sharedInit()
    }
     
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        sharedInit()
    }
     
    func sharedInit() {
        userInteractionEnabled = true
        addGestureRecognizer(UILongPressGestureRecognizer(target: self,
            action: "showMenu:"))
    }
     
    func showMenu(sender: AnyObject?) {
        becomeFirstResponder()
        let menu = UIMenuController.sharedMenuController()
        if !menu.menuVisible {
            menu.setTargetRect(bounds, inView: self)
            menu.setMenuVisible(true, animated: true)
        }
    }
     
    //复制
    override func copy(sender: AnyObject?) {
        let board = UIPasteboard.generalPasteboard()
        board.string = text
        let menu = UIMenuController.sharedMenuController()
        menu.setMenuVisible(false, animated: true)
    }
     
    override func canBecomeFirstResponder() -> Bool {
        return true
    }
     
    override func canPerformAction(action: Selector, withSender sender: AnyObject?)
        -> Bool {
        if action == "copy:" {
            return true
        }
        return false
    }
}

在这个文本标签上长按后便可以复制其内容:

原文:Swift - UIPasteboard剪贴板的使用详解(复制、粘贴文字和图片)2,让图片控件(UIImageView)支持复制、粘贴功能

我们自定义一个图片控件类 UICPImageView(继承UIImageView),内部同样添加Touch事件响应。该控件不仅支持复制,还支持粘贴。

import UIKit
 
class UICPImageView: UIImageView {
 
    override init(frame: CGRect) {
        super.init(frame: frame)
        sharedInit()
    }
     
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        sharedInit()
    }
     
    func sharedInit() {
        userInteractionEnabled = true
        addGestureRecognizer(UILongPressGestureRecognizer(target: self,
            action: "showMenu:"))
    }
     
    func showMenu(sender: AnyObject?) {
        becomeFirstResponder()
        let menu = UIMenuController.sharedMenuController()
        if !menu.menuVisible {
            menu.setTargetRect(bounds, inView: self)
            menu.setMenuVisible(true, animated: true)
        }
    }
     
    //复制
    override func copy(sender: AnyObject?) {
        let board = UIPasteboard.generalPasteboard()
        board.image = self.image
        let menu = UIMenuController.sharedMenuController()
        menu.setMenuVisible(false, animated: true)
    }
     
    //粘贴
    override func paste(sender: AnyObject?) {
        let board = UIPasteboard.generalPasteboard()
        self.image = board.image
        let menu = UIMenuController.sharedMenuController()
        menu.setMenuVisible(false, animated: true)
    }
     
    override func canBecomeFirstResponder() -> Bool {
        return true
    }
     
    override func canPerformAction(action: Selector, withSender sender: AnyObject?)
        -> Bool {
        if action == "copy:" {
            return true
        }else if action == "paste:" {
            return true
        }
        return false
    }
}

下面我们在界面上添加两个 UICPImageView,我们可以把左边控件里的图片复制到右边控件中来,效果图如下:

 

3,让表格(UITableView)支持复制功能


import UIKit
 
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
     
    var tableView:UITableView?
    var tableData = ["条目1", "条目2", "条目3", "条目4", "条目5", "条目6", "条目7"]
     
    override func loadView() {
        super.loadView()
    }
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //创建表视图
        self.tableView = UITableView(frame: self.view.frame, style:.Plain)
        self.tableView!.delegate = self
        self.tableView!.dataSource = self
        //创建一个重用的单元格
        self.tableView!.registerClass(UITableViewCell.self,
            forCellReuseIdentifier: "SwiftCell")
        self.view.addSubview(self.tableView!)
    }
     
    func tableView(tableView: UITableView, performAction action: Selector,
        forRowAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) {
            let board = UIPasteboard.generalPasteboard()
            board.string = tableData[indexPath.row]
    }
     
    func tableView(tableView: UITableView, canPerformAction action: Selector,
        forRowAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) -> Bool {
            if action == "copy:" {
                return true
            }
            return false
    }
     
    func tableView(tableView: UITableView,
        shouldShowMenuForRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        return true
    }
     
    //在本例中,只有一个分区
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1;
    }
     
    //返回表格行数(也就是返回控件数)
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tableData.count
    }
     
    //创建各单元显示内容(创建参数indexPath指定的单元)
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
        -> UITableViewCell
    {
        //为了提供表格显示性能,已创建完成的单元需重复使用
        let identify:String = "SwiftCell"
        //同一形式的单元格重复使用,在声明时已注册
        let cell = tableView.dequeueReusableCellWithIdentifier(identify,
            forIndexPath: indexPath) as UITableViewCell
        cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
        cell.textLabel?.text = tableData[indexPath.row]
        return cell
    }
     
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

长按某个单元格即可复制这个单元格内容:

 





2018-07-19 10:51:26 Philm_iOS 阅读数 2178
本文总结 as、as!、as? 这三种类型转换操作符的异同,以及各自的使用场景。

as

有保证的转换,从派生类转换为基类的向上转型(upcasts)
使用场合:

  • 从派生类转换为基类,向上转型(upcasts)
class Animal {}
class Cat: Animal {}
let cat = Cat()
let animal = cat as Animal
  • 消除二义性,数值类型转换
let num1 = 42 as CGFloat
let num2 = 42 as Int
let num3 = 42.5 as Int
let num4 = (42 / 2) as Double
  • switch 语句中进行模式匹配

如果不知道一个对象是什么类型,你可以通过switch语法检测它的类型,并且尝试在不同的情况下使用对应的类型进行相应的处理。

switch animal {
    case let cat as Cat:
    print("如果是Cat类型对象,则做相应处理")
    case let dog as Dog:
    print("如果是Dog类型对象,则做相应处理")
    default: break
}

as!

强制类型转换,向下转型(Downcasting)时使用,子类(派生类)向父类转换,如果转换失败会报 runtime 运行错误。

官方解释说这是一个不被保证的转换,可能会因为强转的失败而会导致崩溃。同时 !是一个陷阱的标志,就像⚠️一样,用起来存在一定危险性。
示例代码:

class Animal {}
class Cat: Animal {}
let animal :Animal  = Cat()
let cat = animal as! Cat

as?

[as?] 和 [as!] 操作符的转换规则完全一样。但 [as?] 如果转换不成功的时候便会返回一个 nil 对象。成功的话返回可选类型值(optional)。由于 [as?] 在转换失败的时候也不会出现错误,所以对于如果能确保100%会成功的转换则可使用 [as!] ,否则使用 [as?] 。
示例代码:

let animal:Animal = Cat()
if let cat = animal as? Cat{
    print("cat is not nil")
    } else {
    print("cat is nil")
}

原文地址:https://www.jianshu.com/p/ebe29d97b5e9

2017-03-08 15:42:51 jeffasd 阅读数 1882

http://www.jb51.net/article/97240.htm

IOS swift3.0 下闭包语法整理

一、闭包的概念

有oc基础的都知道,闭包其实是oc里面的block,语法格式不一样,但作用是一样的。主要是用于callBack(异步回调)或者两个类之间的通信。它的本质一个函数,一个可执行的代码块,只是这个函数是没有名字的,也就是匿名函数。你也可以把他看作如 int、float一样,是一种数据类型,一种可以作为参数传递的数据类型。

二、基本语法

1、闭包的声明

 //定义一个求和闭包
    //闭包类型:(Int,Int)->(Int)
    let add:(Int,Int)->(Int) = {
      (a,b) in
      return a + b;
    }
   //执行闭包,相当于调用函数 
   let result = add(1100, 200);
    //打印闭包返回值
    print("result=\(result)");

闭包类型是由参数返回值决定,如上述add闭包类型为(Int,Int)->(Int),箭头前面括号是参数类型,多个参数逗号隔开,箭头后面括号返回值类型。

分析下上面代码,“=”左边的“ let add:(Int,Int)->(Int) ”意思是声明一个add常量,add是一个闭包类型,并且这个闭包的类型是:(Int,Int)->(Int)。

“=”右边是一个代码块,即闭包的具体实现,相当于给左边add常量赋值。代码块的语法格式:

{
    (参数1,参数2) in
    //code
 }

参数和需执行的代码(code)用 关键字“in”隔开,如果闭包没有参数, “ () in”可以直接省略:

{
  //code
 }

你也可以用关键字“typealias”先声明一个闭包的数据类型

import UIKit

//声明一个闭包类型 AddBlock
typealias AddBlock = (Int,Int)->(Int);

class ViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()
    let add:AddBlock = {
      (a,b) in
      return a + b;
    }

   let result = add(1100, 200);
    print("result=\(result)");
 }
}

3、闭包的用法

1、两个类之间的通信

ios中类之间的通信方式有多种,常用的有:协议代理、通知,以及本章要讲的闭包。因为协议代理用起来比较麻烦,又是声明协议方法、又要设置代理的,代码步骤太多,我一般不用;通知一般用于两个完全没有关联的类通信,可以一对多,但解耦和的太厉害,我一般是特定的场合用。所以针对有关联的两个类之间的通信,我一般是用闭包或block的,这样比较简洁迅速。

示例程序:监听控制器上一个自定义view按钮的点击


界面效果

CustomView类中代码

class CustomView: UIView {

  //声明一个属性btnClickBlock,type为闭包可选类型
  //闭包类型:()->() ,无参数,无返回值
  var btnClickBlock:(()->())?;

  //重写 init(frame: CGRect)构造函数
  override init(frame: CGRect) {
    super.init(frame:frame);
    //创建按钮
    let btn = UIButton(frame: CGRect(x: 15, y: 15, width: 80, height: 32));
    btn.setTitle("按钮", for: .normal);
    btn.backgroundColor = UIColor.blue;
    //绑定事件
    btn.addTarget(self, action: #selector(CustomView.btnClick), for: .touchDown);
    //添加
    addSubview(btn);

  }
  //按钮点击事件函数
  func btnClick(){

    if self.btnClickBlock != nil {
      //点击按钮执行闭包
      //注意:属性btnClickBlock是可选类型,需要先解包
      self.btnClickBlock!();
    }
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

}

Controller类中代码:

class ViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()

    //创建CustomView对象
    let cutomeView = CustomView(frame: CGRect(x: 50, y: 50, width: 200, height: 200));
    //给cutomeView的btnClickBlock闭包属性赋值
    cutomeView.btnClickBlock = {
      // () in 无参数可以省略
      //当按钮被点击时会执行此代码块
      print("按钮被点击");
    }
    cutomeView.backgroundColor = UIColor.yellow;
    //添加到控制器view上
    self.view.addSubview(cutomeView);

  }
}

2、异步回调(callBack)

以发送一个简单的网络请求为例:

/// 定义一个网络请求函数
  ///
  /// - parameter urlString: 请求接口  String
  /// - parameter succeed:  成功的回调 可选闭包
  /// - parameter failure:  失败的回调 可选闭包
  func requestData(urlString:String,succeed: ((Any?)->(Void))?,failure:((Any?)->(Void))?){

    let request = URLRequest(url: URL(string: urlString)!);

    //发送网络请求
    NSURLConnection.sendAsynchronousRequest(request, queue: OperationQueue()) { (_, data, error) in
      if error == nil {
        //请求成功,执行成功的回调,并把数据传递出去
        succeed?(data);
      }else{
         //请求失败,执行失败的回调,并把错误传递出去
        failure?(error);
      }
    }
  }

// 调用函数requestData函数
    requestData(urlString: "http://www.baidu.com", succeed: { (data) -> (Void) in

      //成功的回调
      guard let result = data as? Data else{
        return;
      }

      let srt = NSString(data: result, encoding: String.Encoding.utf8.rawValue);

      print(srt!)


      }) { (error) -> (Void) in
        //失败的的回调
        print(error);
    }

四、闭包的一些特殊语法

1、尾随闭包

当闭包作为函数的最后一个参数时,可以省略前面的括号。尾随闭包没什么特殊的作用,纯粹是一种语法上的简洁,增加易读性。

例:定义一个函数:

//第二个参数:闭包 (String)->(Void)
func post(url:String,succesce:(String)->Void) {

    print("发送请求");

    succesce("请求完成");
  }

执行函数,正常写法:

 //正常写法,第二个参数,传递一个闭包
   post("http", succesce: {
      //闭包传递的参数
      (json) in
      //执行的代码
       print(json);

    });

执行函数,尾随闭包写法:

//尾随闭包,当闭包作为函数的最后一个参数时,可以省略前面的括号
 HttpTool.post("http") { (json) in
      print(json);
    };

2、逃逸闭包

看起来很“吊炸天”的一个名字,其实很简单。当闭包作为一个参数传递到函数时,我们知道它一般是用于函数内部的异步回调,闭包是等异步任务完成以后才调用,而函数是会很快执行完毕并返回的,所以闭包它需要逃逸,以便稍后的回调。

逃逸闭包一般用于异步函数的回调,比如网络请求成功的回调和失败的回调。语法:在函数的闭包行参前加关键字“@escaping”。

或许细心的人已经发现我上面的示例网络请求为什么没有出现关键字“@escaping”,你可以拉回去看下成功回调或失败的回调,类型是“((Any?)->(Void))?”,后面带了个“?”,这是闭包可选类型,并不是闭包类型,所以无需关键字“@escaping”。

假设成功和失败的回调要弄成闭包类型,而你又要异步使用的话,那就要在形参前面加关键字,如下:

 /// 定义一个网络请求函数
  ///
  /// - parameter urlString: 请求接口  String
  /// - parameter succeed: 成功的回调 闭包 因需要异步使用,前面加关键字@escaping修饰,指明其为逃逸闭包
  /// - parameter failure: 失败的回调 闭包 因需要异步使用,前面加关键字@escaping修饰,指明其为逃逸闭包
  func requestData(urlString:String,succeed: @escaping (Any?)->(Void),failure:@escaping (Any?)->(Void)){

    let request = URLRequest(url: URL(string: urlString)!);

    //发送网络请求
    NSURLConnection.sendAsynchronousRequest(request, queue: OperationQueue()) { (_, data, error) in
      if error == nil {
        //请求成功,执行成功的回调,并把数据传递出去
        succeed(data);
      }else{
         //请求失败,执行失败的回调,并把错误传递出去
        failure(error);
      }
    }
  }

假设成功和失败的回调要弄成闭包类型,而你又要异步使用的话,但你又不想在形参前面加关键字,那对不起,我也没有办法,编译直接报错!


2015-10-15 14:59:20 h454036111 阅读数 6215


一,as 

摘自中文api的话:仅当一个值的类型在运行时(runtime)和as模式右边的指定类型一致 - 或者是该类型的子类 - 的情况下,才会匹配这个值。如果匹配成功,被匹配的值的类型被转换成as模式左边指定的模式。

     首先是运行时   就不多说了  ,重要的是 as 应用条件有2种情况: 

    1,和 "as" 右边类型一致

    2,是右边类型的子类(这种情况在java里叫向上转型)

   事例代码如下:


二,as! 

上例中 第二种情况  2,是右边类型的子类  如果 碰到as 左边类型是右边类型的父类则会报错!(as不可以用于父类转子类,用java话说,不支持向下转型),由此可用as!(强转) 


      编译器也会提示你用as!, as!强转如果类型不符合会报错。

三,as?

as? 相当于optional类型,如果转换失败返回nil。 

上代码!