iOS 开发基础工具 | 青训营笔记

204 阅读9分钟

这是我参与「第四届青训营」笔记创作活动的第3天

一、本堂课重点内容:

image.png

二、详细知识点介绍:

1.iOS系统框架

框架Framework

在软件开发的领域里,Frameworks指的是一个通用的,可复用,具备特定功能的软件或是环境,他可能包含了代码库,API文件,或是一些工具的集合体。

iOS Framework

Framework是一个有层级的目录,他将动态代码库,nib files,图片文件,头文件和参考文件全部封装成一个单一的资源包,多个程序之间可以同时共用它,并被程序调用去执行某个任务。
简单来说,对于Xcode而言,Framework就是一个文件后坠为 .framework的文件包,里面包含了与其相关的文件,程序在启动时会将它加载进内存。

iOS Framework文件夹

Framework 就是以这样像资源包的形式,供开发者使用。当然除了系统提供的之外,你也可以自己去开发Framework或是使用其他三方提供的Framework。

image.png

iOS系统框架 / iOS System Frameworks

image.png

系统框架分层

所有的系统框架可以被分作四层(四个Layer),分别是 Cocoa Touch (触摸层),Media (媒体层),Core Services (核心服务层),以及 Core OS (操作系统层),处于上层的框架会去依赖底层的框架,但底层的框架它不会有依赖上层的情况。

2.Foundation框架

Foundation框架为 App和其他框架提供了基础的能力,包括 数据存储持久化,文本处理,日期时间计算,排序筛选,还有网路。并且Foundation框架的能力是MacOS, iOS, watchOS, tvOS通用的。

NSObject 类

  • 所有类的根类 (root Class)
  • 大量的适应Objective-C语言的方法
  • NSObject是一个遵守NSObject协议的类
//NSObject.h
@protocol NSObject
//.....
- (id)performSelector:(SEL)aSelector;
- (BOOL)isKindOfClass:(Class)aClass;
//.....
@end

@interface NSObject <NSObject> {
//.....
+ (instancetype)alloc
- (instancetype)init
//.....
}

补充 - 如何查看系统头文件

关于如何查看NSObject这种系统类的头文件,这里分享一些方法

  • 第一个方法是 NSObject关键字的地方,例如我自己声明的类,按住 command键在点击NSObject关键字,并跳转到定义
  • 第二个方法是在Xcode任意编辑页面中,按著 command + shift + o,会跳出一个搜索框,搜索NSObject.h 即可

NSObject - 分配内存空间 & 初始化

// NSObject.h
@interface NSObject <NSObject> {  
/** 为新对象分配内存空间 */  
+ (instancetype)alloc;
/** 初始化对象 */  
- (instancetype)init;

/** 为新对象分配内存空间并初始化, 等于[[NSObject alloc] init] */  
+ (instancetype)new;
}
//main.m
ByteDancer *byteDancer1 = [[ByteDancer alloc] init];
// 等同于
ByteDancer *byteDancer2 = [ByteDancer new];

NSObject - 发送消息(方法调用)

// NSObject.h
@protocol NSObject  
/** 发送指定的消息给对象, 返回消息执行结果(相当于方法调用) */  
- (id)performSelector:(SEL)aSelector;  
/** 发送带一个参数的消息给对象, 返回消息执行结果(相当于方法调用) */  
- (id)performSelector:(SEL)aSelector withObject:(id)object;  
/** 判断对象是否能够调用给定的方法 */  
- (BOOL)respondsToSelector:(SEL)aSelector; 
@end

// main.m
// 先判断对象是否能调用方法,再执行调用方法  
if ([bytedancer1 respondsToSelector:@selector(sayHello)]) {  
// 调用无参无返回值方法  
    [bytedancer1 performSelector:@selector(sayHello)];  
}  
// 可以用于调用私有方法
if ([bytedancer1 respondsToSelector:@selector(private_method)]) {  
    [bytedancer1 performSelector:@selector(private_method)];  
}

NSObject - 类关系判断

// NSObject.h
/** 获取当前对象的类 */  
- (Class)class;
/** 获取当前对象的类 */  
- (Class)superclass;

/** 判断对象是否是给定类或给定类子类的实例 */  
- (BOOL)isKindOfClass:(Class)aClass;  
/** 判断对象是否是给定类的实例 */  
- (BOOL)isMemberOfClass:(Class)aClass;  
/** 判断对象是否遵从给定的协议 */  
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;  
类关系判断使用场景
// 字典对应的不确定类型
NSObject *getValue = [dictionary1 objectForKey:@"key1"];
if ([getValue isKindOfClass:NSString.class]) {
    // 确定是NSString 在转型成NSString
    NSString *strValue = (NSString *)getValue;
    [strValue length];
} else if([getValue isKindOfClass:ByteDancer.class]) {
    // 确定是ByteDancer 在转型成ByteDancer
    ByteDancer *byteDacner1 = (ByteDancer *)getValue;
    [byteDacner1 sayHello];
} else {
    NSLog(@"unkown class");
}

常用数据类型

(只放代码example,具体讲解见引用的学习手册)

NSString 字符串

// C语言字符串(基础数据类型)
char *cString = "James";

//NSString.h (专门处理字符串的类)
@interface NSString : NSObject <NSCopying, NSMutableCopying, NSSecureCoding>
//......
@property (readonly) NSUInteger length;
- (unichar)characterAtIndex:(NSUInteger)index;
- (instancetype)init;
//.....
@end
NSString - 创建
// @"" 创建 NSString 对象 (常用)
NSString *stringObject = @"hello";

// C语言字符串
char *cString = "James";
// C语言字符串 -> NSString 对象
NSString *stringObject1 = [NSString stringWithUTF8String:"James"];

// 初始化一个空字符串
NSString *stringObject2 = [[NSString alloc] init];
// 初始化一个字符串
NSString *stringObject3 = [NSString stringWithString:@"hello"];
// 拼接一个字符串
NSString *stringObject4 = [stringObject3 stringByAppendingString:@" world"];
NSString - 类型转换
// 创建格式化字符串 - @"123 , str"
int a = 123;
NSString *stringObject5 = [[NSString alloc]initWithFormat:@"%d , %@", a, "str"];

// MARK: NSString转成基础类型
NSString *numberStr = @"123";
// BOOL
BOOL boolValue = [numberStr boolValue];
// int
int intValue = [numberStr intValue];
//float 
float floatValue = [testStr floatValue];
// double
double doubleValue = [testStr doubleValue];
NSString - 子字符串
NSString *stringObject5 = @"hello";

// 获取字符串的长度
NSUInteger length = [stringObject5 length];
// 获取索引下标的字符
unichar index_char = [stringObject5 characterAtIndex:0];

// 截取字符串,从索引位置到结尾
NSString *subStr1 = [stringObject5 substringFromIndex:1];
// 截取字符串,从开始到索引位置
NSString *subStr2 = [stringObject5 substringToIndex:3];
// 截取字符串,从索引开始,取长度个数组成的字符串
NSRange range = NSMakeRange(1, 2);
NSString *subStr3 = [stringObject5 substringWithRange:range];

NSArray 数组

// 空数组
NSArray *arr1 = [NSArray array];
// 效果同上
NSArray *arr2 = [[NSArray alloc] init];

// @[...] = NSArray对象创建
NSArray *arr3 = @[@"iOS", @"Android", @"Server"];
// 效果同上
NSArray *arr4 = [NSArray arrayWithObjects:@"iOS", @"Android", @"Server"];

// 如果需要放基本类型,可使用NSNumber or @(value) = 自动转成NSNumber对象
NSNumber *numberObject = [[NSNumber alloc] initWithInt:100];
NSArray *arr4 = [NSArray arrayWithObjects:@(123), numberObject];

// 限制存放对象为NSNumer
NSArray<NSNumber *> *numberArrayObject = @[@(1), @(-1), @(3.3)];
NSArray 查询
NSString *str = @"bytedance";
NSArray *array = @[str, @"iOS", @"Android"];

// count  数组中所含元素个数
NSLog(@"count = %d", array.count);
// 返回对应位置对象
NSObject *obj1 = array[0]
// 返回元素对应位置(认对象)
NSUInteger index = [array indexOfObject:obj1];
// lastObject  返回数组最后一个元素
NSObject *obj2 = [array lastObject];

// containsObject   是否包含指定对象
if ([array containsObject:str]) {
    // true
}
if ([array containsObject:@"iOS"]) {
    // true
}

//使用for循环遍历
for (NSString *strObj in array) {
    NSLog(@"%@", strObj);
}
不可变数组 NSArray vs 可变 NSMutableArray
 @interface NSMutableArray<ObjectType> : NSArray<ObjectType>
// 以下方法NSArray无
- (void)addObject:(ObjectType)anObject;
- (void)insertObject:(ObjectType)anObject atIndex:(NSUInteger)index;
- (void)removeLastObject;
- (void)removeObjectAtIndex:(NSUInteger)index;
@end
// 可变
NSMubaleArray *arr1 = .....
doSomething(NSMubaleArray* array);
// arr1 是否已经被修改
// 不可变(只读)
NSArray *arr2 = .....
doSomething(NSArray* array);
// arr2 还是原数据
  • 对象数据可能被修改
  • 线程不安全
  • 查找性能较差
  • 一般用作方法内的临时变量,可做增删
  • 传进去的对象不会被修改
  • 线程安全
  • 查找性能好
  • 用于属性声明或是方法参数/回传值
// NSArray -> NSMutableArray
NSMutableArray *mutableArr1 = [[NSMutableArray alloc] initWithArray:numberArrayObject];
// NSMutableArray -> NSArray
NSArray *fixArr1 = [[NSArray alloc] initWithArray:mutableArr1];
NSMutableArray 数据增删
//MARK: NSMutableArray 数组增删 NSMutableArray *mutableArrayObject = [[NSMutableArray alloc] init];
// 新增任意对象
[mutableArrayObject addObject:@"StringObject1"];
// 在指定下标添加对象
[mutableArrayObject insertObject:@(0) atIndex:0];
// 批量添加
[mutableArrayObject addObjectsFromArray:@[@"StringObject2", @(1)]];

// 移除末尾
[mutableArrayObject removeLastObject];
// 删除指定下标
[mutableArrayObject removeObjectAtIndex:0];
// 移除全部
[mutableArrayObject removeAllObjects];

NSDictionary 字典

// @{} = 创建NSDictionary对象
NSDictionary *dict1 = @{
    @"key1":@"value1"
};
// 效果同上
NSDictionary *dict2 = [NSDictionary dictionaryWithObject:@"key1" forKey:@"value1"];

// 多Key
NSDictionary *dict1 = @{
    @"key1":@"value1",
    @"key2":@"value2"
};
//效果同上
NSDictionary *dict5 = [[NSDictionary alloc]initWithObjects:@[@"value1",@"value2"] 
                                                   forKeys:@[@"key1",@"key2"]];
// 指定保存类型   
NSDictionary<NSString*, NSNumber*> *dictionaryObject = @{
    @"numberKey1": @(0),
    @"numberKey2": @(1),
}             
NSDictionary 访问
NSDictionary *dictionary1 = @{
    @"key1": @"value1"
};

// count  (字典元素个数   key:value 是一一对应的,所以是算作一个的)
int dictionary1Count = [dictionary1 count];

// objectForKey:  (获取一个key对应的值)
NSObject *getValue = [dictionary1 objectForKey:@"key1"];
// 等同
id getValueDirect = dictionary1[@"key1"];

// allKeys   (获取key集合)
NSArray *keysArr = [dictionary1 allKeys];

//allValues   (获取所有value)
NSArray *valuesArr = [dictionary1 allValues];

// 遍历所有Key,并访问对应Value
[dictionary1 enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
     NSLog(@"key = %@  value = %@",key,[dictionary1 objectForKey:key]);
}];
NSMutableDictionary 增删
NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc] initWithDictionary:@{
  @"key1": @"value1"
}];

//setObject:(setValue:)forKey:   (设置某Key对应值)
[mutableDictionary setObject:@"value2" forKey:@"key2"];
[mutableDictionary setValue:@"value3" forKey:@"key3"];
mutableDictionary[@"key4"] = @"value4";

//removeObjectForKey:   (移除某一个key对应的元素)
[mutableDictionary removeObjectForKey:@"key2"];
//removeAllObjects  (移除所有元素)
[mutableDictionary removeAllObjects];

3.实战

实践练习例子

三、实践练习例子:

实战 - 断点与调适

创建iOS App Target

在选择 Target 的页面上,选择 iOS 标签中的 App Target
image.png image.png
生成了一些初始文件
image.png

  • main.m -> 程序的入口
  • AppDelegate -> App的入口代码
  • ViewController -> App的第一个页面代码

运行模拟器

在App的第一个页面代码中添加如下片段:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 350, 100)];
    [label setText:@"Welcom, 我的第一个App"];
    [self.view addSubview:label];
}

然后点击左上角的三角形,即可运行自己的第一个App。

image.png

代码调适工具 - LLDB

代码调适 - 手动断点

手动断点的用法非常简单,就是在断点的代码位置左侧,点击出一个蓝色的箭头,那程序运行到该代码就会进入断点状态,程序会暂停,此时你就可以根据当前的对象状态去找出Bug的根因。

(单击左侧行号既可)
image.png

进入调试界面

设置断点后点击运行三角形,出现调试界面。
(Debug区、对象变量区、控制台区、以及一个程序控制区)
image.png

常用调试指令介绍 - p / po

lldb指令ppo
范例
执行将右边表达式的计算结果保存在 lldb临时变量中,可供本次调试使用打印右边对象的 debugDescription 方法
本质expression --expression -O -- expression —object-description

常用调试指令介绍 - expression

expression命令可以简写成e,该命令会通过LLDB format格式求出一个表达式的值,我们可以用它来赋值,修改变量值,求一个表达式结果,调用方法等等,更多功能我们可以通过help e来查看文档学习. image.png

常用调试指令介绍 - Breakpoint

程序控制区

最后我们来介绍下程序控制区,程序控制区有以下几种功能

  • 首先是 程序继续执行结束暂停状态,直到碰到下个断点
  • 第二个是 stepover,每点击一次程序就会往下执行一行,如果是方法调用,会保持在当前堆栈正常执行完方法
  • 第三个是 setp into,如果当前行是方法调用,会进入到该方法的堆栈里
  • 第四个是stepout,会直接执行到当前方法执行完的堆栈中,如果确定当前方法没有问题时,可以使用
  • 第五个是在调适UI介面非常好用的UI视图层级检视,点击后可以查看当前App的视图情况
  • 第六个则是在查询内存泄漏特别好用的,内存分布图,可以查看到每个对象的持有状况,能看到一个对象持有其他对象或被其他对象持有的的关系

四、课后个人总结:

  • 本章有什么知识点不容易掌握?
    本次的实战内容相当简单,主要是知识点很多,要多加复习和记忆。
  • 什么地方容易与其他内容混淆?
    几种变量的声明格式、调试界面中各区的作用等等。
  • 记录一下感想?
    还是要多练,单单看几遍,是记不住的,常看常新。

五、引用参考:

学习手册:juejin.cn/post/712271…
课程PPT:iOS开发基础工具.pptx