swift 中as、as!、as? 这三种类型转换操作符的异同 及一些控件用法

    xiaoxiao2026-06-13  10

    转自: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)效果图               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     } }

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

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

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

     

    转载请注明原文地址: https://ju.6miu.com/read-1310485.html
    最新回复(0)