2010-09-15 41 views
18

Làm cách nào để kiểm tra xem đối tượng NSNumber có phải là không có hoặc không?kiểm tra xem NSNumber có trống không

OK nil cũng dễ dàng:

NSNumber *myNumber; 
if (myNumber == nil) 
    doSomething 

Nhưng nếu đối tượng đã được tạo ra, nhưng không có giá trị trong đó bởi vì chuyển nhượng thất bại, làm thế nào tôi có thể kiểm tra điều này? Sử dụng một cái gì đó như thế này?

Có phương pháp chung để kiểm tra các đối tượng trống rỗng như đối với NSString có sẵn (xem post) này không?

Ví dụ 1

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; 
[dict setValue:@"" forKey:@"emptyValue"]; 
NSNumber *emptyNumber = [dict objectForKey:@"emptyValue"]; 

Những giá trị không emptyNumber chứa? Làm cách nào để kiểm tra xem emptyNumber có trống không?

Ví dụ 2

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; 
[dict setValue:@"" forKey:@"emptyValue"]; 
NSString *myString = [dict objectForKey:@"emptyValue"]; 
if (myString == nil || [myString length] == 0) 
    // got an empty value 
    NSNumber *emptyNumber=nil; 

gì sẽ xảy ra nếu tôi sử dụng này sau khi emptyNumber được thành lập để nil?

[emptyNumber intValue] 

Tôi có được không?

Ví dụ 3

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; 
[dict setValue:@"" forKey:@"emptyValue"]; 
NSNumber *myEmptyValue = [dict objectForKey:@"emptyValue"]; 
if (myEmptyValue == nil) 
    // NSLog is never called 
    NSLog(@"It is empty!"); 

Giống như cách này NSLog không bao giờ được gọi. myEmptyValue không phải là nil và không phải là NSNull. Vì vậy, nó có chứa một số tùy ý?

+0

@ [0.7] sẽ cung cấp NSNumber chắc chắn không phải 0, nhưng intValue sẽ trả về 0. Vì vậy, đó là một thử nghiệm xấu. – gnasher729

+0

Được bình chọn cho các chi tiết tuyệt vời giúp giải thích điều tôi đang xử lý từ mặc định. NSNumber * savedPin = [[NSUserDefaults standardUserDefaults] valueForKey: @ "someKey"]; trả về một đối tượng có lớp __NSCFConstantString và do đó so sánh với nil không thành công. CẢM ƠN! –

Trả lời

12

NSValue, NSNumber, ... được cho là được tạo từ giá trị và luôn giữ một giá trị. Thử nghiệm cho một giá trị cụ thể như 0 chỉ hoạt động nếu nó không nằm trong phạm vi giá trị hợp lệ mà bạn đang làm việc.

Trong trường hợp hiếm hoi mà code đang hơn thẳng về phía trước để làm việc với nếu bạn có một giá trị đại diện cho "không hợp lệ" hoặc "not set" và bạn không thể sử dụng nil (ví dụ với các container tiêu chuẩn) bạn có thể sử dụng NSNull để thay thế.

Trong của bạn ví dụ đầu tiên này có thể là:

[dict setValue:[NSNull null] forKey:@"emptyValue"]; 

if ([dict objectForKey:@"emptyValue"] == [NSNull null]) { 
    // ... 
} 

Nhưng lưu ý rằng bạn chỉ có thể không chèn (hoặc xóa) giá trị đó trừ khi bạn cần phải phân biệt nil (tức là không có trong container) và, nói, "không hợp lệ":

if ([dict objectForKey:@"nonExistent"] == nil) { 
    // ... 
} 

đối với ví dụ thứ hai , -intValue Hãy cho s bạn 0 - nhưng đơn giản chỉ vì gửi tin nhắn đến nil trả lại 0. Bạn cũng có thể nhận được 0 ví dụ: đối với số NSNumberintValue được đặt thành 0 trước đây, đây có thể là giá trị hợp lệ.
Như tôi đã viết ở trên, bạn chỉ có thể làm điều gì đó như thế này nếu 0không phải là giá trị hợp lệ cho bạn. Lưu ý cho bạn, những gì hoạt động tốt nhất hoàn toàn phụ thuộc vào yêu cầu của bạn là gì.

Hãy để tôi cố gắng tóm tắt :

Lựa chọn # 1:

Nếu bạn không cần tất cả các giá trị từ dãy số, bạn có thể sử dụng một (0 hoặc -1 hoặc .. .) và -intValue/... để cụ thể đại diện cho "trống". Đây rõ ràng không phải là trường hợp của bạn.

Lựa chọn # 2:

Bạn chỉ đơn giản là tôi không lưu trữ hoặc loại bỏ các giá trị từ container nếu họ "trống rỗng":

// add if not empty: 
[dict setObject:someNumber forKey:someKey];  
// remove if empty: 
[dict removeObjectForKey:someKey]; 
// retrieve number: 
NSNumber *num = [dict objectForKey:someKey]; 
if (num == nil) { 
    // ... wasn't in dictionary, which represents empty 
} else { 
    // ... not empty 
} 

Tuy nhiên điều này có nghĩa là không có sự khác biệt giữa các khóa trống và các khóa không bao giờ tồn tại hoặc là bất hợp pháp.

Lựa chọn # 3:

Trong một số trường hợp hiếm hoi của nó thuận tiện hơn để giữ tất cả các phím trong từ điển và đại diện "trống rỗng" với một giá trị khác nhau. Nếu bạn không thể sử dụng một từ phạm vi số, chúng tôi phải đặt một thứ gì đó khác biệt ở dạng NSNumber không có khái niệm về "trống". Cocoa đã có NSNull đối với trường hợp như vậy:

// set to number if not empty: 
[dict setObject:someNumber forKey:someKey]; 
// set to NSNull if empty: 
[dict setObject:[NSNull null] forKey:someKey]; 
// retrieve number: 
id obj = [dict objectForKey:someKey]; 
if (obj == [NSNumber null]) { 
    // ... empty 
} else { 
    // ... not empty 
    NSNumber *num = obj; 
    // ... 
} 

Tùy chọn này hiện cho phép bạn phân biệt giữa "trống rỗng", "không rỗng""không nằm trong container" (key ví dụ bất hợp pháp).

+0

Tôi đã chỉnh sửa bài đăng của mình. Làm thế nào tôi có thể thử nghiệm về sự trống rỗng trong "trường hợp đặc biệt" này? Có trong phạm vi giá trị hợp lệ ở đây không? – testing

+0

Bạn đang chèn '[NSNull null]' để kiểm tra sau này một đối tượng NSNumber trên sự trống rỗng. OK, nhưng các container tiêu chuẩn là gì? Tôi không thể đảm bảo giá trị nào được gán cho đối tượng NSNumber của tôi. Vì vậy, tôi không biết khi nào nên chèn 'nil' hoặc' NSNull'. Trong ví dụ của tôi, nó cũng có thể là một chuỗi rỗng.Lần đầu tiên tôi có nên kiểm tra giá trị trả về của 'objectForKey' nếu nó là một chuỗi rỗng và sau đó tôi nên chèn' nil' hoặc 'NSNull' vào đối tượng NSNumber của tôi? Tôi nghĩ rằng tôi nên luôn luôn chèn nil, trừ khi tôi cần NSNull cho một số trường hợp. Xem ví dụ thứ hai của tôi. – testing

+1

@testing: Các vùng chứa tiêu chuẩn là các vùng chứa từ Cocoa Touch ('NSArray',' NSDictionary', ...). Các thử nghiệm mẫu đầu tiên cho đối tượng là 'NSNull', tùy chọn thứ hai giả định * bạn không đặt giá trị trong vùng chứa * - bạn không thể chèn' nil' vào trong đó, 'nil' đại diện *" không nằm trong vùng chứa " *. Bạn chỉ cần quyết định thời tiết bạn phải phân biệt giữa * "không hợp lệ" */* "không tồn tại" * và * "không có trong vùng chứa" *. Câu cuối cùng của bạn gần với những gì tôi nói - hoặc không đặt nó vào trong thùng chứa (vì vậy bạn có 'nil' cho' -objectForKey: ... ') hoặc đi với' NSNull'. –

3

NSNumbernil hoặc chứa số, không có gì ở giữa. "Tánh không" là một khái niệm phụ thuộc vào ngữ nghĩa của một vật thể cụ thể và do đó không có ý nghĩa gì khi tìm kiếm một phép kiểm tra trống rỗng chung.

Đối với ví dụ của bạn, có một số điều đang xảy ra:

NSMutableDictionary *hash = [NSMutableDictionary dictionary]; 
[hash setObject:@"" forKey:@"key"]; 
NSNumber *number = [hash objectForKey:@"key"]; 
NSLog(@"%i", [number intValue]); 

Các NSLog sẽ in 0 ở đây, nhưng chỉ vì có một phương pháp intValue trong NSString. Nếu bạn thay đổi thông điệp tới một cái gì đó mà chỉ NSNumber có thể làm, mã sẽ thất bại:

NSLog(@"%i", [number unsignedIntValue]); 

này sẽ ném:

-[NSCFString unsignedIntValue]: unrecognized selector sent to instance 0x303c 

Có nghĩa là bạn đang không nhận được một số chung giá trị “trống rỗng” trở lại từ băm, bạn chỉ nhận được NSString bạn đã lưu trữ ở đó.

Khi bạn trống (== nil) NSNumber và gửi tin nhắn, kết quả sẽ bằng không.Đó là chỉ đơn giản là một quy ước ngôn ngữ đơn giản hóa mã:

(array != nil && [array count] == 0) 
(someNumber == nil ? 0 : [someNumber intValue]) 

sẽ biến thành này:

([array count] == 0) 
([someNumber intValue]) 

Hope this helps.

+0

Vậy thử nghiệm NSNumber * = [NSNull null] làm gì? –

+1

Như được viết, mã đó không có ý nghĩa nhiều. NSNull chỉ là một "phiên bản đối tượng của giá trị nil" và về lý do duy nhất nó tồn tại là đại diện cho một giá trị "trống" trong các bộ sưu tập không thể lưu trữ trực tiếp nil. – zoul

+0

Cảm ơn, vâng, tôi đoán tôi chỉ đang cố gắng rõ ràng trong tâm trí của tôi chính xác những gì các khả năng tôi cần phải xem xét cho NSNumber –

0

NSNumber s không thay đổi và chỉ có thể được tạo bằng phương pháp nhà máy hoặc phương pháp ban đầu cung cấp cho chúng một số giá trị số. Theo như tôi biết không thể kết thúc với một NSNumber 'trống', trừ khi bạn đếm 0,

0

Rất ít (đối với tôi ít nhất) để đưa một đối tượng ra khỏi từ điển, mong rằng nó sẽ là một NSNumber và sau đó có nó trả về một đối tượng nil. Nếu điều này xảy ra và bạn làm một intValue nó sẽ sụp đổ.

Điều tôi làm là thiết lập bảo vệ nil vì tôi muốn có giá trị mặc định hơn là sự cố.

Một cách là:

-(int) intForDictionary:(NSDictionary *)thisDict objectForKey: (NSString *)thisKey withDefault: (int)defaultValue 
{ 
    NSNumber *thisNumber = [thisDict objectForKey:thisKey]; 
    if (thisNumber == nil) { 
     return defaultValue; 
    } 
    return [thisNumber intValue]; 
} 

Và tôi có một giống như nó cho nổi. Sau đó, bạn ít nhất có được giá trị mặc định của bạn. Một cách khác là chỉ cần tạo ra một phương pháp để bảo vệ bằng không ..

-(NSNumber *)nilProtectionForNumber: (NSNumber *)thisNumber withDefault: (NSNumber *)defaultNumber 
{ 
    if (thisNumber) { 
     return thisNumber; 
    } 
    else 
     return defaultNumber; 
} 

Đó là một bạn muốn gọi như thế này:

NSNumber *value = [self nilProtectionForNumber:[dict objectForKey:keyThatShouldBeNSNumber] withDefault:[NSNumber numberWithInt:0]]; 
0

Đối phó với Swift 2.0 và Phân tích:

var myNumber = yourArray!.objectForKey("yourColumnTitle") 
    if (myNumber == nil) { 
    myNumber = 0 
     } 

Trong trường hợp của tôi, sau đó tôi phải:

let myNumberIntValue = myNumber!.intValue 
Các vấn đề liên quan