项目档案

UIKit中的在线目录示例

我们在这堂课中要看的示例赢博体育是我们之前在SwiftUI中实现的相同的在线目录赢博体育。这次我将在UIKit中重现那个赢博体育的功能。

赢博体育程序的初始视图是一个登录页面,用户可以使用该页面登录系统或创建新帐户。

一旦用户登录,他们将被带到目录列表页面,在那里他们可以看到他们创建的目录条目。

要创建一个新的目录条目,用户将单击右上角的+按钮。这将把他们带到第三个视图,他们可以在其中输入新用户的详细信息。

Directory类

与SwiftUI版本一样,这个版本的赢博体育程序也有一个Directory类,作为到服务器的网关。

如果您仔细观察这个版本中的Directory类,您会注意到几个重要的区别。

下面是一个典型的服务器交互方法的示例。这是我们将调用的将新用户发布到服务器的方法的代码。

func newUser(成功回调:@escaping () -> Void,失败投诉:@escaping () -> Void){让jsonData = try?JSONEncoder().encode(user) let urlStr = "https://cmsc106.net/directory/users" let url = url (string: urlStr) var request = URLRequest(url: url!) request。httpMethod = "POST"请求。setValue("application/json", forHTTPHeaderField: "Content-Type")请求。httpBody = jsonData让任务= URLSession.shared。dataTask(with: request) {data, response, error in guard error == nil,(response as!)HTTPURLResponse)。statusCode == 200 else {DispatchQueue.main.async {complain()} return} self.user.key = try!JSONDecoder().decode(String.self, from: data!)DispatchQueue.main.async {self. saveuser ()}people = [] DispatchQueue.main.async {callback()}} task.resume()}

以下是关于这段代码需要注意的一些要点:

的LoginController

我们的赢博体育程序的初始视图是登录视图。该视图的控制器类包含链接到New User和Login按钮的操作方法。下面是New User按钮动作方法的代码:

@IBAction函数newUser(_来源:UIButton) {directory.user.name = user.text!Directory.user.password = password.text!目录中。newUser(成功:{self. gotomain()},失败:{self. gotomain()}。showAlert(message: "Add new user failed")})}

注释@IBAction将此方法指定为按钮的操作方法。我们将New User按钮链接到故事板中的这个方法,方法是从按钮control-drag到故事板中的视图控制器图标,然后从控制器中可用的动作方法列表中选择这个方法。

这个方法调用Directory类的newUser()方法,并向它传递一个成功回调和一个失败回调。成功回调调用这个方法:

函数goToMain() {let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil) let mainViewController = storyBoard。实例化viewcontroller (withIdentifier: "Directory")UINavigationController let listView = mainViewController.viewControllers.first as!ViewController列表视图。directory = mainViewController目录。modalPresentationStyle = . fullscreen self。present(mainViewController, animated: true, completion: nil)}

在我们的第一个示例UIKit赢博体育中,我展示了如何在故事板中设置segue用于从一个视图导航到另一个视图。在这段代码中,我们也使用了segue。这一次的不同之处在于,我们将通过调用present()方法以编程方式设置segue。在调用present()之前,我们需要通过请求storyboard对象为我们创建视图控制器来访问我们想要去的视图控制器。一旦我们访问了新的视图控制器,我们就可以给它传递一个指向我们一直在使用的Directory对象的引用。

主视图控制器

用户登录或创建新用户后,我们将把他们带到显示其目录条目的视图中。这个视图的视图控制器是ViewController类。

关于这个视图要注意的第一件事是它子类化了UITableViewController而不是通常的UIViewController。我这样做是因为这个视图的主要工作是显示目录条目列表。一旦我们从UITableViewController中派生出我们的类,我们就可以访问许多管理列表的成员函数。下面是这些方法的代码。

overoverfunc tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{返回directory.getCount()} overoverfunc tableView(_ tableView: UITableView, cellForRowAt indexPath: indexPath) -> UITableViewCell{//获取一个新的或回收的单元格let cell = UITableViewCell(style: .value1, reuseIdentifier: "UITableViewCell") let person = directory.getPerson(at:indexPath.row) cell. textlabel ?text = person.name cell.detailTextLabel?覆盖函数tableView(_ tableView: UITableView,提交editingStyle: UITableViewCell)。EditingStyle, forRowAt indexPath: indexPath){//如果表视图请求提交一个删除命令…如果editingStyle == .delete{//从目录目录中删除项目。removePerson(at: indexPath.row) {tableView.reloadData()}}

这三个方法都是成功管理UITableView所必需的,UITableView是UIKit中SwiftUI List组件的等效。第一个方法返回列表中的行数。第二个方法是最重要的:它根据行号为表视图生成单元格。UITableView期望的单元格是UITableViewCell对象。通过在单元格的textLabel和detailTextLabel属性中设置文本,我们可以显示人员的姓名和办公室。第三个方法处理列表上的编辑操作。对于这个赢博体育程序,我们需要支持的一个编辑操作是删除操作,该操作将在用户滑动时调用,以删除列表项。

这个主视图还具有到第三个视图的segue。这个segue链接到storyboard中的+按钮。下面是视图控制器中的prepare()方法,它将在用户触发segue时被调用:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {switch segue。id {case "AddPerson":让controller = segue.destination为!PersonController currentPerson = Person(name:"",office:"")控制器。person = currentPerson default: preconditionFailure(“意外的segue标识符”)}}

这里的策略是在转到下一个视图之前创建新的Person对象。我们在下一个视图的视图控制器中存储了对那个新人物的引用,并在我们的一个成员变量中存储了对那个新人物的引用。

当我们从第三个视图返回时我们会检查视图控制器中是否有一个新的person。如果是,我们将告诉Directory添加该人员。addPerson()方法的回调调用一些代码,告诉我们嵌入的UITableView重新加载它的数据。赢博体育这些代码都出现在viewWillAppear()方法中,当我们从第三个视图返回后再次出现时,系统将调用该方法:

override func viewWillAppear(_ animated: Bool) {super.viewWillAppear(animated)如果让p = currentPerson {directory.addPerson(p) {self. tableview . reloaddata () self。currentPerson = nil}}

第三个视图的控制器

以下是create new person视图控制器的完整代码:

类PersonController: UIViewController {@IBOutlet var nameField: UITextField!@IBOutlet var officeField: UITextField!var person: person !@IBAction func dismissKeyboard(_ sender: UITapGestureRecognizer) {nameField. resignfirstresponder () officeField.resignFirstResponder()} override func viewWillAppear(_ animated: Bool) {super.viewWillAppear(animated) nameField。text = person.name officeField。文本=人。{super.viewWillDisappear(animated) person.name = nameField.text!的人。office = officeField.text!}}

正如我在上面一节中所描述的,第二个视图将创建一个新的Person对象,并将该对象存储在我们的Person成员变量中。当用户单击顶部栏中的返回链接以离开该视图并返回到第二个视图时,系统将调用viewWillDisappear()方法。该方法中的代码将新人员的姓名和办公室从文本字段复制到person对象中。由于我们使用了对第二个视图存储在其currentPerson成员变量中的同一个Person对象的引用,因此第二个视图将看到该更改。