今天主要是和项目的团队沟通进度,Tonyfool的分享很有料。

Tonyfool 分享

演讲能力

忽悠能力低于水平,不会表达,就很吃亏。

藏拙,不添加有问题的的功能。iPhone 前几版都少了很多功能的,基于产品迭代和

演讲追求哇效应,出乎观众的意料。

别人都有的功能的,就跳过不讲。卖亮点功能,融入场景故事中去演示,如 Apple keynote。

iOS 强调 UE。内置 app 已经用的很舒服很易用,谁便一个产品经理不能画出其产品流畅图。

系统化解决问题

代码调优和 Debug,如何系统化解决新的问题:猜可能是那几个方面出了问题,全面分析完了,再去全面的验证调试解决。而不是想到一个可能一个想法就去试。

摘自 sunnyxx 的文章:一个丝滑的全屏滑动返回手势

status bar

UIApplication 全局的 status bar,牵一发还得动全身,不过 Apple 在 iOS7 之后为 vc 控制自己的 status bar 提供了下面几个方法,终于让这个全局变量变成了局部变量:

1
2
3
- (UIStatusBarStyle)preferredStatusBarStyle NS_AVAILABLE_IOS(7_0);
- (BOOL)prefersStatusBarHidden NS_AVAILABLE_IOS(7_0);
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation NS_AVAILABLE_IOS(7_0);

fullscreen-pop-gesture

一个 UINavigationController 管理了串行的 N 个 UIViewController 栈式的 push 和 pop,而 UINavigationBar 由 UINavigationController 管理,这就导致了 UIViewController 无法控制自己上面的 bar 单独的隐藏或显示。
但是对 UINavigationBar 的控制,依然是全局的,可能 Apple 觉得 App 不应该有这种奇怪的页面结构?

解决这个问题的方法也不难,在滑动返回的后要出现的那个 view controller 中写下面的代码:

1
2
3
4
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}

fullscreen-pop-gesture

Xcode tips

  • Secondary click : Jump to definition
  • Show Relative Items(^1): Callers
    Show Relative Items

一下看了9/10两课,有点烧脑也好,走出舒适区也好, 困了也好,反正看完睡了2小时。现在刚起来写笔记,稍后实践知识点加到项目中。没开字幕,因为我的阅读速度还不如听力。

Tinyfool:看英文视频不看字幕。

ibuick:学习知识后,在另外一个小 App 去运用

Scroll View

概念和使用都很简单,理解成画布、画稿、放大镜即可。

Multithreading

典型的用法:

1
2
3
4

let session = NSURLSession(NSURLSessionConfiguration.defaultSessionConfiguration())
if let url = NSURL(string: “http://url”) { let request = NSURLRequest(URL: url) let task = session.downloadTaskWithRequest(request) {
(localURL, response, error) in  dispatch_async(dispatch_get_main_queue()) { /* I want to do something in the UI here, can I? */ } } task.resume() }

View Controller Lifecycle

  • Instantiated (from storyboard usually)
  • awakeFromNib
  • segue preparation happens
  • outlets get set
  • viewDidLoad

These pairs will be called each time your Controller’s view goes on/off screen …

  • viewWillAppear and viewDidAppear
  • viewWillDisappear and viewDidDisappear

These “geometry changed” methods might be called at any time after viewDidLoad …

  • viewWillLayoutSubviews (… then autolayout happens, then …) viewDidLayoutSubviews

If memory gets low, you might get …

  • didReceiveMemoryWarning

Autolayout

You’ve seen a lot of Autolayout already

  • Using the dashed blue lines to try to tell Xcode what you intend
  • Ctrl-Dragging between views to create relationships (spacing, etc.)
  • The “Pin” and “Arrange” popovers in the lower right of the storyboard
  • Reset to Suggested Constraints (if the blue lines were enough to unambiguously set constraints)
  • Document Outline (see all constraints, resolve misplacements and even conflicts)
  • Size Inspector (look at (and edit!) the details of the constraints on the selected view)
  • Clicking on a constraint to select it then bring up Attributes Inspector (to edit its details)

Mastering Autolayout requires experience

You just have to do it to learn it

Autolayout can be done from code too

Though you’re probably better off doing it in the storyboard wherever possible The demo today will show a simple case of doing Autolayout from code

Demo:

  • Notice auto layout issues and resove them.
  • Preview Storyboard in assistant editor
  • Remove magic nubmers in constraints of size inspector: such as use standard value or 0.

More:

What does “Use standard value and Constrain to Margins” mean in Auto Layout?

Auto Layout Concepts

The fundamental building block in Auto Layout is the constraint. Constraints express rules for the layout of elements in your interface;

Constraint Basics

You can think of a constraint as a mathematical representation of a human-expressable statement. If you’re defining the position of a button, for example, you might want to say “the left edge should be 20 points from the left edge of its containing view.” More formally, this translates to button.left = (container.left + 20), which in turn is an expression of the form y = m*x + b, where:

y and x are attributes of views.

m and b are floating point values.

An attribute is one of left, right, top, bottom, leading, trailing, width, height, centerX, centerY, and baseline.

Auto Layout Tutorial Part 1: Getting Started

fastlane

fastlane lets you define and run your deployment pipelines for different environments. It helps you unify your app’s release process and automate the whole process. fastlane connects all fastlane tools and third party tools, like CocoaPods and xctool.

fastlane 是一款自动化 App 提交流程工具,也拆分了开了每一个工具,也可以直接按照下面的工作流一步提交 App Store。

  • snapshot
    把你的iOS应用程序的本地化语言自动截屏

  • deliver
    一行命令上传截图,元数据和应用程序到 App Store

  • frameit
    快速把你的截图到正确的设备框架

  • gym
    快速打包 iOS 应用程序成 ipa

感兴趣的话,赶紧去官网 https://fastlane.tools/#https://github.com/KrauseFx/fastlane 试一试。希望能够节约到你宝贵的时间。

fastlane workflow

Video Tutorial

  1. Add first View Controller Segue to new View Controller
  2. Add Bar Button Item on first View Controller and set target-action
  3. code in action:method add self.porformSegueWithIdentifier
  4. setToolbarHidden(_ hidden: Bool, animated animated: Bool)
  5. Or set in interface builder

Show and Hide Bottom by code
Show and Hide Bottom set in interface builder

Demo Project on GitHub

More in Segue

Simpler way:

Adding a Segue Between Scenes in a Storyboard

Another way:View Controller segue to View Controller,
your can something more in target-action method.

IOS7, Segue and storyboards - How to create without a button?

design_patterns

总体感觉设计模式课程偏理论,操作起来可能要反复实践后,才会知道项目用哪个设计模式比较合适。

我目前还是学习了解的还是六大基本设计模式,希望以后开发过程中能够思考设计模式的选择。

@李建忠:设计模式是程序员从初阶往中阶迈进很重要的素养。关键在于要去思考设计的方案,为什么这么做?还有哪些设计方法?彼此的优劣?而不是功能跑通就了事。 在这样日积月累的思考和反复实践中,设计功力就会提高。

1. 设计模式简介和 MVC

简单介绍了设计模式的含义,和一些常用的 iOS 设计模式。

xdrt81y 的 关于iOS六大基本设计模式,文章简单明了可以参考一下。

Introducing iOS Design Patterns in Swift – Part 1/2 结合项目介绍了 Swift 中的设计模式。

使用设计模式,苹果文档介绍。

Wikipedia:

In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design.
It is a description or template for how to solve a problem that can be used in many different situations.
Patterns are formalized best practices that the programmer can use to solve common problems when designing an application or system.

2. Target-Action、selector 和 Nib

详细介绍了 Nib 加载

3. Storyboard 和原型设计

Storyboard

我还是很喜欢 Storyboard,比代码直观高效,方便看到原型图和交互关系。

拆分 Storyboard,避免多人同时修改。

推荐:WWDC15 215 What’s New in Storyboards

参考:iOS 9: Staying Organized with Storyboard References

  • instantiateInitialViewController()
  • destination of a segue

Storyboard references are powerful. Not only do they make storyboards manageable and modular, they make it very easy to reuse storyboards and even hook into storyboards at arbitrary places.

Storyboard references are only available in iOS 9.

代码见 GitHub

4. 两步创建和模板方法

The best way to predict your future is to create it.

― Abraham Lincoln

两步创建

对象两步创建:alloc init

工厂方法:+ (instancetype)dateWithTimeIntervalSinceNow:(NSTimeInterval)seconds

内省(Introspection)

模板方法

参考:lichwei1983 的文章 模板方法–行为型模式之四

模板方法应用于下列情况:

  • 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
  • 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。这是 Opdyke 和 Johnson 所描述过的“重分解以一般化”的一个很好的例子。首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
  • 控制子类扩展。模板方法只在特定点调用“ h o o k”操作(参见效果一节),这样就只允许在这些点进行扩展。

模板方法是一种代码复用的基本技术。它们在类库中尤为重要,它们提取了类库中的公共行为。模板方法导致一种反向的控制结构,这种结构有时被称为“好莱坞法则”,即“别找我们,我们找你”。这指的是一个父类调用一个子类的操作,而不是相反。

5. 单例模式

  • UIApplication
  • NSNotificationCenter
  • NSUserDefaults
  • NSFileManager
  • UIAccelerometer
  • NSURLSession

参考:刚刚在线的 iOS 设计模式系列:Singleton – 单例模式

单例设计模式确切的说就是一个类只有一个实例,有一个全局的接口来访问这个实例。当第一次载入的时候,它通常使用延时加载的方法创建单一实例。

在一些情况下,一个类只有一个实例是有意义的。例如,这里没有必要有多个登录实例,除非你一次想写入多个日志文件。或者,一个全局的配置类文件:它可以很容易的很安全的执行一个公共资源,这样的一个配置文件,要比同时修改多个配置类文件好很多。

转发整理一些我认为值得学习的小节。

-原文 https://github.com/objc-zen/objc-zen-book

-Gitbook 链接(包含 PDF, mobi, epub 格式): http://yourtion.gitbooks.io/objc-zen-book-cn/ (感谢 yourtion 整理 )

nil 和 BOOL 检查

类似于 Yoda 表达式,nil 检查的方式也是存在争议的。一些 notous 库像这样检查对象是否为 nil:

1
if (nil == myValue) { ...

或许有人会提出这是错的,因为在 nil 作为一个常量的情况下,这样做就像 Yoda 表达式了。 但是一些程序员这么做的原因是为了避免调试的困难,看下面的代码:

1
if (myValue == nil) { ...

如果程序员敲错成这样:

1
if (myValue = nil) { ...

这是合法的语句,但是即使你是一个丰富经验的程序员,即使盯着眼睛瞧上好多遍也很难调试出错误。但是如果把 nil 放在左边,因为它不能被赋值,所以就不会发生这样的错误。 如果程序员这样做,他/她就可以轻松检查出可能的原因,比一遍遍检查敲下的代码要好很多。

为了避免这些奇怪的问题,可以用感叹号来作为运算符。因为 nil 是 解释到 NO,所以没必要在条件语句里面把它和其他值比较。同时,不要直接把它和 YES 比较,因为 YES 的定义是 1, 而 BOOL 是 8 bit的,实际上是 char 类型。

推荐:

1
2
3
if (someObject) { ...
if (![someObject boolValue]) { ...
if (!someObject) { ...

不推荐:

1
2
3
if (someObject == YES) { ... // Wrong
if (myRawValue == YES) { ... // Never do this.
if ([someObject boolValue] == NO) { ...

同时这样也能提高一致性,以及提升可读性。

Read more »

21. iOS应用框架(上)

主要讲解了 Project 文件目录整理分类,Storyboard 和代码结合使用,Constraints 的使用。稍后在项目里面实践一下。

有提到 [UIScreen mainScreen].bounds 的问题。

我之前就研究过,见:http://gewill.org/2015/08/04/UIScreen-mainScreen-bounds-in-Xcode-7-Beta-4/

23. iOS应用框架(下)

主要演示 Storyboard 的自动布局和代码管理跳转和动画过度。但是总感觉有点基本上是在 AppDelegate 中管理 Storyboard 的跳转关系,实不如 Storyboard references 清晰明了,且不妨碍分工开发。

代码如下:

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
//  AppDelegate.h
// BLDemo05


#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;


/**
* 声明一个 UINavigationController 属性,作为 rootViewController
*/
@property (strong, nonatomic) UINavigationController *loginNavigationVC;


/**
* 使用代码加载 Login.storyboard 的函数
*/
- (void)loadLoginView;
/**
* 使用代码加载 Login.storyboard 的函数
*/
- (void)loadMainView;

@end


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
//  AppDelegate.m
// BLDemo05


#import "AppDelegate.h"
#import "BLUserInfoViewController.h"

@interface AppDelegate ()

@end

@implementation AppDelegate


- (void)loadLoginView {
// 读取 Login.storyboard, 压入 rootViewController(loginNavigationVC)
UIStoryboard *loginStoryboard
= [UIStoryboard storyboardWithName:@"Login"
bundle:[NSBundle mainBundle]];
self.loginNavigationVC = loginStoryboard.instantiateInitialViewController;
self.window.rootViewController = self.loginNavigationVC;
}


- (void)loadMainView {

// 1 - 读取 UserInfo.storyboard, 压入 BLUserInfoViewController(userInfoVC), 一并压入 UINavigationController(navc)
UIStoryboard *userInfoStoryboard
= [UIStoryboard storyboardWithName:@"UserInfo" bundle:[NSBundle mainBundle]];

BLUserInfoViewController *userInfoVC
= [userInfoStoryboard instantiateViewControllerWithIdentifier:@"BLUserInfoViewController"];

UINavigationController *navc
= [[UINavigationController alloc] initWithRootViewController:userInfoVC];

// 2 - 添加 UINavigationController 标题
navc.tabBarItem.title = @"userInfo";

// 3 - 新建一个 UITabBarController(tabBarC),并设为 rootViewController
UITabBarController *tabBarC = [[UITabBarController alloc] init];
tabBarC.viewControllers = @[navc];

self.window.rootViewController = tabBarC;

// 4 - 添加过度效果
[self.window addSubview:self.loginNavigationVC.view];

[UIView animateWithDuration:0.3
animations:^{
self.loginNavigationVC.view.alpha = 0;
self.loginNavigationVC.view.frame = CGRectZero;
self.loginNavigationVC.view.transform = CGAffineTransformMakeScale(0.1, 0.1);
} completion:^(BOOL finished) {
self.loginNavigationVC = nil;
}];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];

// App 启动,调用 loadLoginView 函数
[self loadLoginView];

return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
}

- (void)applicationWillTerminate:(UIApplication *)application {
}

@end

App Distributio

  1. iTunes Connet > MyApps > add App
  2. Xcode
  • Product > Acrchive
  • Window > Organizer > Submit to App Store
  1. iTunes Connet > MyApps > Prerelease
  • Builds: Turn on TestFlight Beta Testing
  • Add Internal or External Testers
  1. Click Open in TestFlight in email from iTunes Store on your iPhone

More in App Distribution Guide

0%