Skip to content

codetalks-new/iOSCodeGenerator

Repository files navigation

iOS Code Generator

Let Code generate Code

安装与使用说明

安装

目前暂时推荐使用开发者模式来安装.

  1. clone 本项目.
  2. 在目录下执行 sudo python setup.py develop 这样就可以在全局目录引用 ios_code_generator 包了.

使用

整个生成脚本命令的调用, 我建议通过 Automator Service 来调用.

  1. 你可以直接将我创建好的 Automator Service 从 Utils/Services 目录拷贝到你机器的 ~/Library/Services 目录. 使用哪一个就拷贝哪一个,或者全部拷贝过去.

  2. 在 Xcode 右键 弹出菜单,选择 Service 就可以看到对应的服务了.

一: 从 API 到 Model

这里的目的是自动将 API 的返回转成 Model. 我以 微博 API 为例进行说明: 比如 微博中的用户对象. 其 API 返回 示例如下:

{ "id": 1404376560, "screen_name": "zaku", "name": "zaku", "province": "11", "city": "5", "location": "北京 朝阳区", "description": "人生五十年,乃如梦如幻;有生斯有死,壮士复何憾。", "url": "http://blog.sina.com.cn/zaku", "profile_image_url": "http://tp1.sinaimg.cn/1404376560/50/0/1", "domain": "zaku", "gender": "m", "followers_count": 1204, "friends_count": 447, "statuses_count": 2908, "favourites_count": 0, "created_at": "Fri Aug 28 00:00:00 +0800 2009", "following": false, "allow_all_act_msg": false, "remark": "", "geo_enabled": true, "verified": false, "allow_all_comment": true, "avatar_large": "http://tp1.sinaimg.cn/1404376560/180/0/1", "verified_reason": "", "follow_me": false, "online_status": 0, "bi_followers_count": 215 }

像这样的 API 返回 结果 , 我们在 应用中 创建一个 User 类,然后根据返回. 一个一个写上. 如:

struct User{ let id:Int let screenName: String /// 省略 }

写这样的代码就像是做苦力一样. 为此, 我写了一个代码生成脚本. 能够快速的 从 API 生成模型代码.

先来看一发动图, 感受下 从 API 到 Model 是多么的方便. [Json2FieldsToModel

使用的是通过 Automator 创建系统服务的方式来调用脚本

首先执行 将 json 转成 fields ,通过 json_to_fields() 函数 .得到结果如下: 上面是原来的 JSON 的. 以注释的形式保存. 下面是得到的字段列表.

/// { /// "id": 1404376560, /// "screen_name": "zaku", /// "name": "zaku", /// "province": "11", /// "city": "5", /// "location": "北京 朝阳区", /// "description": "人生五十年,乃如梦如幻;有生斯有死,壮士复何憾。", /// "url": "http://blog.sina.com.cn/zaku", /// "profile_image_url": "http://tp1.sinaimg.cn/1404376560/50/0/1", /// "domain": "zaku", /// "gender": "m", /// "followers_count": 1204, /// "friends_count": 447, /// "statuses_count": 2908, /// "favourites_count": 0, /// "created_at": "Fri Aug 28 00:00:00 +0800 2009", /// "following": false, /// "allow_all_act_msg": false, /// "remark": "", /// "geo_enabled": true, /// "verified": false, /// "allow_all_comment": true, /// "avatar_large": "http://tp1.sinaimg.cn/1404376560/180/0/1", /// "verified_reason": "", /// "follow_me": false, /// "online_status": 0, /// "bi_followers_count": 215 /// } id:d;screen_name;name;province;city;location;description;url:u;profile_image_url:u;domain;gender;followers_count:i;friends_count:i;statuses_count:i;favourites_count:i;created_at;following:i;allow_all_act_msg:i;remark;geo_enabled:i;verified:i;allow_all_comment:i;avatar_large:u;verified_reason;follow_me:i;online_status:i;bi_followers_count:i 

通过字段列表的速写, 生成 Model 类型

将字段列表稍微分一下行, 如下.

id:d;screen_name;name;province;city;location;description;url:u;profile_image_url:u domain;gender;followers_count:i;friends_count:i;statuses_count:i;favourites_count:i created_at;following:i;allow_all_act_msg:i;remark;geo_enabled:i;verified:i;allow_all_comment:i avatar_large:u;verified_reason;follow_me:i;online_status:i;bi_followers_count:i 

字段简写的形式是 filedName[:fieldType] 各个字段声明以分号分隔开. fieldType 可以省略,省略则表示为 String 类型. 其他的字段简写说明:

  • i : Int
  • b : Bool
  • d : Double
  • s : String 如果是 String 类型的话,建议不用写,因为这是默认类型.
  • u : URL 类型.
  • j : JSON 类型.

其他更多类型支持,参见: 代码中 ios_code_generator/maps.py:203 的说明.

然后通过 ,字段名称及类型简写列表生成 Model. 这里假定 JSON 序列化库为 SwiftyJSON 为上模型名称及相应的配置 User(eq,hash), 配置的意思看生成结果应该一目了然.

User(eq,hash) id:d;screen_name;name;province;city;location;description;url:u;profile_image_url:u;domain;gender;followers_count:i;friends_count:i;statuses_count:i;favourites_count:i;created_at;following:i;allow_all_act_msg:i;remark;geo_enabled:i;verified:i;allow_all_comment:i;avatar_large:u;verified_reason;follow_me:i;online_status:i;bi_followers_count:i 

生成出来的代码如下:

import SwiftyJSON import BXModel struct User :BXModel{ let id : Int let screenName : String let name : String let province : String let city : String let location : String let description : String let url : URL let profileImageUrl : URL let domain : String let gender : String let followersCount : Int let friendsCount : Int let statusesCount : Int let favouritesCount : Int let createdAt : String let following : Bool let allowAllActMsg : Bool let remark : String let geoEnabled : Bool let verified : Bool let allowAllComment : Bool let avatarLarge : URL let verifiedReason : String let followMe : Bool let onlineStatus : Int let biFollowersCount : Int init(json:JSON){ self.id = json["id"].intValue self.screenName = json["screen_name"].stringValue self.name = json["name"].stringValue self.province = json["province"].stringValue self.city = json["city"].stringValue self.location = json["location"].stringValue self.description = json["description"].stringValue self.url = json["url"].stringValue.quietUrl self.profileImageUrl = json["profile_image_url"].stringValue.quietUrl self.domain = json["domain"].stringValue self.gender = json["gender"].stringValue self.followersCount = json["followers_count"].intValue self.friendsCount = json["friends_count"].intValue self.statusesCount = json["statuses_count"].intValue self.favouritesCount = json["favourites_count"].intValue self.createdAt = json["created_at"].stringValue self.following = json["following"].boolValue self.allowAllActMsg = json["allow_all_act_msg"].boolValue self.remark = json["remark"].stringValue self.geoEnabled = json["geo_enabled"].boolValue self.verified = json["verified"].boolValue self.allowAllComment = json["allow_all_comment"].boolValue self.avatarLarge = json["avatar_large"].stringValue.quietUrl self.verifiedReason = json["verified_reason"].stringValue self.followMe = json["follow_me"].boolValue self.onlineStatus = json["online_status"].intValue self.biFollowersCount = json["bi_followers_count"].intValue } func toDict() -> [String:Any]{ var dict : [String:Any] = [ : ] dict["id"] = self.id dict["screen_name"] = self.screenName dict["name"] = self.name dict["province"] = self.province dict["city"] = self.city dict["location"] = self.location dict["description"] = self.description dict["url"] = self.url.absoluteString dict["profile_image_url"] = self.profileImageUrl.absoluteString dict["domain"] = self.domain dict["gender"] = self.gender dict["followers_count"] = self.followersCount dict["friends_count"] = self.friendsCount dict["statuses_count"] = self.statusesCount dict["favourites_count"] = self.favouritesCount dict["created_at"] = self.createdAt dict["following"] = self.following dict["allow_all_act_msg"] = self.allowAllActMsg dict["remark"] = self.remark dict["geo_enabled"] = self.geoEnabled dict["verified"] = self.verified dict["allow_all_comment"] = self.allowAllComment dict["avatar_large"] = self.avatarLarge.absoluteString dict["verified_reason"] = self.verifiedReason dict["follow_me"] = self.followMe dict["online_status"] = self.onlineStatus dict["bi_followers_count"] = self.biFollowersCount return dict } } extension User: Equatable{ static func ==(lhs:User,rhs:User) -> Bool{ return lhs.id == rhs.id } } extension User : Hashable{ var hashValue:Int{ return id.hashValue } }

Enum 好用, Enum 可以更易用

Swift 3 中的枚举可以说是我,好用到让我惊讶的程度. 但是我可以让它更易用.

经典用例

比如 用它来封装 应用 微信的 Tab 栏枚举,如下:

enum AppTab{ case wechat,contacts,discover,me }

到这里已经比用整型常量好很多了. 好了,现在你想将 UITabBarItem 中的构造封装在里面.

  1. 首先我们为其添加一个 title 属性,如下:
extension AppTab{ var title:String{ switch self { case .wechat: return "微信" case .contacts: return "通讯录" case .discover: return "发现" case .me: return "" } } }

然后.就可以直接使用 .title 就可以访问了. 避免了 使用字典保存映射的麻烦. 写法,修改也简单.

  1. 你想判断某一个 AppTab 值是不是 me. 你选择这样做 if tab == .wechat 嗯, Swift 中可以直接写 .wechat 这样的枚举值真方便. 但是你也可以这样. 添加一个 Bool 类型的 Computed Property.
extension AppTab{ var isWechat:Bool{ return self == .wechat } }

然后你想为所有的枚举值都加上这样的 Computed Property. 你复制粘贴然后修改.

  1. 很多时候,你想遍历枚举值, 于是你添加了一个静态属性.保存所以的枚举值为一个数组. 如下:
extension AppTab{ static let allCases:[ AppTab] = [.wechat, .contacts, .discover, .me] }

动起来

so far, so good. 那我可以帮到你什么呢? 我可以帮你少写代码. 怎么帮?

  1. 只需要写少量的几行声明:

如下.

AppTab wechat:微信 contacts: 通讯录 discover:发现 me:我 

选中, 右键, 选择 "Services|generate_enum" 然后如下代码就自动生成了:

//AppTab //wechat:微信 //contacts: 通讯录 //discover:发现 //me:我 enum AppTab { case wechat, contacts,discover,me var isWechat:Bool{ return self == .wechat } var isContacts:Bool{ return self == .contacts } var isDiscover:Bool{ return self == .discover } var isMe:Bool{ return self == .me } var title:String{ switch self{ case .wechat:return "微信" case .contacts:return " 通讯录" case .discover:return "发现" case .me:return "" } } static let allCases:[AppTab] = [.wechat,.contacts,.discover,.me] }

怎么样? 来试试吧! 当然还有其他选项可以使用. 如果你有其他需要麻烦告诉我. 当然有 PR 最好了.

最后来张动图感受一下:

Generate Enum

生成偏好设置访问存取代码

Generate Settings

未完待续

项目其他生成脚本的使用说明,稍后更新.

About

Let Code Generate Code

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published