iOS 数组遍历删除&自定义迭代器

在iOS中,数组是无法通过迭代器删除的,无论是enumerateObjectsUsingBlock迭代器还是for in,抑或是NSEnumerator都无能为力,当然 for循环更不行了,对于java编程的同学来说无法接受啊。

当然办法还是有的是,不然我不会在这里费口舌。


我们主要有两种方式来删除数组,NSPredicate与while循环,但是性能稍有不同。当然这里也会自定义迭代器删除,也是一种不错的选择


一.使用NSPredicate删除数组元素

1.1 NSArray全部删除

NSArray * aArr = @[@1,@"A",@2.0f,@"B",@"3",@4,@5,@"6"];
aArr = [aArr filteredArrayUsingPredicate:[NSPredicate predicateWithValue:NO]];

1.2 NSArray选择性删除

 NSArray * aArr = @[@1,@"A",@2.0f,@"B",@"3",@4,@5,@"6"];
 aArr = [aArr filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id  _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
        if([evaluatedObject isKindOfClass:[NSString class]])
        {
            return NO;
        }
        return YES;
    }]];

注意:以上是NSArray的删除方式,注意,他并不是直接删除NSArray的元素,而是删除的是拷贝后的数组,因此,这种删除我们必须通过接收返回值来得到新的数组集合

如果是NSMutableArray,我们可以使用新增的方法,这种方式是直接删除,但是原理和NSArray一致,都是从内部将新的集合复制给素组

  1.3 NSMutableArray

  NSArray * aArr = @[@1,@"A",@2.0f,@"B",@"3",@4,@5,@"6"];
  NSMutableArray  * bArr = [NSMutableArray  arrayWithArray:aArr];
  
    [bArr filterUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id  _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
       
        NSLog(@"count=%ld",[bArr indexOfObject:evaluatedObject]);
        
        if([evaluatedObject isKindOfClass:[NSString class]])
        {
            return NO;
        }
        return YES;
    }]];


关于NSPredicate删除数组是一种可以选择的方法,我们从Block中打印 count发现,原数组元素基本不会改变,因此我们推测,NSPredicate过滤运行流程如下:

①NSPredicate是复制原数组,复制到一个新的集合,假定称为集合CopyA

②通过Block过滤器过滤出集合CopyA中的元素元素到另一个数组集合,假定这个集合为集合CopyB

③返回过滤数组集合CopyB,释放集合CopyA,完成赋值到初始集合


在整个过程中,出现了过多的数组元素引用和数组赋值,造成使用内存过大,如果NSArray存储的是小数据,而不是多媒体或者大文本,可以不用忌讳。但是如果涉及到大图片,我们这种删除显然是有代价的,也就是可能出现OOM问题。


二.使用while循环遍历删除(推荐)

对于while循环,他的作用对象只能是NSMutableArray,因此,对于NSArray我们需要适当的转换成NSMutableArray。

2.1选择性清除方案(迭代删除)

 NSArray * aArr = @[@1,@"A",@2.0f,@"B",@"3",@4,@5,@"6"];
 
 //数组转换
 NSMutableArray  * bArr = [NSMutableArray  arrayWithArray:aArr];
 aArr = [aArr filteredArrayUsingPredicate:[NSPredicate predicateWithValue:NO]]; //释放元素内存
 aArr = nil;
 
int  i = 0;
while(bArr.count>i)
{
   NSObject * itemObject =  [bArr objectAtIndex:i];
    if([itemObject isKindOfClass:[NSString class]])
    {
       [bArr removeObject:itemObject]; //释放
       itemObject = nil;
  }else{
      i++;
   }
}
aArr = bArr;

这种方式效率显而易见,不仅消耗内存少,而且效率相对较高,当然我们选择逆序迭代的时候结果也是一样。

NSArray * aArr = @[@1,@"A",@2.0f,@"B",@"3",@4,@5,@"6"];
 
 //数组转换
 NSMutableArray  * bArr = [NSMutableArray  arrayWithArray:aArr];
 aArr = [aArr filteredArrayUsingPredicate:[NSPredicate predicateWithValue:NO]]; //释放元素内存
 aArr = nil;
 
int  i = 0;
while(bArr.count>i)
{
    NSObject * lastObject =  [bArr lastObject];
    if([itemObject isKindOfClass:[NSString class]])
    {
       [bArr removeLastObject]; //释放
       itemObject = nil;
  }else{
      i++;
   }
}
aArr = bArr;

特别的,对于迭代全部删除,如NSArray<UIImage * > * 数组中的图片压缩存储,为了及时释放内存,这种优势会体现的更加明显

NSArray * aArr = @[@1,@"A",@2.0f,@"B",@"3",@4,@5,@"6"];
 
 //数组转换
NSMutableArray  * bArr = [NSMutableArray  arrayWithArray:aArr];
aArr = [aArr filteredArrayUsingPredicate:[NSPredicate predicateWithValue:NO]]; //释放元素内存
aArr = nil;
 
while(bArr.count>0)
{
    NSObject * lastObject =  [bArr lastObject];
   // 压缩,存储你的图片
   [bArr removeLastObject]; //释放就图片

}


三.自定义迭代器(推荐)

NSArray 自带迭代器,但删除操作会引起Crash,因此我们需要自定义自己的迭代器,实现可删除迭代器

Iterator.h文件
#import <Foundation/Foundation.h>


@protocol Iterator <NSObject>

@required
/**
* 判断数组是否还有元素
*/
-(BOOL) hasNext;
/**
* 返回数组中的元素(索引为0的元素),必须先使用hasNext判断,否则可能出现数组越界异常
*/
-(NSObject *) next;
/**
* 删除数组中的元素(索引为0的元素),必须先使用hasNext判断,否则可能出现数组越界异常
*/
-(void) remove;

@end
NSMutableArray+Helper.h类目文件
#import <Foundation/Foundation.h>

#import "Iterator.h"

@interface NSMutableArray(Helper)

/**
*
* 返回一个迭代器
*/
-(id<Iterator> ) iterator;

@end

    

NSMutableArray+Helper.m类目文件
#import "NSMutableArray+Helper.h"


/**
*
*实现私有类实现
*/
@interface NSMutableArrayIterator:NSObject<Iterator>
/**
*自定义初始化方法
* @param array 目标数组,NSMutableArray 类型
*/
-(instancetype) initWidthMutableArray:(NSMutableArray *) array;
/**
* 持有的目标数组
*/
@property (nonatomic,strong) NSMutableArray * array;

@property (nonatomic,assign) int nextIndex;
@property (nonatomic,assign) int currentIndex;


@end

@implementation NSMutableArrayIterator

-(instancetype) initWidthMutableArray:(NSMutableArray *) array
{
	if(self=[super init])
	{
		_array = array;	
		_nextIndex = 0;
		_currentIndex = 0;
	}
	return self;
}

-(BOOL) hasNext
{
	
	return _array!=nil && _array.count>_currentIndex;
}
-(NSObject *) next
{
	_nextIndex ++ ;
	_currentIndex =  _nextIndex - 1;
	
	if(_currentIndex>(_array.count-1))
	{
	     NSException *e = [NSException
                          exceptionWithName: @"索引越界"
                          reason: @"迭代索引错误,不能大于元素数量"
                          userInfo: nil];
            @throw e;
	}
	
	return  [_array objectAtIndex:(_currentIndex)];
}
-(void) remove
{

   if(_currentIndex<0)
   {
      NSException *e = [NSException
                          exceptionWithName: @"状态异常"
                          reason: @"迭代索引错误,不能小于0"
                          userInfo: nil];
       @throw e;
   }
	  
    [_array removeObjectAtIndex:(_currentIndex)];
     if (_currentIndex< _nextIndex )  
      {
         _nextIndex--;
         _nextIndex = _nextIndex>0?_nextIndex:0;
     } 
     _currentIndex= -1;  
}
@end

@implementation NSMutableArray(Helper)

-(id<Iterator>) iterator{
	
	NSMutableArrayIterator * iteratorArray = [[NSMutableArrayIterator alloc] initWidthMutableArray:self]; 
	
	return iteratorArray;
}

@end

到这一步,我们完成了整个实现,因此,对于NSArray数组删除,我们需要将其转为NSMutableArray进行删除


这里使用 Windows版本的LLVM+GNUstep编译运行Objective-C代码


090650_Oc2i_2256215.png090650_54HQ_2256215.png






转载于:https://my.oschina.net/ososchina/blog/648725

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值