iOS小技能之字典转模及对象相等性示例详解

目录
  • 前言
  • I 字典转模型
    • 1.1 字典转模型的实现步骤
    • 1.2 字典转模型的过程
  • II 对象的相等性 & 本体性
    • 2.1 相等性检查
    • 2.2 Foundation 框架中,自己实现的相等性检查
    • 2.3 字符串驻留
  • III 代码重构(前提是已经实现了基本功能)
  • see also

前言

字典转模型

/** 通常实现字典实例化模型,都实现了以下模型的实例化方法*/
//使用字典实例化模型
- (instancetype) initWithDictionary :(NSDictionary *) appDictionary;
//类方法可以快速实例化一个对象--把代码放在它最应该呆的地方
+ (instancetype) appInfoWithDictionary : (NSDictionary *) appDictionary;
//返回plist文件对应的模型数组 ,使用懒加载

KVC的赋值

- (instancetype) initWithDictionary:(NSDictionary *)appDictionary{
    //self is object
    self = [super init];
    if (self) {//既然nil解析成NO,所以没有必要在条件语句比较。不要拿某样东西直接与YES比较,因为YES被定义为1
        //init local vars 将plist文件的信息在此处进行字典转模型
        //KVC (key value coding) 键值编码:是一种间接修改、读取对象属性的一种方法;KVC被称为cocoa的大招
        [self setValuesForKeysWithDictionary:appDictionary];//本质上是调用        self setValue:<#(nullable id)#> forUndefinedKey:(nonnull NSString *)
    }
    return self;
}

I 字典转模型

  • 使用字典的坏处

通常取出和修改数据字典的数据,都要通过编写“字符串类型”的key值-》编辑器IDE没有智能提示、手动写key容易写错,且此时IDE不会有任何的警告和报错。 字典的使用例子

dict[@"name"] = @"Jack";
NSString *name = dict[@"name"];
  • 使用数据模型的好处

1)数据模型(专门用来存放数据的对象),使用数据模型表示数据更专业些

2)使用模型修改数据、读取数据均采用对象的属性,提高编写效率

1.1 字典转模型的实现步骤

1)字典转模型的过程,通常被封装在模型内部

2)模型应该提供一个“带有NSDictionary类型”参数的构造方法

- (instancetype)initWithDict:(NSDictionary*)dict;
+ (instancetype)xxxWithDict:(NSDictionary*)dict;

1.2 字典转模型的过程

  • [采用KVC(keyValueCoding)实现] plist文件解析-》字典数组(NSDictionary)-》模型数组(AppInfo)

使用字典实例化模型 (把代码放在它最应该呆的地方)

- (instancetype) initWithDictionary:(NSDictionary *)appDictionary{
    //self is object
    self = [super init];
    if (self) {//既然nil解析成NO,所以没有必要在条件语句比较。不要拿某样东西直接与YES比较,因为YES被定义为1
        //init local vars 将plist文件的信息在此处进行字典转模型
        //KVC (key value coding) 键值编码:是一种间接修改、读取对象属性的一种方法;KVC被称为cocoa的大招
        [self setValuesForKeysWithDictionary:appDictionary];
    }
    return self;
}
//使用类方法实现“字典实例化模型”--地道的代码
+ (instancetype) appInfoWithDictionary:(NSDictionary *)appDictionary{
    //self is class
    return [[self alloc]initWithDictionary:appDictionary];//+ (instancetype)alloc    Description    Returns a new instance of the receiving class.
}
@end
  • 使用KVC的注意事项:

1、plist文件中的键值名称必须与模型对象的属性名称一致

2、模型中的属性,可以不全部出现在plist文件中

II 对象的相等性 & 本体性

一个对象的本体和它的内存地址是相关联的。 NSObject 的isEqual:本质上是对本体性的检查,即两个 NSObject 如果指向了同一个内存地址,那它们就被认为是相同的。

当两个物体有一系列相同的可观测的属性时,两个物体可能是互相相等 。

2.1 相等性检查

对象相等性检查的主要应用场景:确定一个对象是不是一个集合的成员,对于 NSArray,NSDictionary 和 NSString 容器类来说,更加有用的是进行相等性检查,即对于集合中的每个成员进行判断,因此我们需要重写isEqual: 。

重写 isEqual:

  • 先进行本体性检查,如果失败,就进行实际内容(意义)上的比较,比如判断其中几个主要特性的属性。
- (BOOL)isEqual:(id)object {
  if (self == object) {
    return YES;
  }
  if (![object isKindOfClass:[Person class]]) {
    return NO;
  }
  return [self isEqualToPerson:(Person *)object];//关键属性的判断,比如身份证ID
}
  • 重写 hash 方法,便于快速地(O(1)) 进行元素查找。

相对于数组把元素按顺序存储(0, 1, ..., n-1),散列表在内存中分配 n 个位置,然后使用一个散列函数来计算出位置范围之内的某个具体位置。

hash 得到的值不必是唯一可区分的,如果发生了散列碰撞,散列表会从碰撞产生的位置开始向后寻找,把新的元素放在第一个可供放置的位置。

@implementation NSDate (ex)
- (NSUInteger)hash {
  return (NSUInteger)abs([self timeIntervalSinceReferenceDate]);
}

对关键属性的散列值进行一个简单的二进制移位操作,即可简单的实现对象的hash 函数:

@implementation UIColor (ex)
/**
>左移运算符(<<):按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。
*/
- (NSUInteger)hash {
  CGFloat red, green, blue;
  [self getRed:&red green:&green blue:&blue alpha:nil];
  return ((NSUInteger)(red * 255) << 16) + ((NSUInteger)(green * 255) << 8) + (NSUInteger)(blue * 255);
}
@end

对关键属性的散列值进行一个简单的XOR操作

/**
异或 ^ 相同为0,不相同为1;
应用场景:密码加密、散列值计算。
*/
- (NSUInteger)hash {
  return [self.id hash] ^ [self.birthday hash];
}

2.2 Foundation 框架中,自己实现的相等性检查

NSAttributedString -isEqualToAttributedString:

NSData -isEqualToData:

NSDate -isEqualToDate:

NSDictionary -isEqualToDictionary:

NSHashTable -isEqualToHashTable:

NSIndexSet -isEqualToIndexSet:

NSNumber -isEqualToNumber:

NSOrderedSet -isEqualToOrderedSet:

NSSet -isEqualToSet:

NSString -isEqualToString:

NSTimeZone -isEqualToTimeZone:

NSValue -isEqualToValue:

2.3 字符串驻留

字符串驻留的优化技术: 把一个不可变字符串对象的值拷贝给各个不同的指针。

Objective-C 选择器的名字也是作为驻留字符串储存在一个共享的字符串池当中的。

NSString *stra = @"Hello";
NSString *strb = @"Hello";
BOOL wt = (stra == strb); // YES

选择器的比较

OBJC_EXPORT BOOL
class_respondsToSelector(Class _Nullable cls, SEL _Nonnull sel)
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
- (BOOL)respondsToSelector:(SEL)aSelector;
if([device respondsToSelector:@selector(setSmoothAutoFocusEnabled:)]){
}

III 代码重构(前提是已经实现了基本功能)

开发前:设定开发计划、步骤 开发过程中:每一个步骤告一段落之后,我们要暂停,进行代码审核,有针对性的重构(抽离重复代码,模型和视图各尽职责)

代码重构的原则: 把代码放在它最应该呆的地方

1、使用类方法实现字典实例化模型 (模型,通常是plist文件,网络)

使用类方法实例化模型数组

//类方法可以快速实例化一个对象--把代码放在它最应该呆的地方
+ (instancetype) appInfoWithDictionary : (NSDictionary *) appDictionary;
//返回plist文件对应的模型数组 ,使用懒加载
+ (NSArray *)appList;

2、使用类方法实例化视图对象,并用数据模型装配视图内容

用类方法进行视图的实例化

+ (instancetype) appView;//使用类方法加载xib
+ (instancetype) appViewWithAppInfo:(KNAppInfo *) appInfo;//使用类方法加载xib,参数用于视图的数据装配

see also

更多内容请关注 #小程序:iOS逆向,只为你呈现有价值的信息,专注于移动端技术研究领域;

以上就是iOS小技能之字典转模及对象相等性示例详解的详细内容,更多关于iOS字典转模对象相等性的资料请关注我们其它相关文章!

时间: 2022-08-16

iOS调试Block引用对象无法被释放的小技巧分享

Block技术在iOS开发中非常流行也很方便,但是稍微疏忽就可能会产生引用无法被释放的问题,从而造成内存泄漏.那如何知道哪个Block持有了对象并造成内存泄漏呢? 一个解决的方法是在程序运行时通过Xcode的Debug Memory Graph 来查看当前进程中所有生命周期内的对象.这样可以在调试时通过这个功能发现一些本来应该被释放但是却没有被释放的对象.从而确定哪些对象有内存泄漏的嫌疑. 当点击某个对象时,右边可以看出这个对象的内存分配情况以及被引用的情况,从而可以进一步跟踪确认出对象是被谁持

IOS开发之字典转字符串的实例详解

IOS开发之字典转字符串的实例详解 在实际的开发需求时,有时候我们需要对某些对象进行打包,最后拼接到参数中 例如,我们把所有的参数字典打包为一个 字符串拼接到参数中 思路:利用系统系统JSON序列化类即可,NSData作为中间桥梁 //1.字典转换为字符串(JSON格式),利用 NSData作为桥梁; NSDictionary *dic = @{@"name":@"Lisi",@"sex":@"m",@"tel&qu

iOS关联对象示例详解

背景 在iOS开发中如果我们想给一个对象动态添加属性或者给category添加属性的时候,都是通过runtime的关联对象去实现,那我们添加的属性到底是如何存取的呢?是直接添加到了对象自身的内存中了去吗?带着这些疑问让我们看一runtime的源码,解开关联对象的神秘面纱. 关联对象源码 存值 void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) { _o

详解iOS应用UI开发中的九宫格坐标计算与字典转换模型

九宫格坐标计算 一.要求 完成下面的布局 二.分析 寻找左边的规律,每一个uiview的x坐标和y坐标. 三.实现思路 (1)明确每一块用得是什么view (2)明确每个view之间的父子关系,每个视图都只有一个父视图,拥有很多的子视图. (3)可以先尝试逐个的添加格子,最后考虑使用for循环,完成所有uiview的创建 (4)加载app数据,根据数据长度创建对应个数的格子 (5)添加格子内部的子控件 (6)给内部的子控件装配数据 四.代码示例 复制代码 代码如下: // //  YYViewC

iOS中使用对象的弱引用示例代码

简介 我们都知道使用 UIImage imageNamed 创建的 UIImage 对象会被持有(强引用),如果图片太大会占用内存,损耗 APP 的性能,影响用户体验,如果能改造对其的强引用变为弱引用就可以解决问题. 我们可能会有类似上面的场景,有些对象暂时保存起来,可能后面会用到,也有可能不会使用,但是又不想去管理它们的生命周期,如果它们能够自己被销毁就很省事,不需要去关心这些对象到底耗费了多少内存. 今天跟大家聊聊如何在 iOS 开发中保持对对象的弱引用而不是强引用,希望看完之后,能帮助到大

iOS中 LGLAlertView 提示框的实例代码

使用与iOS8 以后,只是把系统的UIAlertController进行了封装,省的每次用的时候要写很多的代码.封装后只需要一句代码即可 , deome 地址 :https://github.com/liguoliangiOS/LGLAlertView.git 上代码LGLAlertView.h: #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> typedef NS_ENUM(NSInteger, LGLAlert

iOS中长条蓝色按钮(button)实现代码

一,效果图. 二,代码. ViewController.m - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //添加设备 UIButton *deviceButton=[UIButton buttonWithType:UIButtonTypeRoundedRect]; deviceButton.frame=CGRe

vue组件中使用iframe元素的示例代码

本文介绍了vue组件中使用iframe元素的示例代码,分享给大家,具体如下: 需要在本页面中展示vue组件中的超链接,地址栏不改变的方法: <template> <div class="accept-container"> <div class="go-back" v-show="goBackState" @click="goBack">GoBack</div> <ul&g

iOS 对view进行截图的示例代码

本文主要介绍了iOS 对view进行截图的示例代码,分享给大家,具体如下: 需要对WKWebView进行截图,之前用的是下面的方法,高版本的系统是没有问题的,低版本的却截到一张白图 - (UIImage *)convertViewToImage:(UIView *)view{ // 第二个参数表示是否非透明.如果需要显示半透明效果,需传NO,否则YES.第三个参数就是屏幕密度了 UIGraphicsBeginImageContextWithOptions(CGSizeMake(view.boun

ASP.NET Core MVC 中实现中英文切换的示例代码

哈喽..大家好 很久没有更新了,今天就来一篇最近开发用到的功能,那就是中英文切换,这个实际上也不是高大上,先说一下原理,在.NET Core框架中给我们提供了全球化的类,叫做Localization,其官方的文档地址传送门. 在我的项目中,我是这样操作的,你想用别的方式,也可以看文档自己去搞.这个已经不是什么新鲜的东西了,只是网上的实现有些问题,不容易明白. 我们无需任何Nuget包,因为它是在Microsoft.AspNetCore.Mvc.Localization中,那么我们直接在.NET

Python 实现黑客帝国中的字符雨的示例代码

本教程很简单吧,除了复制代码之外,希望你也抽点时间去看下"注意",教程很简单,有问题请留言 废话不多数,先上图 注意 本项目中,需要用到文件库"pygame",不会的小伙伴,可以参考我的PyCharm教程里面有详细的讲解如何添加库:对于没有字体ttf的小伙伴,也不必担心,可以去这个链接下载,完全能够满足你的平日使用需求: # !/usr/bin/env python # -*- coding:utf-8 -*- # @Time : 2020.2 # @Author

在pycharm中创建django项目的示例代码

在pycharm中创建django项目的方法步骤,分享给大家,具体如下: 创建完成后,我们可以看看django项目是否可以启动 在Terminal 中输入命令 python manage.py runserver 能看到一下界面证明启动成功 在项目的时候肯定会用到数据库 所以我们需要进入settings中更改数据库的配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': "django_test&qu

iOS如何为圆角添加阴影效果示例代码

前言 大家都知道在iOS中为UIView添加阴影还是比较简单的,只需要设置layer的shadow属性就可以了,但是问题在于设置阴影之后,必须设置masksToBounds为NO,而圆角图片则要求masksToBounds必须为YES,两者相互冲突,会导致无法正确的添加阴影.下面就来给大家介绍正确为圆角添加阴影的效果,话不多说了,来一起看看详细的介绍吧. 先来看看效果图: 正确的做法: 先创建一个透明的UIView,并添加阴影,设置masksToBounds为NO: 然后在透明的UIView上添

iOS中捕获日志与异常示例详解

前言 在平时自己调试的时候,可以直接连接电脑,直接在窗口中查看结果.但是在测试人员测试,或者灰度测试的时候,怎么才能拿到日志呢?最先想到的肯定是输出到本地文件,然后在需要的时候进行上传. 分享一段之前找到的方法,下面的代码提供了两个主要功能: – 把日志输出到文件中 – 捕捉异常信息 [解析都写在注释中了] 示例代码 - (void)redirectNSLogToDocumentFolder { //如果已经连接Xcode调试则不输出到文件 //该函数用于检测输出 (STDOUT_FILENO)