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

在iOS中,数组是没法经过迭代器删除的,不管是enumerateObjectsUsingBlock迭代器仍是for in,抑或是NSEnumerator都无能为力,固然 for循环更不行了,对于java编程的同窗来讲没法接受啊。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选择性删除ui

 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的元素,而是删除的是拷贝后的数组,所以,这种删除咱们必须经过接收返回值来获得新的数组集合atom

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

  1.3 NSMutableArrayspa

  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过滤运行流程以下:code

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

②经过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代码


相关文章
相关标签/搜索