防止偷懶Day24

今天來完成整個註冊、登入、登出程序

首先先來釐清需求

使用者打開APP時應該會進入HomeController

這時我們應該先判斷這使用者是否有帳號登入過

如果有就在navigationItem上更新這名使用者的名稱

如果沒有就把畫面送到LoginController

首先來修改HomeController.swift裡面的程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
override func viewDidLoad() {
super.viewDidLoad()
let newTeamButton = UIBarButtonItem(title: "New Team", style: .plain, target: self, action: #selector(toSetNewTeamController))
navigationItem.rightBarButtonItem = newTeamButton

let logoutButton = UIBarButtonItem(title: "Logout", style: .plain, target: self, action: #selector(handleLogout))
navigationItem.leftBarButtonItem = logoutButton
checkUserIsLogin()
}

func checkUserIsLogin() {
if FIRAuth.auth()?.currentUser?.uid == nil {
perform(#selector(handleLogout), with: nil, afterDelay: 0)
} else {
fetchUserSetNavBarTitle()
}
}

func fetchUserSetNavBarTitle() {
guard let uid = FIRAuth.auth()?.currentUser?.uid else {
return
}
FIRDatabase.database().reference().child("User").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
if let dictionary = snapshot.value as? [String: Any] {
self.navigationItem.title = dictionary["name"] as? String
}
}, withCancel: nil)
}

func handleLogout() {

do {
try FIRAuth.auth()?.signOut()
} catch let logoutError {
print(logoutError)
}

let loginController = LoginController()
loginController.homeController = self
present(loginController, animated: true, completion: nil)
}

我新增了兩個新的function跟修改了一個之前寫的function

這裡新增的兩個新的function分別是checkUserIsLogin以及fetchUserSetNavBarTitle

在viewDidLoad時會執行checkUserIsLogin這個function

裡面負責跟Firebase確認這支手機是否有登入過

如果沒有就去執行handleLogout讓畫面移動到LoginController

如果有就執行另一個新增的fetchUserSetNavBarTitle來更新從Firebase拿到的使用者名稱

然後是修改後的handleLogout多做了兩件事情

第一件事情是跟Firebase做登出的動作

第二件事是在實作LoginController時把hemeController的reference加進去

這樣做的目的是等等我們再處理完LoginController的登入或註冊之後可以直接來更新navigationItem的名稱

p.s.記得import Firebase

再來就進入LoginController.swift來處理登入跟註冊的程序

一樣先上程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import UIKit
import Firebase

class LoginController: AddMemberController {

var homeController: HomeController?
var profileImageTopAnchor: NSLayoutConstraint?
var emailTopAnchor: NSLayoutConstraint?

let loginSegmentedControl: UISegmentedControl = {
let sc = UISegmentedControl(items: ["Login", "Register"])
sc.selectedSegmentIndex = 0
sc.translatesAutoresizingMaskIntoConstraints = false
sc.addTarget(self, action: #selector(handleChangeButtonTitle), for: .valueChanged)
return sc
}()

let emailText: UITextField = {
let text = UITextField()
text.placeholder = "email"
text.translatesAutoresizingMaskIntoConstraints = false
text.layer.borderColor = UIColor.cyan.cgColor
text.layer.borderWidth = 1
return text
}()

let passwordText: UITextField = {
let text = UITextField()
text.placeholder = "password"
text.translatesAutoresizingMaskIntoConstraints = false
text.isSecureTextEntry = true
text.layer.borderColor = UIColor.cyan.cgColor
text.layer.borderWidth = 1
return text
}()

lazy var loginButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Login", for: .normal)
button.backgroundColor = .cyan
button.addTarget(self, action: #selector(handleLoginRegister), for: .touchUpInside)
return button
}()

func handleLoginRegister() {
if loginSegmentedControl.selectedSegmentIndex == 0 {
handleLogin()
} else {
handleRegister()
}
}

func handleLogin() {
guard let email = emailText.text, let password = passwordText.text else {
return
}
FIRAuth.auth()?.signIn(withEmail: email, password: password, completion: { (user, error) in
if error != nil {
return
}
self.homeController?.fetchUserSetNavBarTitle()
self.dismiss(animated: true, completion: nil)
})
}

func handleRegister() {
guard let email = emailText.text, let password = passwordText.text, let name = nameText.text else {
return
}

FIRAuth.auth()?.createUser(withEmail: email, password: password, completion: { (user: FIRUser?, error) in

if error != nil {
print(error!)
return
}

guard let uid = user?.uid else {
return
}

let ref = FIRDatabase.database().reference(fromURL: "https://hbcrecord-5a3d4.firebaseio.com/")
let userReference = ref.child("User").child(uid)
let accountValue = ["email": email, "name": name]
userReference.updateChildValues(accountValue, withCompletionBlock: { (err, ref) in

if err != nil {
print(err!)
return
}

self.homeController?.navigationItem.title = accountValue["name"]
self.dismiss(animated: true, completion: nil)

})

})
}

func handleChangeButtonTitle() {
if loginSegmentedControl.selectedSegmentIndex == 0 {
loginButton.setTitle("Login", for: .normal)
nameText.isHidden = true
profileImageTopAnchor?.constant = 64
emailTopAnchor?.constant = 8
} else {
loginButton.setTitle("Register", for: .normal)
nameText.isHidden = false
profileImageTopAnchor?.constant = 32
emailTopAnchor?.constant = 48
view.layoutIfNeeded()
}
}

override func viewDidLoad() {
super.viewDidLoad()

profileImage.removeFromSuperview()
profileImage.removeConstraints(profileImage.constraints)
positionSegmentedControl.removeFromSuperview()
nameText.removeFromSuperview()
registerButton.removeFromSuperview()

view.addSubview(profileImage)
view.addSubview(loginSegmentedControl)
view.addSubview(nameText)
view.addSubview(emailText)
view.addSubview(passwordText)
view.addSubview(loginButton)
nameText.isHidden = true

profileImageTopAnchor = profileImage.topAnchor.constraint(equalTo: view.topAnchor, constant: 64)
profileImageTopAnchor?.isActive = true
profileImage.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
profileImage.heightAnchor.constraint(equalToConstant: 110).isActive = true
profileImage.widthAnchor.constraint(equalToConstant: 110).isActive = true

loginSegmentedControl.topAnchor.constraint(equalTo: profileImage.bottomAnchor, constant: 8).isActive = true
loginSegmentedControl.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 22).isActive = true
loginSegmentedControl.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -22).isActive = true
loginSegmentedControl.heightAnchor.constraint(equalToConstant: 24).isActive = true

nameText.topAnchor.constraint(equalTo: loginSegmentedControl.bottomAnchor, constant: 8).isActive = true
nameText.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 22).isActive = true
nameText.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -22).isActive = true


emailTopAnchor = emailText.topAnchor.constraint(equalTo: loginSegmentedControl.bottomAnchor, constant: 8)
emailTopAnchor?.isActive = true
emailText.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 22).isActive = true
emailText.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -22).isActive = true
emailText.heightAnchor.constraint(equalToConstant: 32).isActive = true

passwordText.topAnchor.constraint(equalTo: emailText.bottomAnchor, constant: 8).isActive = true
passwordText.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 22).isActive = true
passwordText.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -22).isActive = true
passwordText.heightAnchor.constraint(equalToConstant: 32).isActive = true

loginButton.topAnchor.constraint(equalTo: passwordText.bottomAnchor, constant: 8).isActive = true
loginButton.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 22).isActive = true
loginButton.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -22).isActive = true
loginButton.heightAnchor.constraint(equalToConstant: 50).isActive = true

}

}

這裡一樣新增兩個新function跟修改一個舊function

不過為了可以更新HomeController的navigationItem.title

先新增一個homeController的物件

然後把按下註冊/登入按鈕的動作從舊的handleRegister換成新增的handleLoginRegister

handleLoginRegister裡面用loginSegmentedControl所選擇的是login還是register來決定要呼叫哪個function

如果是登入就呼叫新增的第二個functionhandleLogin來跟Firebase做登入的動作以及剛剛提到的更新navigationItem.title

如果是註冊就呼叫之前寫的handleRegister

但這邊也對handleRegister做了點修改,首先是多傳了name這個值

再來是註冊成功也會去修改homeController的navigationItem.title

不過跟handleLogin裡面直接呼叫fetchUserSetNavBarTitle不同的是

因為註冊時自己就有name這個數值,就不需要多跟Firebase要一次資料了

所以直接把要傳出去註冊的name拿來用就好

來看看完成品吧

Support

Comments

2017-07-15

⬆︎TOP