首先说明几个关键累的作用:
- UserModel类。
用户模型类。一般我们获取了用户信息是放在一个字典里的,现在我们把字典的数据转化成UserModel,这样在我们使用数据的时候可以做到更加便捷和清晰。
同时,我们把访问与用户数据相关的接口放在这个类里,这样做可以增加代码的简洁性。
- User类。
User类是一个单例类,用来保存UserModel实例。一般我们获取了数据,并转化为UserModel后,会直接把UserModel实例回调到LoginViewController,用于更新界面。而V2里的做法是把UseModel实例存储到单例User里,什么时候使用什么时候访问。
此外,我们在User里设置了一个观察属性username,通过监听这个属性的变化来更新UI。
User类还有其他和用户相关的作用,不过总体来说是为了信息的存储使用。
实现用户模块用到的接口:
Controller:
1.点击登陆按钮:
func doLoginAction() {
//参数处理
var username: String?
var password: String?
if let len = self.usernameTextField.text?.characters.count, len > 0{
username = self.usernameTextField.text
}
else{
self.usernameTextField.becomeFirstResponder()
return
}
if let len = self.passwordTextField.text?.characters.count, len > 0{
password = self.passwordTextField.text
}
else{
self.passwordTextField.becomeFirstResponder()
return
}
V2BeginLoadingWithStatus(status: "正在登录")
UserModel.login(username: username!, password: password!) {(response) in
if response.success{
V2Success(status: "登陆成功")
//获取用户信息。注意到没有数据返回,是因为获取的数据实体存储到了单例类User,通过KVO监听实现UI更新
UserModel.getUserInfoByUsername(username: response.value!, completionHandler: { (response) in
self.dismiss(animated: true, completion: nil)
})
}
else{
V2Error(status: response.message)
}
}
}
说明:要注意在getUserInfoByUsername()的回调里没有数据,是因为我们直接把数据存放到了单例类User,通过监听User类的username属性来更新内容
UserModel类:
1.登陆接口1
这个接口实际上不需要参数,直接访问地址获取onceStr、usernameStr、passwordStr
//登录接口1
//1.获取once,回帖、登录都需要用到once。2.获取username、password两个关键字。一般来说我们访问服务器时,字典中参数的key就叫username,但是这里需要获取。
class func login(username: String, password: String, completionHandler: @escaping (V2ValueResponse<String>) -> Void){
Alamofire.request(V2EXURL + "signin", headers: MOBILE_CLIENT_HEADERS).response{ (response) in
if let data = response.data, let utf8Text = String.init(data: data, encoding: .utf8), let jiDoc = Ji.init(htmlString: utf8Text){
//xml数据转字符串(数据处理)
let onceStr: String? = jiDoc.xPath("//*[@name='once'][1]")?.first?["value"]
let usernameStr: String? = jiDoc.xPath("//*[@id='Wrapper']/div/div[1]/div[2]/form/table/tr[1]/td[2]/input[@class='sl']")?.first?["name"]
let passwordStr:String? = jiDoc.xPath("//*[@id='Wrapper']/div/div[1]/div[2]/form/table/tr[2]/td[2]/input[@class='sl']")?.first?["name"]
if let onceStr = onceStr, let usernameStr = usernameStr, let passwordStr = passwordStr {
UserModel.login(username: username, password: password, once: onceStr, usernameFieldName: usernameStr, passwordFieldName: passwordStr, completionHandler: completionHandler)
return
}
}
completionHandler(V2ValueResponse.init(success: false, message: "获取必要字段失败"))
}
}
2.登陆接口2
该接口接受参数once、next、passwordStr、usernameStr,成功访问网络后获得头像和username(昵称),然后将username回调。
//登录接口2
//说明:通过登录接口1获取的once、usernameStr、passwordStr关键字,然后根据输入的用户名和密码,实现对登录接口的访问,并返回用户名和头像
class func login(username: String, password: String, once: String, usernameFieldName: String, passwordFieldName: String, completionHandler: @escaping (V2ValueResponse<String>) -> Void) {
let parameters = [
"once": once,
"next": "/",
passwordFieldName: password,
usernameFieldName: username
]
var dict = MOBILE_CLIENT_HEADERS
dict["Referer"] = "https://v2ex.com/signin"
Alamofire.request(V2EXURL+"signin", method: .post, parameters: parameters, headers: dict).response { (response) in
let htmlString = String.init(data: response.data!, encoding: .utf8)
if let htmlString = htmlString, let jiHtml = Ji.init(htmlString: htmlString) {
if let avatarImg = jiHtml.xPath("//*[@id='Top']/div/div/table/tr/td[3]/a[1]/img[1]")?.first {
if let username = avatarImg.parent?["href"]{
if username.hasPrefix("/member/") {
let username = username.replacingOccurrences(of: "/member/", with: "")
completionHandler(V2ValueResponse.init(success: true, value: username))
return;
}
}
}
}
completionHandler(V2ValueResponse.init(success: false))
}
}
3.回调后,根据username访问用户信息接口
获得回调的username后,需要再次调用获取用户信息的接口,获取用户对象的所有属性信息。
//3.获取用户信息
//说明:通过『登录接口2』获取的username,访问服务器获取整个用户对象的信息。
class func getUserInfoByUsername(username: String, completionHandler: ((V2ValueResponse<String>) -> Void)?) {
let parames = ["username": username]
Alamofire.request(V2EXURL + "api/members/show.json", parameters:parames, headers: MOBILE_CLIENT_HEADERS).responseJSON { (reponse:DataResponse) in
if let model = reponse.result.value as? Dictionary<String, Any>{
let userModel = UserModel()
userModel.username = model["username"] as! String?
userModel.avatar_mini = model["avatar_mini"] as! String?
userModel.avatar_normal = model["avatar_normal"] as! String?
userModel.avatar_large = model["avatar_large"] as! String?
V2User.sharedInstance.userModel = userModel
completionHandler!(V2ValueResponse.init(success: true, message: "成功"))
}
}
}
成功后返回的就是用户对象的所有数据。把返回的属性和UserModel的属性一一对应就完成对UserModel的操作。