引言
如果你从来没有接触过iOS开发,你可以看这篇文章,因为这篇文章就是给0基础的小白准备的。
项目结构
一个入门级iOS App的源代码的项目结构大致为以下结构。
css
YourProject
├── Classes
│ ├── main.m
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── SceneDelegate.h
│ ├── SceneDelegate.m
│ ├── MainViewController.h
│ ├── MainViewController.m
│ ├── MainViewController.storyboard
│ ├── SecondViewController.h
│ ├── SecondViewController.m
│ └── SecondViewController.storyboard
├── Info.plist
└── Assets.xcassets
├── AppIcon.appiconset
├── MyIcon1.imageset
└── MyIcon2.imageset
main.m
这是整个iOS App项目的入口。
objc
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char* argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
UIKit 是iOS的基础UI工具包。这里还指定了appDelegateClassName,入口类名为AppDelegate,相当于Android中的Application类。
AppDelegate.h
objc
#import <UIKit/UIKit.h>
#import "SceneDelegate.h"
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) SceneDelegate *scene;
@end
AppDelegate,即App代理,在里面声明了一个SceneDelegate场景代理。
AppDelegate.m
objc
#import "AppDelegate.h"
#import "SceneDelegate.h"
@interface AppDelegate()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
return YES;
}
#pragma mark - UISceneSession lifecycle
- (UISceneConfiguration*)application:(UIApplication*)application configurationForConnectingSceneSession:(UISceneSession*)connectingSceneSession options:(UISceneConnectionOptions*)options {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
}
- (void)application:(UIApplication*)application didDiscardSceneSessions:(NSSet<UISceneSession*>*)sceneSessions {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
@end
这里的方法声明最前面的-代表这是一个实例方法,而类方法则为+。实例方法的意思是说,要先创建一个属于这个类的对象,再用指针去指这个方法,即调用这个方法。类方法在Java等语言中又叫静态方法,是不需要创建这个类的对象,直接使用类名即可调用。最前面的()里面的为这个方法的返回值,如(void)表示无返回值,(UISceneConfiguration*)则表示返回的是一个UISceneConfiguration类型的指针。//为单行注释,在它后面的这一行的代码不会参与编译,仅方便程序员阅读和理解代码。
SceneDelegate.h
objc
#import <UIKit/UIKit.h>
@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
在.h文件定义了一个成员属性UIWindow类型的指针,这样可以在.m文件中包含这个头文件SceneDelegate.h,以直接使用window这个属性,而不需要重新定义。
SceneDelegate.m
Storyboard 是一个故事面板,承载着UI布局,后面我们也可以使用nib文件.xib定义UI界面。
objc
#import "SceneDelegate.h"
#import "MainViewController.h"
@interface SceneDelegate ()
@end
@implementation SceneDelegate
- (void)scene:(UIScene*)scene willConnectToSession:(UISceneSession*)session options:(UISceneConnectionOptions*)connectionOptions {
UIWindowScene *windowScene = (UIWindowScene *)scene;
UIWindow *window = [[UIWindow alloc] initWithWindowScene:windowScene];
NSLog(@"%@", NSStringFromCGRect(window.bounds));
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainViewController" bundle:nil];
UIViewController *controller = [storyboard instantiateInitialViewController];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller];
[window setRootViewController: navController];
[window makeKeyAndVisible];
self.window = window;
}
- (void)sceneDidDisconnect:(UIScene*)scene {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
- (void)sceneDidBecomeActive:(UIScene*)scene {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
- (void)sceneWillResignActive:(UIScene*)scene {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
- (void)sceneWillEnterForeground:(UIScene*)scene {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
- (void)sceneDidEnterBackground:(UIScene*)scene {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
@end
UIWindowScene你可以理解为存放界面的空壳,通过指定一个UIWindow来创建这个对象。UIWindow可以绑定一个根的UIViewController,根的UIViewController又可以有很多子的UIViewController,形成枝和叶 的树状结构。通过控制器UIViewController就可以创建UIStoryboard,也就是我们提到提到的故事面板。
MainViewController.h
objc
#import <UIKit/UIKit.h>
@interface MainViewController : UIViewController
@end
这里就不得不提到面向对象 编程了,这个对象不是你谈的那个对象。通过:继承父类UIViewController得到一个子类。你可以理解为抽象的概念具体了一点点,但还不够具体到能确定为一个个体。比如父类是玩具类,我细化概念为奥迪双钻玩具类,不是广告啊。奥迪双钻玩具类又可以细化为陀螺类或悠悠球类。这里赛车类表示不服,我赛车不值得一提吗?你买到的那个具体的陀螺,比如"玄冥寒鲛"就是一个对象。有了类的这个模板,我们可以理解为设计图,就可以创建无数个具体的对象。
MainViewController.m
objc
#import "MainViewController.h"
#import "SecondViewController.h"
@interface MainViewController ()
@property (weak, nonatomic) IBOutlet UIButton *btnStart;
@end
@implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)clickMyFirstButton:(id)sender {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"SecondViewController" bundle:nil];
UIViewController *controller = [storyboard instantiateInitialViewController];
[self.navigationController pushViewController:controller animated:YES];
}
@end
创建出界面显示了还不过瘾,那么我们可以跳转到另外一个界面。这里就需要用到UIViewController控制器类的对象,这里是一个导航控制器。通过调用它的pushViewController方法,来切换到另外一个界面SecondViewController显示。 由于控制器和界面是一对一绑定的,切换到那个控制器,就相当于切换到那个界面了。IBAction是一个行为类,在故事面板中直接拖拽连线即可绑定这个返回IBAction的方法,故事面板或.xib文件中就可以直接关联某块区域视图View的某种事件,比如点击事件。用户点击那个区域的视图,就会调用这个方法里面的代码,我们这里定义的是发生场景切换。
Info.plist
以key-value形式配置一些参数,比如使用宽松的网络策略允许不使用https请求,而使用http请求。
xml
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Assets.xcassets
Assets.xcassets目录下存放着项目的图片资源。其中AppIcon.appiconset管理着App在 iPhone、iPad等设备上不同尺寸的App桌面图标。自定义的图片资源也可以放在这个目录下,也可以包括不同分辨率的集合。
扩展函数
NSDictionary+QueryString.h
objc
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSDictionary (QueryString)
- (NSString*)queryString;
@end
NS_ASSUME_NONNULL_END
NSDictionary、NSString、NSArray、NSObject 等基础类都来自 Foundation ,它iOS非常重要的基础类库,里面定义了很多基础的功能,我们可以直接调用。在这里我们扩展一个queryString函数。
NSDictionary+QueryString.m
objc
#import "NSDictionary+QueryString.h"
@implementation NSDictionary (QueryString)
- (NSString*)queryString {
NSMutableArray *pairs = [NSMutableArray array];
[self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
NSString *encodedKey = [key stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSString *encodedValue = [value stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
[pairs addObject:[NSString stringWithFormat:@"%@=%@", encodedKey, encodedValue]];
}];
return [pairs componentsJoinedByString:@"&"];
}
@end
self指针指向当前对象,相当于Java语言中的this。这个方法的作用就是将key-value 的字典NSDictionary,相当于Java中的Map,转换成Http中GET请求中带参数拼接的URL。
写到最后
这个是一个简单的iOS App的功能演示的代码的分析,你还需要使用MacBook电脑在AppStore中安装一个名叫XCode 的开发工具以创建一个iOS项目。这个代码是用Objective-C 开发语言写的,用于入门,后续你还可以学习更高级的iOS开发语言Swift来开发iOS App。