IOS Apprentice Chinese version – start with iOS development from 0 – seventeenth

Edit existing to-do names

Adding new to-do items to app to the list is a huge step forward for you, but usually with the addition, there are two other operations that need to be implemented, that is:

1, delete the “do” project (by sweeping a row to delete, we have implemented in the front)

2 edit existing to-do items

Edit the existing project is very useful, if you want to do with a typo or rename the project you need to modify, need to use the edit function.

Maybe you can do a new interface to complete the function, but you will find this new function and do the interface does not have what difference, the only difference is that the first character exists in the text box, and the new beginning of the text box is empty.

So we reuse the new add in interface so that it has the ability to modify the name of the existing project.

Preview after IOS Apprentice Chinese version - start with iOS development from 0 - seventeenth

When the user clicks the Done button, you do not create a new CheclistItem object, but simply modify the text of the existing CheclistItem object.

You should also notify the delegate that the changes have been made so that the delegate will update the corresponding table view cell in the list.

Exercise: what kind of changes do we need to implement this feature? Can you make a list?

Answer: 1. When editing an item, the interface needs to be renamed Edit Item (now Add Item)
2, and you must be able to read to an existing ChecklistItem object.
3, you must put the text of this ChecklistItem object in the text box.
4, when the user clicks the Done button, you should not add a new ChecklistItem object, but instead update the edited one.

There are some user interface issues that need to be addressed, such as how do users open the interface for editing projects? Most of the app are the direct click on a line to complete the action, but in the US app, click the action has been taken, it is used to control the switch of the checkmark.

To solve this problem, you need to modify the UI design first.

When a line has two functions, the standard approach is to use the button (detail disclosure button) to complete the function.

IOS Apprentice Chinese version - start with iOS development from 0 - seventeenth
details button

Click on a line, or the implementation of the original action, the switch is to control the checkmark in our app, and when you click the details button, open the edit project interface.

Up: is there an alternative approach is to click on the left, only the checkmark area, is used to switch the checkmark, click on this line of other places, open the edit project interface.
and some app do this, you can trigger the entire screen as editable, and then edit the project one by one. Which method you use depends on which method is most beneficial to your data model.

Open the story template, select table view cell, and then go to the property inspector, find the Accessory option, and select Detail Disclosure (Note: Detail, Disclosure, not Detail) option.

Then the checkmark will be a blue exclamation + A is greater than the number to replace the icon button. This means that you have to re select a place for the checkmark.

Drag and drop a new label into the cell, and make the following settings:

Text: tick (option+v can enter the symbol)

Font: Helvetica, Neue, bold, size 22


If option+v does not have this symbol, you can select Edit-&gt from the Xcode top menu; Emoji & Symbols. Then in the pop-up window search bar enter “check”, select a checkmark, or select any graphics you love. (note that when you do this, double click on the tag and proceed to the state where you can enter text. Otherwise, these special symbols may not be displayed correctly on some phones.)

IOS Apprentice Chinese version - start with iOS development from 0 - seventeenth
inserts the Emoji symbol

Readjust the position and size of the two labels. Do not overlap each other or cover the blue exclamation mark on the right.

The redesigned prototype cell should look like this:

New cell design for IOS Apprentice Chinese version - start with iOS development from 0 - seventeenth

Open ChecklistViewController.swift and change configureCheckmark (for:with:) to:

Func configureCheckmark (for cell: UITableViewCell with, item: ChecklistItem) {let label = cell.viewWithTag (1001) as! UILabel if item.checked {label.text} {else = "V" = "label.text"}}

Now we do not modify the accessory property of the cell, but instead modify the text of the new label.

Run app, you will see the transfer of the checkmark from right to left, and there were more information with a blue exclamation button on the right side. Click on a line switch checkmark, click the details button is not.

The effect after running IOS Apprentice Chinese version - start with iOS development from 0 - seventeenth

Now, let’s start working on the edit interface after clicking the details button. This is very simple, because the Interface Builder allows you to add a transition for the details button.

Open the story template. Select table view cell, and press Ctrl to drag to the next Navigation Controller. In the pop-up window, select the Present Action under section Accessory Modally.

IOS Apprentice Chinese version - start with iOS development from 0 - seventeenth
adds transitions for the details button

Now from the Checklists interface to the navigation bar has two transitions, one is used for button, a button for detailed information in cell.

IOS Apprentice Chinese version - start with iOS development from 0 - seventeenth
two transitions

To enable app to distinguish between two transitions, we have to give them different identities, ID.

Select the new transition arrow, then open the property inspector and enter EditItem in identifier.

If you run app, click the blue exclamation mark button to open the new add in interface, but you won’t have any effect if you click the Cancel button at this point.

Exercise: think about why?

Answer: you have not configured to delegate yet. We must remember that you are in prepare (for:sender:) is entrusted, but only button AddItem turning setting you need to entrust, to do the same for the EditItem field.

Before you fix this problem, you need to enable the new add in interface to have the ability to edit ChecklistItem objects.

Open AddItemViewController.swift and add a new instance variable:

VaR, itemToEdit:, ChecklistItem?

This variable is used to contain the ChecklistItem object that the user is ready to edit. But when you add a new to-do item, itemToEdit will be nil, which is how the view controller can distinguish between additions and edits.

Because itemToEdit will be nil, so it must be optional, that’s the question mark function.

Or add the viewDidLoad () method in AddItemViewController.swift:

Override, func, viewDidLoad (), {super.viewDidLoad (), if, let, item = itemToEdit, {title = Edit, Item, textField.text = item.text}}

Recall that viewDidLoad () is the party view controller that is called by the UIKit when it is loaded from the story template, when the interface is not yet displayed on the screen. This gives you time to configure the user interface.

In edit mode, that is, when itemToEdit is not nil, you change the name of the navigation bar “Edit Item””. You do this by changing the title attribute of the navigation bar.

Each view controller has several built-in properties, and title is one of them. The navigation controller automatically changes the name of the navigation bar after reading the value of the title.

You also set the text value of the text box with the value of item.

If let
you can’t use the optional variables like normal variables. For example, if you write a sentence like this directly: textField.text = item.text, the Xcode compiler will give you an error, “Value, of, optional, type, ChecklistItem?” Not (unwarped type ChecklistItem type variable value without unpacking) “this is because the itemToEdit
is ChecklistItem type variable.
want to use it, you must first unpack. Through a special syntax to complete this function: if let temporaryConstant = optionalVariable temporaryConstant now contains the unwrapped {/ / value / / of the optional variable} if the type is not nil, if the condition is true, the if statement in the code is executed.
and some other methods can read the value of the variable type, but the use of if let is the most secure type: if no value, or is nil, then the if statement in the code will be automatically skipped. Can the
selection make you dizzy? Practice more, practice makes perfect, and everyone does. Selection is a feature of swift, and most mainstream languages do not have this function, and many developers spend a lot of effort here to understand it.
, though difficult to understand, can be selected to avoid null pointer errors and prevent your app from hanging up.

Now AddItemViewController has the ability to identify when to enter the editing interface. If itemToEdit has a ChecklistItem object, the interface will magically turn into an edit interface.

But where do you assign itemToEdit? It’s in transit, of course! The ideal place here is to assign values to variables and to configure everything before the screen is about to appear on the screen.

Open ChecklistViewController.swift and change prepare (for: sender:) for the following:

Override func prepare (for segue: UIStoryboardSegue sender: Any?) {if segue.identifier = = "AddItem" else if segue.identifier = = {...} {navigationController = "EditItem" let segue.destination as! UINavigationController let controller = navigationController.topViewController as AddItemViewController controller.delegate self if! = let indexPath = tableView.indexPath (for: sender as UITableViewCell! = items[indexPath.row]) {controller.itemToEdit}}}

As before, you read the navigation controller from the story template and call AddItemViewController using the topViewController property.

You also set the delegate property of the view controller so that you can get the notification when the user clicks the Cancel or Done button, and the thing here is exactly the same as the “AddItem” transition.

The more interesting part is the newly added part:

If, let, indexPath = tableView.indexPath (for:, sender, as, UITableViewCell) {controller.itemToEdit = items[indexPath.row]

The prepare (for:sender:) method has a parameter called sender. This parameter contains a reference to the control transition, in our case, when the details button of table view cell is clicked.

You set up a UITableViewCell object to locate the line number of the clicked line, the corresponding index-path, by using tableView.indexPath (for:).

The return type of tableView.indexPath (for:) is IndexPath, which is optional, which means that it may return nil. This is why you need to unpack the reason before use it with if let.

Once you have a line number, you can get the ChecklistItem object that needs to be edited, and you assign it to the itemToEdit attribute of AddItemViewController at the same time.

View controller between each other to send data
, we talked about the interface B (Add/Edit Item screen), return data to the interface A (Checklists screen) is completed by commissioned.
, but here you pass data from the interface A to the interface B, that is to say, to pass a ChecklistItem object for editing.
data is passed between the view controllers in two ways:
1, from A to B. When the interface A opens the interface B, A gives the data needed by the B. You simply create an instance variable in the B view controller, and then assign the variable to the A when you transition to B, which is usually done in prepare (for:sender:).
2, from B to A. B returns data to A, and you need to use the delegate. The figure below illustrates the
A to send data to the B, how to B variables, and how B was commissioned by the A to return the data:
iOS Apprentice中文版-从0开始学iOS开发-第十七课

I hope you can understand the initial transfer of data between the view controller. In our course, there will be several such scenes, please be sure to master this knowledge. The essence of
‘s iOS app is to create a view controller and pass data in it, and you have to make this your second instinct.

After these steps, you can run the app, click the button will open the new to do interface, and click on a line on the blue exclamation button will pop up the editing interface, the interface already exists to edit entries:

iOS Apprentice中文版-从0开始学iOS开发-第十七课
editing to-do list

Here’s a little problem: the Done button on the navigation bar was disabled at first, because you originally set it off in the story template and disabled it.

Open AddItemViewController.swift and add a line of code to go in:

Override func viewDidLoad (super.viewDidLoad) let (if) {item = itemToEdit {title = "Edit Item" textField.text = item.text doneBarButton.isEnabled = true / / add a}}

In edit mode, you can safely put the Done button in the available state at the beginning, because the Done is automatically disabled as the text is deleted.

The real problem is not here. For now, when you run app, edit a row, click the Done button, and you will find that the original line has not been modified. Instead, a new line has been added.

You haven’t written the code to copy and update the data model, so the delegate will assume that your purpose is to add a new line.

To solve this problem, you need to add a new method to the trust agreement.

Open AddItemViewController.swift and add the following code in the protocol:

Func addItemController (controller: AddItemViewController didFinishEditing item: _, ChecklistItem)

Now the whole protocol looks like this:

Protocol AddItemViewControllerDelegate: class func addItemControllerDidCancel (controller: _ {AddItemViewController (func) addItemController controller: AddItemViewController didFinishAdding _, item: ChecklistItem addItemController (func) controller: AddItemViewController didFinishEditing item: _, ChecklistItem)}

Now, when the user clicks the Done button, there are two ways to respond.

When a new row is added, call didFinishAdding, and call didFinishEditing when the line is edited.

These two different scenarios can be handled separately by calling different delegate methods.

Open AddItemViewController.swift and change the done () method to:

@IBAction func done (if let) {item = itemToEdit {item.text = textField.text! Delegate?.addItemController (self didFinishEditing: item)} else {let item = ChecklistItem (item.text) = textField.text item.checked = false! Delegate?.addItemController (self didFinishAdding: item)}}

First, we check whether itemToEdit belongs to contain an object, you should understand that if let is unpacking type variable.

If the optional variable is not empty, you put an existing ChecklistItem object in the text box and call the new didFinishEditing method.

If it's empty, add a new record to it, just like we did before.

Try running app, and you’ll see a surprise, APP hung up.

Xcode says, "Build Failed", but there is no error in AddItemViewController.swift. Why is that?

You can see an error message in the Xcode problem Navigator (Issue navigator):

IOS Apprentice Chinese version - start with iOS development from 0 - seventeenth
error message

The error message occurred in ChecklistViewController because it did not execute the protocol method. This is not surprising, because you just added the didFinishEditing method to the protocol, but you haven’t told the view controller yet who will play the delegate role.

Up: the Xcode error information for this version of me: Method’addItemController (_: didFinishAdding:) has different argument names from ‘those required by protocol…, this is a relatively strange error message. It does not accurately describe what went wrong, simply reflecting Swift’s confusion about the current situation.
when you make your own app, you may be faced with strange information that cannot be described by Swift. As experience increases, you become familiar with these situations. Swift’s compiler has just come out, and it needs to be perfected.

Add the following code in ChecklistViewController.swift and you can make a history of the error just now:

Func addItemController (controller: AddItemViewController didFinishEditing _, item: ChecklistItem) {if let index = items.index (of: item) {let indexPath = IndexPath (row: index, section: 0) if let cell = tableView.cellForRow (at: indexPath) {configureText (for: cell, with: item)}} dismiss (animated: true, completion: Nil)}

In this way, ChecklistItem has new text, and cell is already in table view. You just need to update the tags in table view cell.

This new method is used to find the ChecklistItem object corresponding to the cell, and then update the tag through the configureText method.

The first line statement is new to us:

If, let, index = items.index (of:, item)

You need to read the required IndexPath from the cell, and first you need to find the line number of the ChecklistItem object. The line number and ChecklistItem are the same in the items array as the index value, and then you return the index through the index (of) method.

Although this does not happen in our app, but the theory in an array of an object does not exist, this time index (of) will return to nil, so it is the return value of the type, so we use if let to unpack it.

Try running app, oh, I think I’m too impatient. Xcode gives another error: Cannot, invoke, index, with, an, argument, list, of,, type, blah, blah, blah. What’s the matter?

This is because you cannot use index (of) on any object and use it only on objects of the same kind. Index (of) compares the object you look for in the array in some way to the object line that calls it, to see if they are equal.

Your ChecklistItem object does not now have this function. There are several ways to deal with this problem. Let’s use the simplest one.

Add something to the line in the class declaration of ChecklistItem.swift:

Class, ChecklistItem:, NSObject {

If you’ve used Object-C before, then you should be very familiar with NSObject.

Almost all objects in Object-C are based on NSObject. This is the most basic block of code provided by iOS, which provides a large number of useful basic functions that Swift objects do not have.

When you write code with Swift, you don't need to talk about NSObject most of the time, but it's a must at the moment.

By building ChecklistItem over NSObject, you can compare it safely. Later, when we learn how to store checklist objects, you must also convert it to NSObject.

Run app, try the function, everything is OK now.

Refactoring code

Now that you have a app, you can implement new to-do lists and edit events, and that’s great.

But I found the name of AddItemViewController is not appropriate, after all this is now carrying the new interface to do and edit the existing two projects, we should rename it to ItemDetailViewController.

Now we have good news and bad news. Which one do you want to hear first?

The good news is that Xcode has a special menu for refactoring the source code, including the rename tool, which you can find in Edit->. Refactor.

The bad news is that in Xcode 8, this feature does not support the Swift language and only supports Object-C, so you can’t use it, bad reviews.

So our only option is to do it manually, and fortunately, Xcode has a very handy search and replace feature. We’ll do this job step by step.

1, open the search navigation, engineering navigation interface on the third buttons.

IOS Apprentice Chinese version - start with iOS development from 0 - seventeenth
is the one with the magnifying glass Icon

2, click Find, switch to Replace (replace).

3. Switch the Ignoring Case in the figure above to Matching Case.

4. Enter AddItemViewController in the search box. Important: make sure your spelling is correct.

5. Enter ItemDetailViewController in the replace box

IOS Apprentice Chinese version - start with iOS development from 0 - seventeenth

6, click the Enter key on the keyboard to start the search, this operation will not be replaced.

The search results will return all relevant matches. You should see two swfit source files and Main.storyboard.

IOS Apprentice Chinese version - start with iOS development from 0 - seventeenth
search results

7 Click the Preview button. Xcode opens an interface that contains the parts that will be replaced in each file.

IOS Apprentice Chinese version - start with iOS development from 0 - seventeenth
replace result Preview

Compare each pair carefully, make sure you don’t replace them and don’t replace them. The substitution was simply to replace the word “AddItemViewController” with “ItemDetailViewController”, including the story template.

8, click the Replace button and pray. If Xcode needs you to confirm, click Continue.

9, in the engineering navigator, select AddItemViewController.swift, then click again, two clicks not too fast, and then you can rename the file.

The new name is: ItemDetailViewController.swift

It’s not over yet, and you’ll have to rename the previous delegate agreement.

1, switch to the search navigator again

2, make sure that you are in Replace mode (if not click Find to switch to Replace)

3. Make sure you are in Matching Case mode (if not, click Ignoring Case to toggle)

4, enter the search text addItemViewController, note that the beginning is lowercase a

5, enter the replacement text itemDetailViewController, note that the beginning is lowercase I

6. Hit the return key on the keyboard.

IOS Apprentice Chinese version - start with iOS development from 0 - seventeenth
gets search results

The search results should contain only the names of the protocol delegate methods, each in two files, ChecklistViewController.swift and ItemDetailViewController.swift.

7, click Replace All to replace.

After the replacement, you can search again to confirm the result of the replacement. At this point, you should not find anything, because it has been replaced.

The protocol method in ItemDetailViewController.swift should now look like this:

Protocol ItemDetailViewControllerDelegate: class func itemDetailViewControllerDidCancel (controller: _ {ItemDetailViewController (func) itemDetailViewController controller: ItemDetailViewController didFinishAdding _, item: ChecklistItem itemDetailViewController (func) controller: ItemDetailViewController didFinishEditing item: _, ChecklistItem)}

Use the command+B key to recompile the following code, and if successful, the compiler will succeed.

Up: if the compiler error, then it must be a search and replace the wrong key, check again, especially sensitive, ItemDetailViewController in swift and itemDetailViewController are two completely different objects, letters to them at the beginning is not the same.

If you run a app crash, check the Custom Class in the Add Item of the ItemDetailViewController in the story template. Sometimes Xcode misses this place when searching for replacements.

Since you’ve made a lot of changes, it’s best to clean up the cache first, and then cache cleanup through the Xcode menu Product-&gt, Clean.

If there are no problems, you can rerun app and test all the scenes. Make sure everything is working properly. (if the Xcode compilation is normal, but still shows a false error, then try to turn off the Xcode and try again)

Iterative development (Iterative Development)
if you think our development process in the course of this too much, why not step it? Make so many detours. The idea is incorrect.
when you start to achieve specific functions from a design, you will find a lot of problems not considered, so you need to practice constantly in the process of reconstruction of their code, finally achieve the ideal effect.
software development is one such kind of work.
at first you just finished a small piece of functionality and it didn’t seem to be a problem. Then you add another small part into it, and suddenly the unexpected problem arises. At this point, perhaps you will have to reverse the previous design and start all over again. You can’t repeat the behavior frequently until you have finished it.
software development is a continuous and meticulous process. So in our course, solution I will not give you the most perfect, but perfection through continuous modification to attain, and the details of each small details. Because real software development is such a job.
and you will start from 0 until you complete a complete app and continue to solve problems in the process, just like any professional does.
does not exist in the software design of the field sweep down irresistibly from a commanding height, like architectural drawings of something like that, I don’t believe in these design. Of course, it’s right to plan ahead, but you can’t plan it as a way of doing it. While I’m writing these tutorials, I’ll draw some sketches to figure out how these app should work. The effect of this job is remarkable, but it often has problems in the process of development, which makes me have to change my mind. It’s only a small app.
that doesn’t mean you don’t plan ahead, just don’t waste too much time on it.
all you have to do is simply start from a certain step until the problem gets stuck, then backtrack and find a solution to the problem. This is called iterative development, which is much faster and more efficient than planning a blueprint in advance.

Edit existing to-do names, adding new to-do items to app is a huge step forward to the list, but usually with new additions, there are two other operations that need to be implemented, that is:


protocol ItemDetailViewControllerDelegate: class {
    func itemDetailViewControllerDidCancel(_ controller: ItemDetailViewController)
    func itemDetailViewController(_ controller: ItemDetailViewController,didFinishAdding item: ChecklistItem)
    func itemDetailViewController(_ controller: ItemDetailViewController,didFinishEditing item: ChecklistItem)



如果你运行app崩溃的话,检查一下故事模版中Add Item这个界面的身份检查器中的Custom Class此时应该为ItemDetailViewController。有时在搜索替换时,Xcode会漏掉这个地方。



迭代开发(Iterative development)