Xcode Tips - Spelling and Grammarly

勾选 Check Spelling while typing

如果代码中的英文拼写出现错误,将会出现只能提示,在拼写错误的地方下面加入红色波浪线。

快捷方式 command + ;
将会一条条的小时语法出现错误的地方。

另外一个快捷方式 command + shift + ;,可以帮你推荐正确的拼写。

2020/4/11 posted in  iOS

App Icon Design

Design

我们对符号的应用可以追溯到很久很久之前,总所周知我们现在使用的文字就是从象形文字发展过来的。

  • 象征化

    找到一个简单易懂的象征,物体、图形标注或者符号。

  • 简单性

    设计要简单,不要杂乱无章,太过复杂。如果设计的好,人们一眼就能看懂。

  • 关联性

    创建与用户之间的感情连接,跟UI一样,图标是应用的脸面,一定要有趣并且引人注目

  • 传统性

    对图标的修改要有意义而且谨慎,不建议经常更改应用图标尤其是每次升级的时候,要与时俱进。

比如最初的keynote的图标就是一张讲台,以后的每次迭代升级都是围绕着讲台进行的改变,是与时俱进的,风格不断变化。而且如果你注意到的话讲台上都有一个话筒,这个也是一直有延续的。

屏幕快照 2018-12-11 下午2.16.00

iOS平台与macOS设计的不同又相同。

屏幕快照 2018-12-11 下午2.19.41

配色,元素都是类似的,而且iOS的iwork图标更是保持了一致性,一致的地平面,一致的白色,没有多余复杂的元素。

现在来看GarageBand和Music Memos的关系,有颜色和图标来看,明显有关系。圆圈代表了木吉他上的音孔,弦的振动很清晰很有趣,让人感到动感和创造力

屏幕快照 2018-12-11 下午2.24.00

Q:怎么不显示名字,也能让人理解。

A:高对比度,颜色清晰可见,设计简单,构图独特。

下面是News的图标的例子。

屏幕快照 2018-12-11 下午2.32.55

进行了三次改变设计,才做到简单醒目,即使在文件夹的小图标也会一目了然,这点对于App Icon Design 十分重要。

屏幕快照 2018-12-11 下午2.34.30

Process

设计是一个交互过程,设计时要去考虑这些环节。

  • 独特性

    要做到有区分性,特别是对于一些类似功能的APP

    屏幕快照 2018-12-11 下午2.41.11

  • 实践

    纸笔有时候比鼠标有用的多,绘画是激发灵感的好方法。

    屏幕快照 2018-12-11 下午2.40.50

  • 测试

    要在主屏,在设置,在文件夹中测试不同情形的展示效果,要用图标展现界面的话要特别注意,Clear是一个很完美的典范,简单,多彩,高对比度。

    屏幕快照 2018-12-11 下午2.41.54

  • 耐心

    答案不会立马就来,慢慢来,检查选项,保存好作品,有时候最简单的设计或者你放弃的设计师最好的选择。

2020/4/11 posted in  iOS

APP 后台任务以及捕捉bugly无法捕捉的异常

后台任务

iOS 后台保活的 5 种方式:Background Mode、Background Fetch、Silent Push、PushKit、Background Task。

  • 使用 Background Mode 方式的话,App Store 在审核时会提高对 App 的要求。通常情况下,只有那些地图、音乐播放、VoIP 类的 App 才能通过审核。
  • Background Fetch 方式的唤醒时间不稳定,而且用户可以在系统里设置关闭这种方式,导致它的使用场景很少。
  • Silent Push 是推送的一种,会在后台唤起 App 30 秒。它的优先级很低,会调用 application:didReceiveRemoteNotifiacation:fetchCompletionHandler: 这个 delegate,和普通的 remote push notification 推送调用的 delegate 是一样的。
  • PushKit 后台唤醒 App 后能够保活 30 秒。它主要用于提升 VoIP 应用的体验。
  • Background Task 方式,是使用最多的。App 退后台后,默认都会使用这种方式。

接下来,我们就看一下,Background Task 方式为什么是使用最多的,它可以解决哪些问题?

在你的程序退到后台以后,只有几秒钟的时间可以执行代码,接下来就会被系统挂起。进程挂起后所有线程都会暂停,不管这个线程是文件读写还是内存读写都会被暂停。但是,数据读写过程无法暂停只能被中断,中断时数据读写异常而且容易损坏文件,所以系统会选择主动杀掉 App 进程。

而 Background Task 这种方式,就是系统提供了 beginBackgroundTaskWithExpirationHandler 方法来延长后台执行时间,可以解决你退后台后还需要一些时间去处理一些任务的诉求。

Background Task 方式的使用方法,如下面这段代码所示:

- (void)applicationDidEnterBackground:(UIApplication *)application {
    self.backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^( void) {
        [self yourTask];
    }];
}

在这段代码中,yourTask 任务最多执行 3 分钟,3 分钟内 yourTask 运行完成,你的 App 就会挂起。 如果 yourTask 在 3 分钟之内没有执行完的话,系统会强制杀掉进程,从而造成崩溃,这就是为什么 App 退后台容易出现崩溃的原因。

捕捉被系统杀死的异常

系统杀死的app是无法捕捉到崩溃信号的,所以上面的方法也就无效了。

因为app在后台执行任务只会保活三分钟,如果我们在[self yourTask];中的任务执行超过三分钟,那么我们就无法捕获这种崩溃。

但是我们可以在应用被杀死之前先把堆栈信息保存到内存当中,这样当app下次启动联网的时候就可以上传这些堆栈信息到我们自身的服务器当中,分析崩溃日志以及找出异常原因。

打印调用堆栈信息

NSLog(@"%@",[NSThread callStackSymbols]);

应用崩溃有哪些

6

2020/4/10 posted in  iOS

Swift & Objective-C & C++之间的混编

①Objective-C 调用 C++

OC本身可以直接调用C的代码 比如直接可以调用printf方法。
但是OC中的.m直接编译C++的代码就会出现编译错误
需要把OC.m改成OC.mm之后(objective-c变成了objective-c++)引入iostream(#include<iostream>)就可以直接编译了。
这可以在.mm文件当中直接使用c++的代码。
也可以另外新建一个c++的文件,并且创建.h文件。

********CPPHello.hpp声明文件********
#ifndef CPPHello_hpp
#define CPPHello_hpp

#include <stdio.h>
class CPPHello{
    
public:
    static void sayHello();
};

#endif /* CPPHello_hpp */
********CPPHello.cpp实现文件********
#include "CPPHello.hpp"

void CPPHello::sayHello(){
    
    printf("hello world");
    
}

注意:oc调用c++必须要把.m改成.mm,要不然会报错。

②C++ 调用 Objective-C

新建cocoaTouch中的类,语言选择Objective-C,比如objcHello.hobjcHello.m然后在刚才的c++文件(CPPHello.cpp)中import objcHello.h就会出现编译错误。
所以c++语言不能直接import OC的头文件要对头文件进行修改,把头文件所有内容删除替换成c++能够识别的代码比如c或者c++的代码。

//objcHello.h
void objcSayHello();

另外objcHello.m文件要修改成objcHello.mm文件,然后#import <Foundation/Foundation.h>之后就可以在objcHello.mm文件调用oc的代码了。
并且可以在objcHello.mm文件中写oc的类了,比如如下代码。

#import <Foundation/Foundation.h>
#import "ObjcHello.h"

@interface ObjcHello:NSObject

-(void)sayHello;

@end

@implementation ObjcHello

-(void)sayHello{
    
    NSLog(@"hello objc");
}
@end


void objcSayHello(){
    
//  NSLog(@"hello Objc");
    ObjcHello * h = [ObjcHello new];
    [h sayHello];
}

然后修改完之后引入比如#include "ObjcHello.h"就可以在里面对.h文件的方法进行调用了。

#include "CPPHello.hpp"
#include "ObjcHello.h"
void CPPHello::sayHello(){
    
//   printf("hello world");
    objcSayHello();
    
}

③Swift调用C

新建CHello.h文件,然后创建头文件,然后选择创建桥接文件。
在这个桥接文件中#import其他公开头文件用来暴露给swift文件。

1.在.h文件中声明一个方法

CHello.h
#ifndef CHello_h
#define CHello_h

#include <stdio.h>
void sayHello();
#endif /* CHello_h */

2.在.c文件中实现一个方法

Chello.c 
#include "CHello.h"

void sayHello(){
    
    printf("hello c");
    
}

3.在桥接文件中引入CHello.h

//  Use this file to import your target's public headers that you would like to expose to Swift.
//

#import "CHello.h"

4.在swift当中直接调用sayHello()方法

④Swift & Objective-C & C++混编

新建OC的类比如OCHello.h和OCHello.m

#import <Foundation/Foundation.h>

@interface OCHello : NSObject
-(void)hello;
@end
#import "OCHello.h"

@implementation OCHello
-(void)hello{
    
    NSLog(@"oc sayHello");
}
@end

然后在桥接文件中引入OCHello.h
在swift当中就可以直接调用,代码如下所示

import UIKit
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        var h = OCHello();
        h.hello()

    }
}

如果想要swift调用c++的话可以把OCHello.m改成OCHello.mm
在.mm文件中写c++的代码如下所示

#include <iostream>
#import "OCHello.h"

@implementation OCHello
-(void)hello{
    
//    NSLog(@"oc sayHello");
    std::cout<<"hello cpp\n";
}
@end

swift当中的代码不做任何变化,这样就做到了三种语言的混编。

提示

.mm文件当中可以写oc,c,c++的代码
oc可以完全兼容c语言的代码
swift不可以直接执行c语言的代码,要做一些声明比如上面的调用实现。
swift不可以执行c++的代码,要用oc做中间层,一般要避免。

2020/2/11 posted in  iOS

终端命令

2019/12/11 posted in  其它

狗十三

没有所谓的彻底反省,每次以为大家都能反省的时候,接下来就是给观众们当头一棒。

最后李玩问起自己父母当时怎么认识的,然后李玩的爸爸立马声泪俱下,用手盖住女儿的脸,不让女儿看到自己流下的眼泪。

说,自己不是个好爸,大概是年轻的时候犯下了错误,导致离婚,可能很后悔,但是再也回不去了。

2019/12/11 posted in  电影

视图的绘制周期

当view第一次在屏幕上显示的时候,系统会绘制它的内容,然后系统会截取内容的快照,并且将快照作为视图的可见外观,如果你永远不改变视图的内容,那么视图的绘制代码永远不会改变。如果更改了视图的内容,不用直接重新绘制,而是使用setNeedsDisplay或者setNeedsDisplayInRect方法是视图无效。这些方法会告知视图内容以及改变并且需要在下一次进行重绘。如果需要立马重绘,那么需要使用layoutIfNeeded方法。

iOS-4
iOS-5

2019/10/11 posted in  iOS

启动优化

main 函数执行开始会进入到appDelegatedidFinishLaunchingWithOptions方法执行

很多人在一些第三方 SDK 初始化配置,各种初始化的工作都放在appDelegatedidFinishLaunchingWithOptions 这个阶段执行,其实是不合理的,正确的做法应该是弄清楚哪些是APP 启动时候真正需要的初始化功能,哪些是在其对应功能开始使用时才需要初始化的,梳理完之后把他们都放在对应的阶段进行。

首屏渲染这部分的代码止于didFinishLaunchingWithOptions 方法作用于结束。因为这时候首屏已经完成了渲染,所以可以不着急立马对其优化,但是那些阻碍线程的操作还是要优先处理的。

首屏渲染完成之后的阶段应该是非首屏其他业务模块的初始化,监听的注册,配置文件的读取等等。

时间统计

可以在Edit Scheme中添加Arguments用来统计启动时间

屏幕快照 2019-04-09 上午11.51.38

添加参数DYLD_PRINT_STATISTICS 并且 value 为1

这样启动app的时候就会有时间统计

Total pre-main time: 3.3 seconds (100.0%)
         dylib loading time: 551.91 milliseconds (16.4%)
        rebase/binding time: 1.8 seconds (54.5%)
            ObjC setup time: 754.55 milliseconds (22.5%)
           initializer time: 217.73 milliseconds (6.4%)
           slowest intializers :
             libSystem.B.dylib :  12.87 milliseconds (0.3%)

同时这个顺序也就代表了应用启动时的执行顺序。

2019/10/11 posted in  iOS