概述
转自: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")
}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
(4)这里排序的上下箭头不是图片,而是使用 Font Awesome 图标字体库。优点是可以很轻松地设置颜色和大小,而不会失真
3,项目代码
(代码中高亮部分表示新增的排序相关的代码)
-- 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()
}
}
长按某个单元格即可复制这个单元格内容:
最后
以上就是天真天空为你收集整理的swift 中 as、as!、as? 这三种类型转换操作符的异同 及一些控件用法的全部内容,希望文章能够帮你解决swift 中 as、as!、as? 这三种类型转换操作符的异同 及一些控件用法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复