Swift: 如何让泛型代码更干净
Swift: How to make Generics code more clean
我正在寻找使我的代码更简洁、更高效的方法。
我有一个“BaseInfo”,它有一些属性,而且它是“SomeInfo”和“AnotherInfo”classes 的父级,它们有自己的附加属性。我创建了一个通用函数,用于从 UserDefaults 中保存和获取这些对象。考虑到它应该使用的信息类型,我有 ViewController 使用这些函数保存和加载信息。我想知道有什么方法可以使我的代码更清晰并摆脱我的 ViewContoller 中的那些类型转换。这是我的信息 classes:
public class BaseInfo: Codable{
var name: String?
init(_ dict: [String: Any]){
name = dict["name"] as? String
}
}
class AnotherInfo: BaseInfo {
var secondName: String?
override init(_ dict: [String : Any]) {
super.init(dict)
secondName = dict["secondName"] as? String
}
required init(from decoder: Decoder) throws {
fatalError("init(from:) has not been implemented")
}
}
class SomeInfo: BaseInfo {
var middleName: String?
override init(_ dict: [String : Any]) {
super.init(dict)
middleName = dict["middleName"]
}
required init(from decoder: Decoder) throws {
fatalError("init(from:) has not been implemented")
}
}
这是我的 class 管理信息
protocol InfoManagerProtocol {
static func getInfo(with type: InfoType) -> BaseInfo?
static func saveInfo <T: BaseInfo>(with type: InfoType, info: T)
}
class InfoManager: InfoManagerProtocol {
static func getInfo<T: BaseInfo>(with type: InfoType) -> T? {
if let data = UserDefaults.standard.object(forKey: type.toString()) as? Data, let info = try? JSONDecoder().decode(type.typeOfInfo() as! T.Type, from: data){
return info
}
return nil
}
static func saveInfo<T>(with type: InfoType, info: T) where T : BaseInfo {
if let encodedData = try? JSONEncoder().encode(info){
UserDefaults.standard.setValue(encodedData, forKey: type.toString())
}
}
}
InfoType 枚举:
enum InfoType: Int{
case base = 1
case another = 2
case some = 3
}
extension InfoType{
func toString() -> String{
switch self{
case .base:
return "base"
case .another:
return "another"
case .some:
return "some"
}
}
func typeOfInfo() -> BaseInfo.Type{
switch self{
case .base:
return BaseInfo.self
case .another:
return AnotherInfo.self
case .some:
return SomeInfo.self
}
}
}
和一些控制器
class ViewCV: UIViewController{
......
// some outlets
var infoType: InfoType? // info
// some func that updates UI
func updateUI(){
let genericInfo = InfoManager.getInfo(info: .infoType)
self.someNameOutletLabel.text = genericInfo.name
self.secondNameOutletLabel?.text = (genericInfo as? AnotherInfo).secondName // here I don't like it
if let someInfo = genericInfo as? SomeInfo{
self.secondNameOutletLabel?.text = someInfo.thirdName // or like here I also don't like
}
}
}
期待其他批评家和建议
您可以通过跳过 InfoType
类型来简化您的代码,而是定义从给定参数或 return 值使用的类型。
所以协议变成
protocol InfoManagerProtocol {
static func getInfo<T: BaseInfo>() -> T?
static func saveInfo <T: BaseInfo>(info: T)
}
然后执行。请注意,我现在使用类名本身作为键
而不是枚举中的 toString
class InfoManager: InfoManagerProtocol {
static func getInfo<T: BaseInfo>() -> T? {
if let data = UserDefaults.standard.object(forKey: "\(T.self)") as? Data, let info = try? JSONDecoder().decode(T.self, from: data){
return info
}
return nil
}
static func saveInfo<T>(info: T) where T : BaseInfo {
if let encodedData = try? JSONEncoder().encode(info){
print(encodedData)
UserDefaults.standard.set(encodedData, forKey: "\(T.self)")
}
}
}
下面是如何使用它的例子(假设init(from:)
已经正确实施)
let dict: [String: String] = ["name": "Joe", "secondName": "Doe", "middleName": "Jr"]
let another = AnotherInfo(dict)
let some = SomeInfo(dict)
//Here the declaration of the argument tells the generic function what T is
InfoManager.saveInfo(info: another)
InfoManager.saveInfo(info: some)
//And here the declaration of the return value tells the generic function what T is
if let stored:AnotherInfo = InfoManager.getInfo() {
print(stored, type(of: stored))
}
if let stored:SomeInfo = InfoManager.getInfo() {
print(stored, type(of: stored))
}
我正在寻找使我的代码更简洁、更高效的方法。 我有一个“BaseInfo”,它有一些属性,而且它是“SomeInfo”和“AnotherInfo”classes 的父级,它们有自己的附加属性。我创建了一个通用函数,用于从 UserDefaults 中保存和获取这些对象。考虑到它应该使用的信息类型,我有 ViewController 使用这些函数保存和加载信息。我想知道有什么方法可以使我的代码更清晰并摆脱我的 ViewContoller 中的那些类型转换。这是我的信息 classes:
public class BaseInfo: Codable{
var name: String?
init(_ dict: [String: Any]){
name = dict["name"] as? String
}
}
class AnotherInfo: BaseInfo {
var secondName: String?
override init(_ dict: [String : Any]) {
super.init(dict)
secondName = dict["secondName"] as? String
}
required init(from decoder: Decoder) throws {
fatalError("init(from:) has not been implemented")
}
}
class SomeInfo: BaseInfo {
var middleName: String?
override init(_ dict: [String : Any]) {
super.init(dict)
middleName = dict["middleName"]
}
required init(from decoder: Decoder) throws {
fatalError("init(from:) has not been implemented")
}
}
这是我的 class 管理信息
protocol InfoManagerProtocol {
static func getInfo(with type: InfoType) -> BaseInfo?
static func saveInfo <T: BaseInfo>(with type: InfoType, info: T)
}
class InfoManager: InfoManagerProtocol {
static func getInfo<T: BaseInfo>(with type: InfoType) -> T? {
if let data = UserDefaults.standard.object(forKey: type.toString()) as? Data, let info = try? JSONDecoder().decode(type.typeOfInfo() as! T.Type, from: data){
return info
}
return nil
}
static func saveInfo<T>(with type: InfoType, info: T) where T : BaseInfo {
if let encodedData = try? JSONEncoder().encode(info){
UserDefaults.standard.setValue(encodedData, forKey: type.toString())
}
}
}
InfoType 枚举:
enum InfoType: Int{
case base = 1
case another = 2
case some = 3
}
extension InfoType{
func toString() -> String{
switch self{
case .base:
return "base"
case .another:
return "another"
case .some:
return "some"
}
}
func typeOfInfo() -> BaseInfo.Type{
switch self{
case .base:
return BaseInfo.self
case .another:
return AnotherInfo.self
case .some:
return SomeInfo.self
}
}
}
和一些控制器
class ViewCV: UIViewController{
......
// some outlets
var infoType: InfoType? // info
// some func that updates UI
func updateUI(){
let genericInfo = InfoManager.getInfo(info: .infoType)
self.someNameOutletLabel.text = genericInfo.name
self.secondNameOutletLabel?.text = (genericInfo as? AnotherInfo).secondName // here I don't like it
if let someInfo = genericInfo as? SomeInfo{
self.secondNameOutletLabel?.text = someInfo.thirdName // or like here I also don't like
}
}
}
期待其他批评家和建议
您可以通过跳过 InfoType
类型来简化您的代码,而是定义从给定参数或 return 值使用的类型。
所以协议变成
protocol InfoManagerProtocol {
static func getInfo<T: BaseInfo>() -> T?
static func saveInfo <T: BaseInfo>(info: T)
}
然后执行。请注意,我现在使用类名本身作为键
而不是枚举中的toString
class InfoManager: InfoManagerProtocol {
static func getInfo<T: BaseInfo>() -> T? {
if let data = UserDefaults.standard.object(forKey: "\(T.self)") as? Data, let info = try? JSONDecoder().decode(T.self, from: data){
return info
}
return nil
}
static func saveInfo<T>(info: T) where T : BaseInfo {
if let encodedData = try? JSONEncoder().encode(info){
print(encodedData)
UserDefaults.standard.set(encodedData, forKey: "\(T.self)")
}
}
}
下面是如何使用它的例子(假设init(from:)
已经正确实施)
let dict: [String: String] = ["name": "Joe", "secondName": "Doe", "middleName": "Jr"]
let another = AnotherInfo(dict)
let some = SomeInfo(dict)
//Here the declaration of the argument tells the generic function what T is
InfoManager.saveInfo(info: another)
InfoManager.saveInfo(info: some)
//And here the declaration of the return value tells the generic function what T is
if let stored:AnotherInfo = InfoManager.getInfo() {
print(stored, type(of: stored))
}
if let stored:SomeInfo = InfoManager.getInfo() {
print(stored, type(of: stored))
}