NSArray를 반복하는 표준 관용구를 찾고 있습니다. 내 코드는 OS X 10.4 이상에 적합해야합니다.
NSArray를 반복하는 표준 관용구를 찾고 있습니다. 내 코드는 OS X 10.4 이상에 적합해야합니다.
답변:
10.5 + / iOS에 일반적으로 선호되는 코드입니다.
for (id object in array) {
// do something with object
}
이 구문은 NSFastEnumeration
프로토콜 을 따르는 컬렉션의 개체를 열거하는 데 사용됩니다 . 이 방법은 단일 객체 호출을 통해 얻은 여러 객체에 대한 포인터를 버퍼에 저장하고 포인터 산술을 사용하여 버퍼를 통해 진행하여 객체를 반복하므로 속도 이점이 있습니다. 이다 훨씬 빠른 호출하는 것보다 -objectAtIndex:
루프를 때마다.
그것은 당신이 기술적 중에 있음을 주목할 가치가 있습니다 사용 A에 대한-에를 단계별로 루프 NSEnumerator
, 내가 찾은 그이 무효화합니다 거의 모든의 빠른 열거의 속도의 장점. 그 이유는 기본 NSEnumerator
구현이 -countByEnumeratingWithState:objects:count:
각 호출에서 버퍼에 하나의 객체 만 배치 하기 때문입니다 .
나는 이것을 radar://6296108
(NSEnumerators의 빠른 열거가 느리다) 에서보고 했지만 고치지 않음으로 반환되었습니다. 그 이유는 빠른 열거가 개체 그룹을 미리 가져오고 열거 자의 주어진 지점으로 만 열거하려는 경우 (예 : 특정 개체가 발견되거나 조건이 충족 될 때까지) 분류 후 동일한 열거자를 사용하기 때문입니다. 루프의 경우 여러 개체를 건너 뛰는 경우가 종종 있습니다.
OS X 10.6 / iOS 4.0 이상을 코딩하는 경우 블록 기반 API를 사용하여 배열 및 기타 컬렉션을 열거 할 수도 있습니다.
[array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
// do something with object
}];
당신은 또한 사용할 수 있습니다 -enumerateObjectsWithOptions:usingBlock:
및 통과 NSEnumerationConcurrent
및 / 또는 NSEnumerationReverse
옵션 인수로.
10.5 이전의 표준 관용구는 다음 NSEnumerator
과 같이 and 루프 를 사용하는 것입니다.
NSEnumerator *e = [array objectEnumerator];
id object;
while (object = [e nextObject]) {
// do something with object
}
간단하게 유지하는 것이 좋습니다. 배열 유형에 자신을 묶는 것은 융통성이 없으며 사용의 속도 향상은 -objectAtIndex:
어쨌든 10.5 이상에서 빠른 열거로 개선에 중요하지 않습니다. (빠른 열거는 실제로 기본 데이터 구조에서 포인터 산술을 사용하고 대부분의 메소드 호출 오버 헤드를 제거합니다.) 조기 최적화는 결코 좋은 생각이 아닙니다. 어쨌든 병목 현상이 아닌 문제를 해결하기 위해 더 복잡한 코드가 생성됩니다.
를 사용하면 다른 코드 변경없이 -objectEnumerator
열거 가능한 다른 컬렉션 ( NSSet
, 키의 NSDictionary
등) 으로 쉽게 변경 하거나 -reverseObjectEnumerator
배열을 뒤로 열거하도록 전환 할 수도 있습니다 . 반복 코드가 메소드에있는 경우 어떤 것도 전달할 수 NSEnumerator
있으며 코드는 반복되는 것을 신경 쓰지 않아도됩니다 . 또한 NSEnumerator
(적어도 Apple 코드에서 제공하는 것)은 더 많은 객체가있는 한 열거하는 컬렉션을 유지하므로 자동 릴리즈 된 객체가 얼마나 오래 존재할지 걱정할 필요가 없습니다.
아마도 NSEnumerator
(또는 빠른 열거)가 당신을 보호 하는 가장 큰 것은 열거 할 때 지식 없이도 변경 가능한 컬렉션 (배열 또는 기타) 변경을 갖는 것입니다. 인덱스로 개체에 액세스하는 경우 디버깅이 끔찍할 수있는 이상한 예외 또는 일대일 오류 (종종 문제가 발생한 후)가 발생할 수 있습니다. 표준 관용구 중 하나를 사용하는 열거 형에는 "실패한"동작이 있으므로 돌연변이가 발생한 후 다음 객체에 액세스하려고하면 문제 (잘못된 코드로 인해)가 즉시 나타납니다. 프로그램이 점점 복잡해지고 멀티 스레딩되거나 타사 코드가 수정할 수있는 것에 의존함에 따라 취약한 열거 코드는 점점 문제가되고 있습니다. 캡슐화와 추상화 FTW! :-)
for (id object in array)
하면 배열에서 객체의 현재 색인을 결정하는 방법이 있습니까? 아니면 별도의 카운터를 포함해야합니까?
for
다음과 같은 루프를 사용합니다 :for(;;) { id object = [ e nextObject ] ; if ( !e ) { break ; } ... your loop operation ... }
OS X 10.4.x 및 이전 버전의 경우 :
int i;
for (i = 0; i < [myArray count]; i++) {
id myArrayElement = [myArray objectAtIndex:i];
...do something useful with myArrayElement
}
OS X 10.5.x (또는 iPhone) 이상 :
for (id myArrayElement in myArray) {
...do something useful with myArrayElement
}
for (NSUInteger i = 0, count = [myArray count]; i < count; i++)
하면 가장 효율적이고 간결하게 사용할 수 있습니다.
테스트 및 소스 코드의 결과는 다음과 같습니다 (앱에서 반복 횟수를 설정할 수 있음). 시간은 밀리 초이며 각 항목은 테스트를 5-10 회 실행 한 평균 결과입니다. 나는 일반적으로 유효 숫자 2-3 자리까지 정확하고 그 후에는 매 실행마다 다를 수 있음을 발견했다. 이는 1 % 미만의 오차 한계를 제공합니다. 내가 관심있는 대상 플랫폼이기 때문에 테스트는 iPhone 3G에서 실행되었습니다.
numberOfItems NSArray (ms) C Array (ms) Ratio
100 0.39 0.0025 156
191 0.61 0.0028 218
3,256 12.5 0.026 481
4,789 16 0.037 432
6,794 21 0.050 420
10,919 36 0.081 444
19,731 64 0.15 427
22,030 75 0.162 463
32,758 109 0.24 454
77,969 258 0.57 453
100,000 390 0.73 534
데이터 세트 (NSDictionary, NSArray, NSSet 등)를 처리하기 위해 Cocoa가 제공하는 클래스는 메모리 관리, 재 할당 등의 관료주의에 대해 걱정할 필요없이 정보 관리를위한 매우 훌륭한 인터페이스를 제공합니다. 물론 비용이 많이 듭니다. . NSNumbers의 NSArray를 사용하는 것이 간단한 반복을 위해 Float의 C Array보다 느리다는 것이 명백하다고 생각합니다. 그래서 몇 가지 테스트를하기로 결정했으며 결과는 매우 충격적이었습니다! 나는 이것이 나쁜 것이라고 기대하지 않았습니다. 참고 :이 테스트는 내가 관심있는 대상 플랫폼이므로 iPhone 3G에서 수행됩니다.
이 테스트에서는 C float *와 NSNumber의 NSArray간에 매우 간단한 랜덤 액세스 성능 비교를 수행합니다.
각 배열의 내용을 요약하고 mach_absolute_time ()을 사용하여 시간을 지정하는 간단한 루프를 만듭니다. NSMutableArray는 평균 400 배 더 오래 걸립니다 !! (400 %가 아니라 400 배 더 길다. 40,000 % 더 길다!).
헤더:
// Array_Speed_TestViewController.h
// 배열 속도 테스트
// Mehmet Akten이 2009 년 5 월 2 일에 작성 함.
// Copyright MSA Visuals Ltd. 2009. 모든 권리 보유.
#import <UIKit/UIKit.h>
@interface Array_Speed_TestViewController : UIViewController {
int numberOfItems; // number of items in array
float *cArray; // normal c array
NSMutableArray *nsArray; // ns array
double machTimerMillisMult; // multiplier to convert mach_absolute_time() to milliseconds
IBOutlet UISlider *sliderCount;
IBOutlet UILabel *labelCount;
IBOutlet UILabel *labelResults;
}
-(IBAction) doNSArray:(id)sender;
-(IBAction) doCArray:(id)sender;
-(IBAction) sliderChanged:(id)sender;
@end
이행:
// Array_Speed_TestViewController.m
// 배열 속도 테스트
// Mehmet Akten이 2009 년 5 월 2 일에 작성 함.
// Copyright MSA Visuals Ltd. 2009. 모든 권리 보유.
#import "Array_Speed_TestViewController.h"
#include <mach/mach.h>
#include <mach/mach_time.h>
@implementation Array_Speed_TestViewController
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
NSLog(@"viewDidLoad");
[super viewDidLoad];
cArray = NULL;
nsArray = NULL;
// read initial slider value setup accordingly
[self sliderChanged:sliderCount];
// get mach timer unit size and calculater millisecond factor
mach_timebase_info_data_t info;
mach_timebase_info(&info);
machTimerMillisMult = (double)info.numer / ((double)info.denom * 1000000.0);
NSLog(@"machTimerMillisMult = %f", machTimerMillisMult);
}
// pass in results of mach_absolute_time()
// this converts to milliseconds and outputs to the label
-(void)displayResult:(uint64_t)duration {
double millis = duration * machTimerMillisMult;
NSLog(@"displayResult: %f milliseconds", millis);
NSString *str = [[NSString alloc] initWithFormat:@"%f milliseconds", millis];
[labelResults setText:str];
[str release];
}
// process using NSArray
-(IBAction) doNSArray:(id)sender {
NSLog(@"doNSArray: %@", sender);
uint64_t startTime = mach_absolute_time();
float total = 0;
for(int i=0; i<numberOfItems; i++) {
total += [[nsArray objectAtIndex:i] floatValue];
}
[self displayResult:mach_absolute_time() - startTime];
}
// process using C Array
-(IBAction) doCArray:(id)sender {
NSLog(@"doCArray: %@", sender);
uint64_t start = mach_absolute_time();
float total = 0;
for(int i=0; i<numberOfItems; i++) {
total += cArray[i];
}
[self displayResult:mach_absolute_time() - start];
}
// allocate NSArray and C Array
-(void) allocateArrays {
NSLog(@"allocateArrays");
// allocate c array
if(cArray) delete cArray;
cArray = new float[numberOfItems];
// allocate NSArray
[nsArray release];
nsArray = [[NSMutableArray alloc] initWithCapacity:numberOfItems];
// fill with random values
for(int i=0; i<numberOfItems; i++) {
// add number to c array
cArray[i] = random() * 1.0f/(RAND_MAX+1);
// add number to NSArray
NSNumber *number = [[NSNumber alloc] initWithFloat:cArray[i]];
[nsArray addObject:number];
[number release];
}
}
// callback for when slider is changed
-(IBAction) sliderChanged:(id)sender {
numberOfItems = sliderCount.value;
NSLog(@"sliderChanged: %@, %i", sender, numberOfItems);
NSString *str = [[NSString alloc] initWithFormat:@"%i items", numberOfItems];
[labelCount setText:str];
[str release];
[self allocateArrays];
}
//cleanup
- (void)dealloc {
[nsArray release];
if(cArray) delete cArray;
[super dealloc];
}
@end
보낸 사람 : memo.tv
//////////////////////
블록이 도입 된 이후에 사용 가능하므로 블록이있는 배열을 반복 할 수 있습니다. 구문은 빠른 열거만큼 좋지는 않지만 동시 열거라는 매우 흥미로운 기능이 있습니다. 열거 순서가 중요하지 않고 잠금없이 작업을 병렬로 수행 할 수 있으면 다중 코어 시스템에서 상당한 속도 향상을 제공 할 수 있습니다. 동시 열거 섹션에서 이에 대해 자세히 알아보십시오.
[myArray enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {
[self doSomethingWith:object];
}];
[myArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[self doSomethingWith:object];
}];
/////////// NSFastEnumerator
빠른 열거의 개념은 빠른 C 배열 액세스를 사용하여 반복을 최적화하는 것입니다. 기존 NSEnumerator보다 빠를뿐만 아니라 Objective-C 2.0도 매우 간결한 구문을 제공합니다.
id object;
for (object in myArray) {
[self doSomethingWith:object];
}
//////////////////
NSEnumerator
이것은 외부 반복 형식입니다. [myArray objectEnumerator]는 객체를 반환합니다. 이 객체에는 nextObject 메소드가 있는데, nil을 반환 할 때까지 루프에서 호출 할 수 있습니다.
NSEnumerator *enumerator = [myArray objectEnumerator];
id object;
while (object = [enumerator nextObject]) {
[self doSomethingWith:object];
}
//////////////////
objectAtIndex : 열거
정수를 증가시키는 for 루프를 사용하고 [myArray objectAtIndex : index]를 사용하여 객체를 쿼리하는 것이 가장 기본적인 열거 형입니다.
NSUInteger count = [myArray count];
for (NSUInteger index = 0; index < count ; index++) {
[self doSomethingWith:[myArray objectAtIndex:index]];
}
/////////////// 보낸 사람 : darkdust.net
세 가지 방법은 다음과 같습니다.
//NSArray
NSArray *arrData = @[@1,@2,@3,@4];
// 1.Classical
for (int i=0; i< [arrData count]; i++){
NSLog(@"[%d]:%@",i,arrData[i]);
}
// 2.Fast iteration
for (id element in arrData){
NSLog(@"%@",element);
}
// 3.Blocks
[arrData enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"[%lu]:%@",idx,obj);
// Set stop to YES in case you want to break the iteration
}];
에 each
메소드를 추가 NSArray category
하면 많이 필요할 것입니다.
ObjectiveSugar 에서 가져온 코드
- (void)each:(void (^)(id object))block {
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
block(obj);
}];
}
이 작업을 수행 :-
for (id object in array)
{
// statement
}