Extensions存储属性
From: https://grayluo.github.io/WeiFocusIo/cocoa-swift/2015/12/21/swiftpracticeextensionmd
在OC中我们使用Category提高的代码的规范,减少了冗余,在swift中虽然不再有Category了,但是有了类似功能的Extension,相比于Category而言,Extension没有名称,而且不能定义存储属性(当然我们可以使用runtime解决,稍后会讲到)。
Extensions可以扩展的内容包括:
- 添加计算型属性和计算静态属性
- 定义实例方法和类型方法
- 提供新的构造器
- 定义下标
- 定义和使用新的嵌套类型
- 使一个已有类型符合某个接口
- 属性与方法:
extension SomeType {
// 加到SomeType的新功能写到这里
}
- 协议:
extension SomeType: SomeProtocol, AnotherProctocol {
// 协议实现写到这里
}
//CustomCell
extension CustomCell{
var defaulHeight:Float{
return 50;
}
}
//test
let cell = CustomCell(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
let defaultHeight = cell.defaulHeight
print("default height:\(defaultHeight)")
虽然我们前面已经讲到了,默认的extension不支持存储属性,我们来试一下:
//CustomCell
extension CustomCell{
var company:String?
}
编译器直接就提示: Extensions may not contain stored properties
但是有时候我们也会有这种需要在Extension中添加存储属性的时候,比如我们使用别人的第三方库时,那我们有没有其它办法可以实现在Extension中添加存储属性呢,当默认的方法都实现不了的时候,在iOS开发中不论是OC还是Swift,我们都可以考虑一下Runtime。
//CustomCell
extension CustomCell{
private struct AssociatedKeys{
static var name = "CustomCell_name"
static var location = "CustomCell_location"
}
var name:String?{
get{
return objc_getAssociatedObject(self, &AssociatedKeys.name) as? String
}
set{
if let newValue = newValue{
objc_setAssociatedObject(self, &AssociatedKeys.name, newValue as String, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
var location:String?{
get{
return objc_getAssociatedObject(self, &AssociatedKeys.location) as? String
}
set{
if let newValue = newValue{
objc_setAssociatedObject(self, &AssociatedKeys.location, newValue as String, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
}
//test
let cell = CustomCell(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
cell.name = "Grey.Luo"
cell.location = "成都市高新区"
print("cell.name:\(cell.name),cell.location:\(cell.location)")
以上就是一个最基本的使用Runtime给Extension添加存储属性的示例,其中objc_getAssociatedObject与objc_setAssociatedObject中都会用到一个关联key,可以把其想作是KVC的那种思想,为了不对整个类和命名空间(即模块)导致污染,使用这种私有嵌套结构体的方式是业内大牛们推荐的方式,OK,我们再看一下runtime的文档:
/**
* Sets an associated value for a given object using a given key and association policy.
*
* @param object The source object for the association.
* @param key The key for the association.
* @param value The value to associate with the key key for object. Pass nil to clear an existing association.
* @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”
*
* @see objc_setAssociatedObject
* @see objc_removeAssociatedObjects
*/
@available(iOS 3.1, *)
public func objc_setAssociatedObject(object: AnyObject!, _ key: UnsafePointer<Void>, _ value: AnyObject!, _ policy: objc_AssociationPolicy)
/**
* Returns the value associated with a given object for a given key.
*
* @param object The source object for the association.
* @param key The key for the association.
*
* @return The value associated with the key \e key for \e object.
*
* @see objc_setAssociatedObject
*/
@available(iOS 3.1, *)
public func objc_getAssociatedObject(object: AnyObject!, _ key: UnsafePointer<Void>) -> AnyObject!
//CustomCell
extension CustomCell{
convenience init(defaultHeight:Float){
self.init()
print("convenience init...\(defaultHeight)")
}
//test
let cell = CustomCell(defaultHeight: 50)
extension CustomCell{
func normalFun(param1:String,param2:Int){
print("normalFun,\(param1),\(param2)")
}
}
PS: 一旦某个扩展方法中要修改实例本身,则需要在方法前添加mutating,而且仅支持结构体与枚举的扩展,不支持类和协议,其实就是数据类型与类在系统中的存储机制不一样。 如:
extension Int{
mutating func doubleIt(){
self = self * 2
}
}
以下方法则不行:
class CustomOb: NSObject {
var customName:String?
var customLocation:String?
init(name:String, location:String) {
customName = name
customLocation = location
}
}
extension CustomOb{
mutating func modifyMyself(defaultHeight:Float){
self = CustomOb(name: "Grey.Luo", location: "成都高新")
}
}
以上这样对CustomOb进行扩展,无法使用mutating进行实例修改,直接报错:
‘mutating’ isn’t valid on methods in classes or class-bound protocols
如果对Subscripts不太熟悉的同学,可以查看[Cocoa-Swift之Subscripts][1]
[1]:
//CustomOb
class CustomOb: NSObject {
var customName:String?
var customLocation:String?
init(name:String, location:String) {
customName = name
customLocation = location
}
}
extension CustomOb{
subscript(index:Int) -> String{
var rs:String? = nil
if(index == 0){
rs = customName
}else if(index == 1){
rs = customLocation
}
return rs!
}
}
//test
let customOb = CustomOb(name: "Grey.Luo", location:"成都高新")
print("\(customOb[0]),\(customOb[1])")
我们前面在讲存储属性的时候其实已经涉及到了,前面嵌套了一个结构体用于Runtime的关联key。我们再来一个枚举示例。
class CustomOb: NSObject {
var customName:String?
var customLocation:String?
var customGroup:String?
init(name:String , location:String , group:String?) {
customName = name
customLocation = location
customGroup = group
}
enum Sex{
case Secret,Man,Woman
}
var sex:Sex{
switch(customGroup?.lowercaseString){
case "ManGroup"?:
return .Man
case "WomanGroup"?:
return .Woman
default:
return .Secret
}
}
}
//test
let customOb = CustomOb(name: "Grey.Luo", location:"成都高新" ,group: nil)
print("customOb.Sex:\(customOb.sex)")
protocol CustomObProtocol{
func protocolFun(age:Int,company:String)->Bool
}
extension CustomOb:CustomObProtocol{
func protocolFun(age: Int, company: String) -> Bool {
print("age:\(age),company:\(company)")
return true
}
}
参考:
本文主要用于一个知识的归纳总结,过程中可能会引用到其它地方的文字或代码,如有侵权请及时联系我,在此对写作过程中参考了的文章作者表示感谢!
Extensions存储属性
install_url
to use ShareThis. Please set it in _config.yml
.