Skip to content

Objc DataStructure

Deepin edited this page Aug 24, 2022 · 34 revisions

了解一门语言,往底层挖,不得不提数据结构,这里我们将从“数据结构”和“数据类型”两个角度来分析OC这门语言的数据结构。

http://www.cocoachina.com/articles/23270 https://mp.weixin.qq.com/s/MIdIRkwmtZu3eJv6ZGuJ9g

https://www.jianshu.com/p/c0c6bf1b0abe

https://www.baidu.com/s?wd=oc%E4%B8%AD%E7%9A%84UnitType&rsv_spt=1&rsv_iqid=0x94bd964800000821&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&rqlang=cn&tn=baiduhome_pg&rsv_dl=tb&rsv_enter=1&oq=UnitType&rsv_btype=t&inputT=2338&rsv_t=6a6d%2F%2FB6YTIi3meCzV0fwAMgwLt%2FXctNKKgZf9H8ov3LBk3BFApuH7Jg6RHsougAbAl3&rsv_sug3=8&rsv_sug1=1&rsv_sug7=100&rsv_pq=8fc9200100000b1c&rsv_sug2=0&rsv_sug4=4697

一、数据结构

Q: 什么是数据结构呢?
A: 数据结构是以某种特定的布局方式存储数据的容器。这种“布局方式”决定了数据结构对于某些操作是高效的,而对于其他操作则是低效的。

数据结构通常分为以下八大类:

  1. 数组 - Array
  2. - Heap
  3. - Stack
  4. 队列 - Queue
  5. 链表 - Linked List
  6. - Graph
  7. 散列表 - Hash哈希表
  8. - Tree (字典树:这是一种高效的树形结构)

以上这些似乎更加笼统和全局,接下来,我们从日常接触较多的数据类型角度来详细分析一下。

二、数据类型

Objective-C(以下简称OC)这门语言是C语言的严格超集,相比于C, OC是一门面向对象语言, 如同C++一样支持用户定义类型Class。用户定义类型为Cocoa框架的诞生提供了可能。OC数据类型, 实际上指的是C数据类型加上Cocoa框架集合(Foundation、UIKit等)中定义的的数据类型,也即Cocoa类(泛指所有基于OC运行时且派生自根类NSObject的类)。 OC中可以使用的数据类型可以用下面的公式来表示:

OC数据类型 = C数据类型 + Cocoa类型

那么我们可以列出OC数据类型的大体层次结构如下:

  • OC数据类型
    • C数据类型
      • 基本数据类型
        • int(整型)
        • char(字符型)
        • float\double(浮点型)
        • bool(布尔类型)
        • enum(枚举型)
      • struct\union(构造类型)
      • pointer(指针类型)
      • void(空类型)
    • Cocoa类型
      • OC基本数据类型
        • CGFloat
        • NSInteger
        • NSUInteger
        • BOOL
      • NSObject对象数据类型-引用数据类型(列举出几种)
        • NSData
        • NSNumber
        • NSArray - NSMutableArray
        • NSSet - NSMutableSet
        • NSDictionary - NSMutableDictionary
        • NSString - NSMutableString
        • ...

三、数据类型详解

OC中Cocoa的数据类型是基于NSObject这个“万物之源”的,其实内部是基于struct结构体(这个将在后续分析),而结构体是C的数据类型,本身OC本身可以使用C中的数据类型,那么我们势必要从源头先分析C中的数据类型。

像 int、float、char 等是由C语言本身提供的数据类型,不能再进行分拆,我们称之为基本数据类型;而结构体可以包含多个基本类型的数据,也可以包含其他的结构体,我们将它称为复杂数据类型构造数据类型

1. C基本数据类型

基本数据类型(fundamental data types)也叫原始数据类型(primitive data types)。

  • 基本数据类型
    • int(字符型)
    • char(整型)
    • float\double(浮点型)
    • bool(布尔类型)
    • enum(枚举型)

在计算机的对应不同的编译器存储字节如下:

数据类型 16位编译器 32位编译器 64位编译器
char 1byte 1byte 1byte
int 2byte 4byte 4byte
float 4byte 4byte 4byte
double 8byte 8byte 8byte
bool 8byte 8byte 8byte
long 4byte 4byte 8byte

iOS 5S以后的手机对应系统都是64位的,主要看64位的即可。

    NSLog(@"char字节数----%lu",sizeof(char));
    NSLog(@"bool字节数----%lu",sizeof(bool));
    NSLog(@"short字节数----%lu",sizeof(short));
    NSLog(@"int字节数----%lu",sizeof(int));
    NSLog(@"long字节数----%lu",sizeof(long));
    NSLog(@"float字节数----%lu",sizeof(float));
    NSLog(@"double字节数----%lu",sizeof(double));
    
    NSLog(@"short int字节数----%lu",sizeof(short int));
    NSLog(@"long int字节数----%lu",sizeof(long int));
    NSLog(@"long double字节数----%lu",sizeof(long double));
2022-08-24 15:01:44.187758+0800 InterviewSample[48525:3037966] char字节数----1
2022-08-24 15:01:44.191498+0800 InterviewSample[48525:3037966] bool字节数----1
2022-08-24 15:01:44.192965+0800 InterviewSample[48525:3037966] short字节数----2
2022-08-24 15:01:44.193364+0800 InterviewSample[48525:3037966] int字节数----4
2022-08-24 15:01:44.193581+0800 InterviewSample[48525:3037966] long字节数----8
2022-08-24 15:01:44.193858+0800 InterviewSample[48525:3037966] float字节数----4
2022-08-24 15:01:44.194046+0800 InterviewSample[48525:3037966] double字节数----8
2022-08-24 15:01:44.194212+0800 InterviewSample[48525:3037966] short int字节数----2
2022-08-24 15:01:44.194453+0800 InterviewSample[48525:3037966] long int字节数----8
2022-08-24 15:01:44.195106+0800 InterviewSample[48525:3037966] long double字节数----16

总结:NSInteger与int的区别是NSInteger会根据系统的位数(32or64)自动选择int的最大数值(int or long)。 1、Integer默认值是null,而int默认值是0; 2、声明为Integer的变量需要实例化,而声明为int的变量不需要实例化; 3、Integer是对象,用一个引用指向这个对象;而int是基本类型,直接存储数值。

从16位到32位再到64位的变化, 影响的主要是语言内置类型所占的字节数以及字节对齐的不同。在32位的年代,使用的是IPL32的规范,到了64位之后,改成了LP64规范。除了这些以外,还有浮点类型,数据类型里面,NSInteger在32位时等同于int,在64位时等同于long,而这个数据结构使用非常广,非常多不规范的时候会直接和int替换使用,在32位是毫无问题,但在64位时。这就是隐患了。CGFloat也有相同的问题,所以代码的检查改动必须细致。至于对齐,假设使用了偏移量来访问struct的项,那么须要认真细致的检查,其余的还算好。当然假设你用了malloc,那么也请检查一下分配的内存大小。建议是多使用sizeof来帮助计算。

1.1. 字符型 chart

  • char类型代表字符类型,存放点个字符,用单引号引用起来。如:’A’,如果要表示一些特殊字符,要使用转义字符“\”。
  • NSLog函数中格式化字符串:%c。

1.2. 整型 int

  • int类型代表整数,它的十六进制表示方式:OxFFED0D.
  • 在使用NSLog函数中格式化字符串使用%i表示十进制的整数,%o(字母o)表示8进制整数,%#x表示十六进制整数,它的取值范围是与设备相关的,无法一概而论。

1.3. 浮点型

1.3.1. 单精度浮点型 float
  • float类型表示代表单精度浮点数,可以在数值后面加上f或者F,例如:13.5f。float浮点数也可以用科学计数法表示,例如:1.7e4。
  • NSLog函数中格式化字符串:%f表示浮点数(会保留后面6位小数),%e表示科学计数法,%g表示浮点数。
1.3.2. 双精度浮点型 double
  • double类型代表双精度浮点数,与float数相似,占用的字节空间double类型大体上是float类型的两倍。大多数计算机是使用64位,表示double类型。
  • NSLog函数中格式化字符串,与float的%f、%e和%g相同。

1.4. 布尔 bool

在计算机内部以int类型存储, 布尔类型是_Bool(别名BOOL),取值范围是1或0,其中1可以用TURE和YES表示,0可以用FALSE和NO表示。

1.5. 枚举类型 enum

枚举类型(在计算机内部以int类型存储):如果需要定义一组相关常量,可以采用枚举类型,把这些常量定义成一个类型,例如游戏在上、下、左、右方向,可以枚举类型:enum direction{up,down,left,right}.其中,up从0开始,down是1,以此类推加1。如果不想从0开始,也可以指定初始值,如:enum direction{up=1,down,left,right}。

1.6. 数据类型的专用限定词: 那些大牛专用技术型文件爱标注这些"技术类限定词"。

可以在int、float和double、char类型前面加上限定词,限定词有:long、longlong、short、unsigned和signed,这些限定词从而增强了基本类型。

  • long int:在大部分计算机中代表32位整数,在整数后面加L(或l)表示,如:long int numberOfPoints = 1310L.NSLog函数中格式化字符串使用%li表示。
  • long long int:可以指定更加宽泛的整数类型,保证变量至少64位宽度。NSLog函数中格式化字符串使用%lli表示。
  • long double:可以指定更为宽泛的double类型,要显示这个可以在尾部使用L(大小写)表示,1.23+7L.NSLog函数中格式化字符串使用%Lf、%Le和%Lg表示。
  • short int:用来指定存放相对小得整数,一般式占用int类型的一半。大部分计算机是16位。
  • unsigned int(无符号整数):告诉编译器只是接受整数,在数值之后存放字母u(或U)表示,例如:0x00ffU;在编写整数的时候,可以将字母u(或U)和l(或L)组合起来,例如:100UL.
  • signed char(char在计算机中存的也是整数,所以有符号和无符号之分。):代表的字符和编译器有关,一般也作为无符号整数使用。
数据类型 16位编译器 32位编译器 64位编译器
short int 2byte 2byte 2byte
unsigned int 2byte 4byte 4byte
unsigned long 4byte 4byte 8byte
long long 8byte 8byte 8byte

考虑到在计算机中的存储形式,C语言的基本数据类型其实可以总结为: 字符型整型浮点型, 其中枚举型还有布尔类型在计算机内部以int类型存储; 而floatdouble都属于浮点型

long long 的级别高于long ,long 的级别高于 int ,int 的级别高于 short ,short 的级别高于 char 。(另外有 _Bool 永远是最低级别)。级别高的整数类型的宽度大于等于级别较低的整数类型。

2. 构造类型

构造类型包括: 数组类型, 结构体类型(struct), 共用/联合体类型(union)。其中union一般在对单片机等内存比较小的设备进行编程时才使用。

3. 指针类型

指针(Pointer)就是内存的地址,C语言允许用一个变量来存放指针,这种变量称为指针变量。指针变量可以存放基本类型数据的地址,也可以存放数组、函数以及其他指针变量的地址。

data_type *pointer_name

由于指针在实质上是一个内存地址,内存地址的长度跟CPU的寻址有关(与data_type无关), 所以在32位系统上, 指针占据4个字节;在64位系统上,指针占据8个字节.

4. 空类型

空类型一般用于函数的返回值,表示不需要返回任何类型。由于void类型只是一个抽象概念,并不会存在于内存中,自然就没有字节占用。

OC数据类型

Foundation框架中定义的NSObject类是iOS中最重要的数据类型,用户定义的类都需要继承自它从而获得调用iOS系统资源的能力。Foundation中还有一个重要的集合(Collection)概念,其包含了NSArray、NSSet、NSDictionarry以及各自的可变类型;此外,还有NSString、NSMutabString、NSNumber等重要的类型。以上提及的类型均继承自NSObject,是用户定义类型(class)而并非构造类型(struct),它们在被赋值或者被传入函数或者方法时,不会发生值拷贝,而是传递现有实例的引用。

我们先来看看C里面有哪些数据类型。

C数据类型

  • 基本数据类型
  • 构造类型
  • 指针类型
  • 空类型

boolean.h文件中,我们可以看到

#if defined(__x86_64__) && !defined(KERNEL)
typedef unsigned int    boolean_t;
#else
typedef int             boolean_t;
#endif
/// Type to represent a boolean value.
#if (TARGET_OS_IPHONE && __LP64__)  ||  TARGET_OS_WATCH
#define OBJC_BOOL_IS_BOOL 1
typedef bool BOOL;
#else
#define OBJC_BOOL_IS_CHAR 1
typedef signed char BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#endif

#if __has_feature(objc_bool)
#define YES __objc_yes
#define NO  __objc_no
#else
#define YES ((BOOL)1)
#define NO  ((BOOL)0)
#endif

OC中可用的数据类型可以分为: C基本数据类型OC对象数据类型两大类。接下来我们将详细分析一下之间的关联。

typedef signed char           int8_t;
typedef short                   int16_t;
typedef int                     int32_t;
typedef long long               int64_t;

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;

typedef unsigned int    u_int;

#ifdef __LP64__
typedef long unsigned int uintmax_t;
#else
typedef long long unsigned int uintmax_t;

typedef unsigned char                   UInt8;
typedef signed char                     SInt8;
typedef unsigned short                  UInt16;
typedef signed short                    SInt16;

#if __LP64__
typedef unsigned int                    UInt32;
typedef signed int                      SInt32;
#else
typedef unsigned long                   UInt32;
typedef signed long                     SInt32;
#endif

#if __LP64__ || 0 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif

typedef unsigned char                   Boolean;

#if defined(__x86_64__) && !defined(KERNEL)
typedef unsigned int    boolean_t;
#else
typedef int             boolean_t;
#endif

typedef float               Float32;
typedef double              Float64;

/* Definition of `CGFLOAT_TYPE', `CGFLOAT_IS_DOUBLE', `CGFLOAT_MIN', and
   `CGFLOAT_MAX'. */

#if defined(__LP64__) && __LP64__
# define CGFLOAT_TYPE double
# define CGFLOAT_IS_DOUBLE 1
# define CGFLOAT_MIN DBL_MIN
# define CGFLOAT_MAX DBL_MAX
#else
# define CGFLOAT_TYPE float
# define CGFLOAT_IS_DOUBLE 0
# define CGFLOAT_MIN FLT_MIN
# define CGFLOAT_MAX FLT_MAX
#endif

/* Definition of the `CGFloat' type and `CGFLOAT_DEFINED'. */

typedef CGFLOAT_TYPE CGFloat;

#if __FLT_EVAL_METHOD__ == 0
    typedef float float_t;
    typedef double double_t;
#elif __FLT_EVAL_METHOD__ == 1
    typedef double float_t;
    typedef double double_t;
#elif __FLT_EVAL_METHOD__ == 2 || __FLT_EVAL_METHOD__ == -1
    typedef long double float_t;
    typedef long double double_t;
#else /* __FLT_EVAL_METHOD__ */
#   error "Unsupported value of __FLT_EVAL_METHOD__."
#endif /* __FLT_EVAL_METHOD__ */

以下待整理

和 id类型 :
> 注:由于在OC中BOOL实际上是signed char类型的重命名,NSInteger等也大同小异,因而并没有将它们归为新的类型。
从可以知道OC中`Class`与`NSObject`都是基于`Struct`, 接下来我们将`指针类型`及`构造类型`中的`结构体类型Struct`挑出来重点分析
基本数据类型有:int、float、double和char类型。
对象类型就是 类 或 协议 所声明的指针类型,例如:
NSAutoreleasePool *pool ,其中,NSAutoreleasePool是一个类,NSAutoreleasePool *是它指针类型 或叫 对象类型。
id类型可以表示任何类型,一般只是表示对象类型,不表示基本数据类型,所以刚才的变量可以声明 pool 也可以声明为 id pool。
类型解释:

1. C基本数据类型

2. C构造类型

结构体类型

(a).C语言本身提供的数据类型很少,那么C语言是如何构造复杂的数据类型呢?有三种方法:结构体、指针、数组。 (b).结构体和指针在iOS编程是至关重要的,在OC中很少需要C的数组,因为OC有它自己的NSArray类型。 (c).C的结构体是一个混合数据类型,在这个类型中包含了多种数据类型(也可以是另一个结构体),它能够作为单个的实体被传递。其中的元素通过点符号来访问。例如:

一个CGPoint定义如下:

struct CGRect{
CGRect x;
CGRect y;
};

typedef struct CGPoint

3. C指针类型

4. C空类型

5. OC基本数据类型

OC的基本数据类型主要来源于C中的基本数据类型、C中的构造类型、C中的指针类型以及对象类型

6. OC对象数据类型

OC中的Cocoa框架类型如下,主要是在Foundation中,结构如下:

  • Cocoa类型
    • C基本数据类型-变名
      • CGFloat
      • NSInteger
      • NSUInteger
      • BOOL
    • NSObject对象数据类型
      • Collection
        • NSArray
        • NSMutableArray
        • NSSet
        • NSMutableSet
        • NSDictionary
        • NSMutableDictionary
      • NSString
      • NSMutableString
      • NSNumber

NSNumber

@interface NSNumber : NSValue

- (NSNumber *)initWithChar:(char)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedChar:(unsigned char)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithShort:(short)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedShort:(unsigned short)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithInt:(int)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedInt:(unsigned int)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithLong:(long)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedLong:(unsigned long)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithLongLong:(long long)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedLongLong:(unsigned long long)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithFloat:(float)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithDouble:(double)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithBool:(BOOL)value NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithInteger:(NSInteger)value API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)) NS_DESIGNATED_INITIALIZER;
- (NSNumber *)initWithUnsignedInteger:(NSUInteger)value API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)) NS_DESIGNATED_INITIALIZER;

可以看到NSNumber继承自NSValue, NSValue继承自NSObject; NSNumber有继承自C的各种初始化方法。

@interface NSIndexSet : NSObject <NSCopying, NSMutableCopying, NSSecureCoding> {
    @protected   // all instance variables are private
    struct {
        NSUInteger _isEmpty:1;
        NSUInteger _hasSingleRange:1;
        NSUInteger _cacheValid:1;
        NSUInteger _reservedArrayBinderController:29;
    } _indexSetFlags;
    union {
        struct {
            NSRange _range;
        } _singleRange;
        struct {
            void * _data;
            void *_reserved;
        } _multipleRanges;
    } _internal;
}
@interface NSRegularExpression : NSObject <NSCopying, NSSecureCoding> {
    @protected   // all instance variables are private
    NSString *_pattern;
    NSUInteger _options;
    void *_internal;
    id _reserved1;
    int32_t _checkout;
    int32_t _reserved2;
}

/* nil、NULL、NSNull / / id */ Class NSObject

数据类型转换

有了数据类型必然有各类型数据之间的转换:

1.按照数据类型占用存储不同可以自动类型转换或强制类型转换,总的原则是小存储容量类型可以自动转换成大存储容量数据类型。

2.不同类型数据间按照下面关系的从左到右(从低到高)自动转换。如下:

_Bool、char、short int、枚举类型——>int——>long int——>long long int

——>float——>double——>long double.

3.强制类型转换:

如果遵守类型转换是右到左情况,就需要强制类型转换了。强制类型转换语法形式上很简单,就是在数据前面加上(目标类型),但是这种转换是存在风险的,有可能造成数据的丢失,需要谨慎进行。

/* SEL就是对方法的一种包装。 */

(1).方法的存储位置

@interface Person:NSObject

(void)test1; (void )test2; @end

Person *person = [[Person alloc]init];

(2)在内存中如下:在内存中每个类的方法都存储在类对象中,每个方法都有一个与之对应的SEL类型的数据,根据一个SEL数据就可以找到对应的方法地址,进而调用方法。

SEL类型的定义:typedef struct objc_selector *SEL.

SEL对象的创建

SEL s1 = @selector(test1);

SEL s2 = NSSelectorFromString(@“test1”)

注意:(a).SEL类型是OC中用来定义方法的关键字,和其他语言不同的是SEL类型虽然是方法定义,但却不从属于任何类实例,其值是通过@selector进行计算,可以把它当做一个函数指针来使用,当然它实际上并不是一个函数指针,而是const char*。

(b).SEL类型可以在编译时通过@selector()直接创建,也可以用NSSelectorString()函数创建,这个函数允许你通过名字调用方法。例如:

[object performSelector:@selector(doSomething)]];

它和如下代码等价:[object doSomething];

(3).各种语言都有传递函数的方法:C语言使用函数指针,C++中有函数引用,OC使用选择器selector和block。

/* nil、NULL、NSNull */

首先要说明的是,nil、Nil、NULL三个关键字和NSNull类都是表示空,它们本质上都是一样的,都是(void *)0,既然写法不同,那么代表用处也不一样,这样做的意义是为了区分不同的数据类型,比如你一看到用到了NULL就知道这是个C指针,看到nil就知道这是个Objective-C对象,看到Nil就知道这是个Class类型的数据。具体的区别如下:

(a).nil用来给对象赋值(OC的任何对象都属于id类型),Null则给任何指针赋值,NULL和nil不能互换,nil用于类指针赋值(在OC中类是一个对象,是类的meta-class的实例),而NSNull则用于集合操作,虽然它们表示的都是空值,但使用场合不同。

(b).OC有个特性,就是当发送消息给nil对象使,系统返回0值而不是引起异常,这和Java的NullPointerException以及C/C++的程序直接崩溃的处理完全不同,因为nil是对象的合法值,nil对象同样可以接收消息。

(c).nil被定义为空对象,也就是值为0的对象。

/* id */

(a).在OC中最普遍的3种类型就是id、Class和SEL, id就是指向OC对象的指针,它等价于C语言中的void *,可以映射任何对象指针类型指向它,或者映射它指向其他的对象。当然,也可以传递任何消息给id,但如果该id不支持这个消息就会返回一个运行时异常。

(b).id数据类型可存储任何类型的对象。从某种意义上说,它是一般对象类型。如果要用基本类型代替,需要对基本数据类型进行封装。

(c).id是一个指向任何一个继承了Object(或者NSObject)类的对象。需要注意的是,id

是一个指针,所以在使用id的时候不需要加星号。例如:

id foo = nil;

(d).在OC中,id取代了int类型成为默认的数据类型(在C语言上的函数返回值,int是默认的返回类型)。

/* Bool */

(a).在OC中的布尔类型是BOOL,其值可以是YES或NO,也可以赋值为TRUE和FALSE。YES和TRUE等价,都是非零值;NO和FALSE等价,都是零值。

(b).在调试的时候可以通过打印数字的方式(格式为%d)输出其值,代码如下:

BOOL loginResult = YES;

NSLog(@"LoginResult is %d",loginResult);

(c).布尔变量的值为YES/NO或1/0.YES和1代表真。

/* 结构体 */

(a).C语言本身提供的数据类型很少,那么C语言是如何构造复杂的数据类型呢?有三种方法:结构体、指针、数组。

(b).结构体和指针在iOS编程是至关重要的,在OC中很少需要C的数组,因为OC有它自己的NSArray类型。

(c).C的结构体是一个混合数据类型,在这个类型中包含了多种数据类型(也可以是另一个结构体),它能够作为单个的实体被传递。其中的元素通过点符号来访问。例如:

一个CGPoint定义如下:

struct CGRect{

CGRect x;

CGRect y;

};

typedef struct CGPoint

指针类型

指针 函数指针 指针函数

结构体类型Struct

struct是oc的基础 结构体初始化后不能在定义

既然是类,我们就可以实例化一个对象 NSString *s = [NSString new]; 1)分配空间 2)初始化 3)返回地址

NSArray

排序
  • 逆序,array.reverseObjectEnumerator.allObjects
  • 数组中是字符串对象排序首选sortedArrayUsingSelector:
NSArray *array = @[@"John Appleseed", @"Tim Cook", @"Hair Force One", @"Michael Jurewitz"];
NSArray *sortedArray = [array sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
  • 存储内容是数字
NSArray *numbers = @[@9, @5, @11, @3, @1];
NSArray *sortedNumbers = [numbers sortedArrayUsingSelector:@selector(compare:)];
  • 使用函数指针sortedArrayHint排序
- (NSData *)sortedArrayHint;
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator
     context:(void *)context;
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator
     context:(void *)context hint:(NSData *)hint;
  • 基于block的排序方法
- (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr;
- (NSArray *)sortedArrayWithOptions:(NSSortOptions)opts
     usingComparator:(NSComparator)cmptr;
  • 性能比较selector最快
Sorting 1000000 elements. selector: 4947.90[ms] function: 5618.93[ms] block: 5082.98[ms].
  • 更快的二分查找
typedef NS_OPTIONS(NSUInteger, NSBinarySearchingOptions) {
     NSBinarySearchingFirstEqual = (1UL << 8),
     NSBinarySearchingLastEqual = (1UL << 9),
     NSBinarySearchingInsertionIndex = (1UL << 10),
};

- (NSUInteger)indexOfObject:(id)obj
     inSortedRange:(NSRange)r
     options:(NSBinarySearchingOptions)opts
     usingComparator:(NSComparator)cmp;

//Time to search for 1000 entries within 1000000 objects. Linear: 54130.38[ms]. Binary: 7.62[ms]

枚举

  • 使用indexesOfObjectsWithOptions:passingTest:
NSIndexSet *indexes = [randomArray indexesOfObjectsWithOptions:NSEnumerationConcurrent
     passingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
     return testObj(obj);
}];
NSArray *filteredArray = [randomArray objectsAtIndexes:indexes];
  • 传统的枚举
NSMutableArray *mutableArray = [NSMutableArray array];
for (id obj in randomArray) {
     if (testObj(obj)) {
          [mutableArray addObject:obj];
     }
}
  • block方式枚举
NSMutableArray *mutableArray = [NSMutableArray array];
[randomArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
     if (testObj(obj)) {
          [mutableArray addObject:obj];
     }
}];
  • 通过下标objectAtIndex:
NSMutableArray *mutableArray = [NSMutableArray array];
for (NSUInteger idx = 0; idx < randomArray.count; idx++) {
     id obj = randomArray[idx];
     if (testObj(obj)) {
          [mutableArray addObject:obj];
     }
}
  • 使用比较传统的学院派NSEnumerator
NSMutableArray *mutableArray = [NSMutableArray array];
NSEnumerator *enumerator = [randomArray objectEnumerator];
id obj = nil;
while ((obj = [enumerator nextObject]) != nil) {
     if (testObj(obj)) {
          [mutableArray addObject:obj];
     }
}
  • 使用predicate
NSArray *filteredArray2 = [randomArray filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id obj, NSDictionary *bindings) {
     return testObj(obj);
}]];
  • 各个方法枚举时间参考,indexesOfObjectsWithOptions在开启了并发枚举的情况下比NSFastEnumeration快一倍。
枚举方法 / 时间 [ms] 10.000.000 elements 10.000 elements
indexesOfObjects:, concurrent 1844.73 2.25
NSFastEnumeration (for in) 3223.45 3.21
indexesOfObjects: 4221.23 3.36
enumerateObjectsUsingBlock: 5459.43 5.43
objectAtIndex: 5282.67 5.53
NSEnumerator 5566.92 5.75
filteredArrayUsingPredicate: 6466.95 6.31

NSDictionary

性能

同样数目的值,NSDictionary比NSArray要花费多得多的内存空间

排序

使用NSArray的排序方法将键数组排序为新的对象

- (NSArray *)keysSortedByValueUsingSelector:(SEL)comparator;
- (NSArray *)keysSortedByValueUsingComparator:(NSComparator)cmptr;
- (NSArray *)keysSortedByValueWithOptions:(NSSortOptions)opts
     usingComparator:(NSComparator)cmptr;
枚举
  • keysOfEntriesWithOptions:passingTest:,可并行
NSSet *matchingKeys = [randomDict keysOfEntriesWithOptions:NSEnumerationConcurrent
passingTest:^BOOL(id key, id obj, BOOL *stop)
{
     return testObj(obj);
}];
NSArray *keys = matchingKeys.allObjects;
NSArray *values = [randomDict objectsForKeys:keys notFoundMarker:NSNull.null];
__unused NSDictionary *filteredDictionary = [NSDictionary dictionaryWithObjects:values
     forKeys:keys];
  • getObjects:andKeys: 枚举,基于c数组
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary];
id __unsafe_unretained objects[numberOfEntries];
id __unsafe_unretained keys[numberOfEntries];
[randomDict getObjects:objects andKeys:keys];
for (int i = 0; i < numberOfEntries; i++) {
     id obj = objects[i];
     id key = keys[i];
     if (testObj(obj)) {
          mutableDictionary[key] = obj;
     }
}
  • block枚举
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary];
[randomDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
     if (testObj(obj)) {
          mutableDictionary[key] = obj;
     }
}];
  • NSFastEnumeration
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary];
for (id key in randomDict) {
     id obj = randomDict[key];
     if (testObj(obj)) {
          mutableDictionary[key] = obj;
     }
}
  • NSEnumeration
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary];
NSEnumerator *enumerator = [randomDict keyEnumerator];
id key = nil;
while ((key = [enumerator nextObject]) != nil) {
     id obj = randomDict[key];
     if (testObj(obj)) {
          mutableDictionary[key] = obj;
     }
}
  • 各个方法枚举时间参考
枚举方法 / 时间 [ms] 50.000 elements 1.000.000 elements
keysOfEntriesWithOptions:, concurrent 16.65 425.24
getObjects:andKeys: 30.33 798.49
keysOfEntriesWithOptions: 30.59 856.93
enumerateKeysAndObjectsUsingBlock: 36.33 882.93
NSFastEnumeration 41.20 1043.42
NSEnumeration 42.21 1113.08

参考链接

iOS 数据结构总结
iOS-数据结构
iOS有哪些数据类型/基本数据类型?
基础数据类型和它的转化
C语言和OC的结构体(struct)
iOS中编写高效能结构体的7个要点
OC底层原理之《内存对齐原则》
iOS_NSSet与NSArray的区别
iOSNSSet 和 NSArray的区别

Clone this wiki locally