iOS基础 3.0

2023-11-19  本文已影响0人  脚踏实地的小C

前言

6、什么是KVC、KVO?
7、通知和协议的不同之处?
8、单例是什么?优缺点是什么?
9、什么是懒加载?优缺点是什么?
10、static什么时候使用?有什么作用?

6、什么是KVC、KVO?

KVC(Key-Value Coding)
  KVC是一种通过键值访问对象的属性的机制,允许通过键(属性名)来访问修改对象的属性值。这使得我们可以通过字符串形式访问对象的属性,而不需要直接调用相应的方法。

在项目中,以下一些情况下你可能会使用KVC
1、设置和获取对象的属性
  KVC提供了一种方便的方式来设置和获取对象的属性,尤其是当属性名以字符串形式存在时。这对于在运行时动态地访问或修改对象的属性非常有用。

// 设置对象属性
[object setValue:@"John" forKey:@"name"];

// 获取对象属性
NSString *name = [object valueForKey:@"name"];

2、字典和模型的转换
  当从服务器或其他数据源获得数据时,通常以字典的形式提供。使用KVC,你可以方便将字典中的键值对映射到对象的属性,实现字典和模型对象之间的转换

NSDictionary *data = @{@"name": @"John", @"age": @25};

// 使用KVC将字典转换为对象
Person *person = [[Person alloc] init];
[person setValuesForKeysWithDictionary:data];

3、动态地访问属性
  当需要动态地访问或操作对象的属性时,KVC提供了一种方便的机制。这对于通用的数据操作表单处理等场景非常有用。

NSString *propertyName = @"name";
NSString *propertyValue = [object valueForKey:propertyName];

4、集合操作
  KVC提供了一套用于集合操作的方法,例如对数组中的每个元素执行某个操作计算数组中的最大或最小值等。这对于处理集合数据非常方便。

NSArray *numbers = @[ @10, @20, @30 ];

// 计算数组中的总和
NSNumber *sum = [numbers valueForKeyPath:@"@sum.self"];

5、在自定义控制台输出中使用
  在调试时,通过覆盖description方法并使用KVC来生成自定义控制台输出,可以方便地查看对象的内部状态。

- (NSString *)description {
    return [NSString stringWithFormat:@"Person - Name: %@, Age: %@", [self valueForKey:@"name"], [self valueForKey:@"age"]];
}

优点:

//正常情况下某个类的创建
@interface Person : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;

@end


//使用KVC
NSDictionary *data = @{@"name": @"John", @"age": @25};
// 使用 KVC 将字典转换为对象
Person *person = [[Person alloc] init];
[person setValuesForKeysWithDictionary:data];
@interface Person : NSObject

@property (nonatomic, copy) NSString *name;

@end

@implementation Person
@end

// 创建包含 Person 对象的数组
NSArray *people = @[ [[Person alloc] initWithName:@"John"],
                    [[Person alloc] initWithName:@"Jane"],
                    [[Person alloc] initWithName:@"Bob"] ];

// 使用 KVC 获取所有人的姓名组成的新数组
NSArray *names = [people valueForKeyPath:@"@each.name"];

NSLog(@"Names: %@", names);

缺点


KVO(Key-Value Observing)
  KVO允许一个对象监听另一个对象特定属性值的变化。当被观察的对象的属性发生改变时,观察者会收到通知。这提供了一种在对象之间保持同步的机制。

在项目中,以下一些情况下你可能会使用KVO
1、UI更新
  当数据模型的属性变化时,需要更新用户界面。

// 添加 KVO 观察者
[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

// 实现 KVO 观察者方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"name"]) {
        // 在这里执行刷新 UI 的操作
        [self updateUIWithNewName:change[NSKeyValueChangeNewKey]];
    }
}

2、数据同步
  当多个对象之间需要保持数据同步时,可以使用KVO。一个对象的属性变化将会通知到观察者观察者可以做出相应的响应,保持数据的一致性
3、观察属性变化执行特定操作
  在属性变化时,需要执行一些特点的操作,而不是仅仅更新UI。
4、监控网络请求状态
  在进行网络请求时,有时需要监控网络请求的状态变化,以便在请求完成时执行一些操作。
5、自定义观察者模式
  KVO提供了一种机制来实现观察者模式,用于建立对象之间的通信。这样可以减少对象之间的直接耦合。

ps:使用KVO时应该遵循一些最佳实践,如正确注册移除观察者,处理观察者通知时的线程安全等。

优点

// 被观察的对象
@interface Person : NSObject

@property (nonatomic, copy) NSString *name;

@end

@implementation Person
@end

// 观察者
@interface Observer : NSObject

@end

@implementation Observer

- (instancetype)init {
    self = [super init];
    if (self) {
        // 创建被观察对象
        Person *person = [[Person alloc] init];

        // 添加观察者
        [person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

        // 模拟属性变化,触发 KVO
        person.name = @"John";

        // 移除观察者
        [person removeObserver:self forKeyPath:@"name"];
    }
    return self;
}

// 实现 KVO 观察者方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"name"]) {
        NSLog(@"Name changed to: %@", change[NSKeyValueChangeNewKey]);
    }
}

@end

缺点

7、通知和协议的不同之处?

  通知协议时iOS中两种不同的机制,用于实现对象之间的通信和协作

通知

// 发送通知的代码
[[NSNotificationCenter defaultCenter] postNotificationName:@"SomeNotification" object:nil];

// 接收通知的代码
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:@"SomeNotification" object:nil];

// 通知处理方法
- (void)handleNotification:(NSNotification *)notification {
    NSLog(@"Received notification: %@", notification.name);
}

协议

// 定义一个协议
@protocol MyProtocol
- (void)doSomething;
@end

// 类采用协议
@interface MyClass : NSObject <MyProtocol>
@end

@implementation MyClass
- (void)doSomething {
    NSLog(@"Doing something");
}
@end

如果通信涉及到多个对象,且这些对象之间的关系比较松散通知是一个不错的选择

如果通信是一对一的关系,并且需要确保采用协议的对象实现了一组特定的方法,协议是更适合的选择

8、单例是什么?优缺点是什么?

  单例是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。单例模式通常使用静态方法或类方法(类似于sharedInstance)来返回唯一的实例。

优点

缺点

// MySingleton.h
@interface MySingleton : NSObject

@property (nonatomic, strong) NSString *data;

+ (instancetype)sharedInstance;

@end

// MySingleton.m
@implementation MySingleton

// 静态变量用于保存唯一实例
static MySingleton *_sharedInstance = nil;

+ (instancetype)sharedInstance {
    // 使用GCD确保线程安全创建单例
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[super alloc] init];
    });

    return _sharedInstance;
}

- (instancetype)init {
    // 防止通过init方法创建新的实例
    NSAssert(!_sharedInstance, @"Use sharedInstance method to get the instance.");
    self = [super init];
    if (self) {
        // 初始化
    }
    return self;
}
@end

9、什么是懒加载?优缺点是什么?

  懒加载是一种延迟加载对象或执行操作的技术,它在需要的时候才进行加载执行,而不是在应用启动时就立即加载或执行。懒加载通常用于延迟加载视图、数据或其他资源,以提高应用程序的性能资源利用率

优点

缺点

10、static什么时候使用?有什么作用?

  static关键字用于不同的上下文,其作用取决于它所修饰的内容。

1、静态局部变量:在方法调用之间保留其值,而不像普通局部变量那样在每次调用时重新初始化。这可以用于实现在方法之间保持状态的需求。

- (void)someMethod {
    static NSInteger counter = 0;
    counter++;
    NSLog(@"Counter: %ld", counter);
}

2、静态全局变量:在文件范围内可见,但是其作用域限制在当前文件中。这可以用于在整个文件中共享状态或数据

// 在文件的顶部或实现文件的全局作用域内
static NSInteger globalCounter = 0;

- (void)someMethod {
    globalCounter++;
    NSLog(@"Global Counter: %ld", globalCounter);
}

3、静态函数:作用域限制在当前文件中,不可被其他文件访问。这可以用于实现文件内部的私有函数,不暴露给其他文件使用。

// 在文件的顶部或实现文件的全局作用域内
static NSInteger multiplyByTwo(NSInteger number) {
    return number * 2;
}

- (void)someMethod {
    NSInteger result = multiplyByTwo(5);
    NSLog(@"Result: %ld", result);
}

4、静态常量:用于定义在整个文件内都可见的常量,避免魔法数字的使用。常量通常以static const的形式定义,确保其在编译时被优化。

static const NSInteger MaxItemCount = 10;

- (void)someMethod {
    NSLog(@"Max Item Count: %ld", MaxItemCount);
}
上一篇 下一篇

猜你喜欢

热点阅读