原文:《Start Developing iOS Apps Today》html
入口函數main.mios
#import <UIKit/UIKit.h> #import "XYZAppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool
{ return UIApplicationMain(argc, argv, nil, NSStringFromClass([XYZAppDelegate class])); } }
The call to UIApplicationMain
creates two important initial components of your app:canvas
UIApplication
class, called the application object.XYZAppDelegate
class, called the app delegate
XYZAppDelegate.hwindows
#import <UIKit/UIKit.h> @interface XYZAppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @end
XYZAppDelegate.m設計模式
#import "XYZAppDelegate.h" @implementation XYZAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end
During a significant runtime event—for example, app launch, low-memory warnings, and app termination—the application object calls the corresponding method in the app delegate, giving it an opportunity to respond appropriately. You don’t need to do anything special to make sure these methods get called at the correct time—the application object handles that part of the job for you.api
Even though a view instance can have multiple subviews, it can have only one superview.架構
At the top of the view hierarchy is the window object. Represented by an instance of the UIWindow
class, a window serves as the basic container into which you can add your view objects for display onscreen.app
A view controller isn’t part of the view hierarchy and it’s not an element in your interface.iphone
Each content view hierarchy that you build in your storyboard needs a corresponding view controller, responsible for managing the interface elements and performing tasks in response to user interaction. This usually means writing a customUIViewController
subclass for each content view hierarchy. If your app has multiple content views, you use a different custom view controller class for each content view.ide
注:一個界面對應一個View和一個View Controller?
A navigation controller manages transitions backward and forward through a series of view controllers.
The first item added to the stack becomes the root view controller and is never popped off the stack. Other view controllers can be pushed on or popped off the navigation stack.
Specifically, navigation controller presents a navigation bar—the view at the top of the screen that provides context about the user’s place in the navigation hierarchy—which contains a back button and other buttons you can customize.
You generally don’t have to do any work to pop a view controller off of the navigation stack; the back button provided by the navigation controller handles this for you. However, you do have to manually push a view controller onto the stack. You can do this using storyboards.
It’s important to make sure that one of the view controllers is marked as being the initial view controller.
File. Lets you specify general information about the storyboard.
Quick Help. Provides useful documentation about an object.
Identity. Lets you specify a custom class for your object and define its accessibility attributes.
Attributes. Lets you customize visual attributes of an object.
Size. Lets you specify an object’s size and Auto Layout attributes.
Connections. Lets you create connections between your interface and source code.
There are several types of segues you can create:
Push. A push segue adds the destination view controller to the navigation stack. Push segues may only be used when the source view controller is connected to a navigation controller.
Modal. A modal segue is simply one view controller presenting another controller modally, requiring a user to perform some operation on the presented controller before returning to the main flow of the app. A modal view controller isn’t added to a navigation stack; instead, it’s generally considered to be a child of the presenting view controller. The presenting view controller is responsible for dismissing the modal view controller it created and presented.
Custom. You can define your own custom transition by subclassing UIStoryboardSegue
.
Unwind. An unwind segue moves backward through one or more segues to return the user to an existing instance of a view controller. You use unwind segues to implement reverse navigation.
注:模態對話框(Modal Dialogue Box),是指在用戶想要對對話框之外的應用程序進行操做時,必須首先對該對話框進行響應。如單擊【肯定】或【取消】按鈕等將該對話框關閉
注:經過限制各邊距來實現佈局的屏幕適應
In the outline view for your interface, select Table View under Table View Controller.
With the table view selected, open the Attributes inspector in the utility area.
In the Attributes inspector, choose Static Cells from the pop-up menu next to the Content option.
Three empty table view cells appear in your table view.
In the outline view or on the canvas, select the top cell.
In the Attributes inspector, choose Basic from the pop-up menu next to the Style option.
The Basic style includes a label, so Xcode creates a label with the text 「Title」 in the table cell.
In the outline view or on the canvas, select the label.
In the Attributes inspector, change the text of the label from 「Title」 to 「Mow the Lawn.」 For the change to take effect, press Enter or click outside the utility area.
Alternatively, you can edit a label by double-clicking it and editing the text directly.
Repeat steps 4–7 for the other cells, giving them text for other likely to-do items.
Create enough cells so that the items more than fill the screen. You can create new cells by copying and pasting them or by holding down the Option key when dragging a cell.
In the outline view, select Table View Controller.
With the view controller selected, choose Editor > Embed In > Navigation Controller.
In the outline view or on the canvas, select Navigation Item under Table View Controller.
Navigation bars get their title from the view controller that the navigation controller currently displays—they don’t themselves have a title. You set the title using the navigation item of your to-do list (the table view controller) rather than setting it directly on the navigation bar.
In the Attributes inspector, type My To-Do List
in the Title field.
If necessary, open the Object library.
Drag a Bar Button Item object from the list to the far right of the navigation bar in the table view controller.
A button containing the text 「Item」 appears where you dragged the bar button item.
In the outline view or on the canvas, select the bar button item.
In the Attributes inspector, find the Identifier option in the Bar Button Item section. Choose Add from the Identifier pop-up menu.
The button changes to an Add button (+
).
On the canvas, select the Add button.
Control-drag from the button to the add-to-do-item view controller.
Choose 「push」 from the shortcut menu.
In the outline view or on the canvas, select the text field.
On the canvas, open the Resolve Auto Layout Issues pop-up menu , and choose Update Constraints.
Alternatively, you can choose Editor > Resolve Auto Layout Issues > Update Constraints.
The constraints are updated and the Xcode warnings disappear.
In the outline view or on the canvas, select the segue from the table view controller to the add-to-do-item view controller.
In the Attributes inspector, choose Modal from the pop-up menu next to the Style option.
Choose File > New > File (or press Command-N).
On the left of the dialog that appears, select the Cocoa Touch template under iOS.
Select Objective-C Class, and click Next.
In the Class field, type AddToDoItem
after the XYZ
prefix.
Choose UIViewController
in the 「Subclass of」 pop-up menu.
The class title changes to 「XYZAddToDoItemViewController.」 Xcode helps you by making it clear from the naming that you’re creating a custom view controller. That’s great, so leave the new name as is.
Make sure the 「Also create XIB file」 option is unselected.
Click Next.
The save location will default to your project directory. Leave that as is.
The Group option will default to your app name, ToDoList. Leave that as is.
The Targets section will default to having your app selected and the tests for your app unselected. That’s perfect, so leave that as is.
Click Create.
In the project navigator, select Main.storyboard
.
If necessary, open the outline view .
In the outline view, select the 「View Controller – Add To-Do Item」 view controller.
Click the disclosure triangle next to the 「View Controller – Add To-Do Item」 scene to show the objects in your scene. The first one should be the view controller. Click it to select it. Notice that the scene row has a different icon from the view controller row.
With the view controller selected, open the Identity inspector in the utility area.
The Identity inspector appears at the top of the utility area when you click the third button from the left. It lets you edit properties of an object in your storyboard related to that object’s identity, such as what class it is.
In the Identity inspector, open the pop-up menu next to the Class option.
You’ll see a list of all the view controller classes Xcode knows about. The last one in the list should be your custom view controller, XYZAddToDoItemViewController
. Choose it to tell Xcode to use your view controller for this scene.
In the project navigator, open XYZToDoListTableViewController.h
.
Add the following code below the @interface
line:
- (IBAction)unwindToList:(UIStoryboardSegue *)segue;
In the project navigator, open XYZToDoListTableViewController.m
.
Add the following code below the @implementation
line:
- (IBAction)unwindToList:(UIStoryboardSegue *)segue
{
}
In the project navigator, select Main.storyboard
.
On the canvas, Control-drag from the Cancel button to the Exit item in the add-to-do-item scene dock.
unwindToList:
from the shortcut menu.The action message is a selector defined in source code, and the target—the object that receives the message—is an object capable of performing the action, typically a view controller. The object that sends the action message is usually a control—such as a button, slider, or switch.
注:按下按鈕,調用ViewController類的方法就是一種Target-Action模式,Sender是按鈕,Target是ViewController,Action是被調用的方法。
The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate may respond to the message by updating the appearance (or state) of itself or of other objects in the app, and in some cases it will return a value that affects how an impending event is handled.
注:
delegating object:發出委託的對象
delegate:被委託的對象
delegating object通常會有一個delegate的成員變量,delegating object發出消息給delegate,告訴它delegating object即將處理或已經處理的事件,delegate會對該消息作出反應,有時候會返回一個值告訴delegating object即將發生的事件如何處理。
Xcode already made ViewController
the delegate of the Controller when you configured it in the storyboard.
好比使用StoryBoard時,文本框類中的delegate變量會自動指向自身的ViewController。當按下鍵盤的Return鍵時,文本框發出消息textFieldShouldReturn給delegate,即ViewController,若Viewcontroller實現了textFieldShouldReturn的方法,那麼就會響應該消息,使文本框失去焦點而達到隱藏鍵盤的目的(爲何要使用delegate?由於文本框本身不能處理textFiledShouldReturn)。
delegate是一種架構設計模式。 在iOS中,它是經過@protocol 來實現的。舉一個經過協議來實現委託的例子(轉自ios中關於delegate(委託)的使用心得)。我想買個手機,因此我有個buyPhone 方法,可是我不知道到誰那買手機,因此把這個需求發佈出去(聲明這個協議),若是有賣手機的商人(也就是說他能實現buyPhone這個方法)看到,他就會接受個人委託,(在商人本身的類中聲明該協議並實現buyPhone方法),那麼個人委託對象就指向了這個商人(個人類成員變量delegate存的是對該商人的引用),當我要買手機的時候,直接找他就好了(發送buyPhone消息給本身的類成員變量delegate)。
協議是在delegating object中制定的,即@protocol的內容寫在delegating object中;而delegate負責遵循該協議,即寫的是<Mydelegate>。
Me.h大概長這樣
@protocol MyDelegate -(void)buyPhone:(NSString *)phoneType money:(NSString *)money; @end @interface Me : NSObject { id<MyDelegate> delegate; } @property(assign,nonatomic)id<MyDelegate> delegate; @end
商人類的頭文件Business.h
#import <Foundation/Foundation.h> #import "Me.h" @interface Business : NSObject<MyDelegate> @end
商人類的實現文件Business.m
#import "Business.h" @implementation Business -(void)buyPhone:(NSString *)phoneType money:(NSString *)money { NSLog(@"手機有貨,這個價錢賣你了,發貨中!!"); } @end
當我指定買這個商人的手機的時候
delegate = business; //business爲Business的一個實例
買手機的函數大概長這樣
-(void)willBuy { [delegate buyPhone:@"iphone 4s" money:@"4888"]; }
這樣就應該很清楚Delegate是怎麼回事了。我要買手機的時候,將delegate指向某個商人,Me發送buyPhone消息給delegate,即那個商人,那個商人接收到消息以後,因爲實現了buyPhone方法,因此會調用該方法。
委託方法一般包括3種動詞:should、will、did。
should表示一個動做發生前,一般帶有返回值,能夠在動做發生以前改變對象狀態。
will在動做發生前,委託能夠對動做作出響應,但不帶有返回值。
did在動做發生後作出的響應。
#import "XYZToDoItem.h" @interface XYZToDoItem () @property NSDate *completionDate; @end @implementation XYZToDoItem @end
注:
Class Extension v.s. Class Category
Class Extension只能在.m中聲明(通常在本類的實現文件的最上方),@interface後面添加類名和空括號,便可補充方法也可補充屬性。
Class Category傾向於寫在獨立的文件中(聲明寫在新的.h,實現寫在新的.m),@interface後面添加類名和帶分類名的括號,只能在Category中補充方法。
To make something a data source of the table view, it needs to implement the UITableViewDataSource
protocol.
To have a functioning table view requires three methods.
The first of these isnumberOfSectionsInTableView:
, which tells the table view how many sections to display.
The next method, tableView:numberOfRowsInSection:
, tells the table view how many rows to display in a given section.
The last method, tableView:cellForRowAtIndexPath:
, asks for a cell to display for a given row.
Interface Builder takes the static cells you configured and converts them all into prototypes.
注:利用一個Static Cell看成原型,改Table的其餘元素的樣式均按照該Static Cell來產生。
In the project navigator, select XYZToDoListTableViewController.m
.
Add the following lines to the end of the file, just above the @end
line:
#pragma mark - Table view delegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { }
You want to respond to taps but not actually leave the cell selected. Add the following code to deselect the cell immediately after selection:
[tableView deselectRowAtIndexPath:indexPath animated:NO];
Search for the corresponding XYZToDoItem
in your toDoItems
array.
XYZToDoItem *tappedItem = [self.toDoItems objectAtIndex:indexPath.row];
Toggle the completion state of the tapped item.
tappedItem.completed = !tappedItem.completed;
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
Before a segue executes, the system gives the view controller involved a chance to prepare by calling prepareForSegue:
.
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { }
找到XXXAppDelegate.m文件中的didFinishLaunchingWithOptions函數,將
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
這句註釋掉便可。
運行提示:Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier ListPrototypeCell1 - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'.
通過摸索,發現TableView的鏈接檢視器中的outlets下dataSource和delegate都沒有綁定TableViewController(另外一個跟着教程走的成功運行的程序卻綁定了),不過問題好象不在這裏。
而是TableViewCell屬性檢視器中的Identifier必須爲ListPrototypeCell,而後找到XXXViewController.m文件中的cellForRowAtIndexPath函數,檢查CellIdentifier的設置是否正確,名字也必定要是ListPrototypeCell。我還一直覺得能夠自定義,只要兩邊對應上就好了。
static NSString *CellIdentifier = @"ListPrototypeCell";