2014-09-06 10 views
9

Dobra drużyna, to dziwne. [NSDecimalNumber integerValue] zachowuje się dziwnie.{NSDecimalNumber integerValue} dziwnie się zachowuje w iOS8

Jestem usatysfakcjonowany, próbując ustalić, dlaczego niektóre części mojej aplikacji są uszkodzone w iOS8, i szukam zmiennej o nazwie "timeSeconds". Wydaje się, jakby to w zmiennych Xcode Zobacz:

_timeSeconds (NSDecimalNumber *) 344.514533996581994496 

Ale kiedy zapytać go w debugera widzę tak:

(lldb) p [self.timeSeconds doubleValue] 
(double) $14 = 344.51453399658192 
(lldb) p [self.timeSeconds intValue] 
(int) $15 = 344 
(lldb) p [self.timeSeconds integerValue] 
(NSInteger) $16 = -5 
(lldb) p (NSInteger)[self.timeSeconds intValue] 
(NSInteger) $17 = 344 

Zobacz, że „-5”? Czy ktokolwiek z was pięknych ludzi może to powtórzyć lub wyjaśnić, zanim złożę radar?

Oto SSCCE:

NSDecimalNumber *n = [NSDecimalNumber decimalNumberWithString:@"344.514533996581994496"]; 
NSLog(@"%@", n); // 344.514533996581994496 
NSLog(@"%ld", (long)[n intValue]); // 344 
NSLog(@"%ld", (long)[n integerValue]); // -5 
NSLog(@"%ld", (long)[n unsignedIntegerValue]); // 12 

Z góry dzięki!

Matthew

+0

Mateusz - co znalazłeś? NSDecimalNumber na iOS 8 powoduje ogromne problemy w mojej aplikacji na żywo! – SAHM

Odpowiedz

12

Wynik dla integerValue jest zaskakujące, ale z tego co rozumiem, co zostało udokumentowane:

NSDecimalNumber dziedziczy NSNumber. W notach podklasujących z NSNumber podano, że podklasa "... musi zastąpić metodę dostępową, która odpowiada zadeklarowanemu typowi - na przykład, jeśli twoja implementacja właściwości objCType zwraca" i ", musisz zastąpić wartość intValue. . "

objCType jest ustawiony na wewnętrzny wskaźnik, więc powinien być taki sam jak dla NSNumber.

NSDecimal nie zastępuje intergerValue. Zastąpi ona doubleValue, więc powinno działać dobrze.

Jedyną rzeczą, która sprawia, że ​​zastanawiam: wydaje się, że nie zastępują intValue albo ...

+0

Myślę, że zdecydowanie jesteś na dobrej drodze. Chciałbym zrozumieć to trochę lepiej i jeśli zastanowisz się nad intValue, opublikuj swoją odpowiedź. Ale zamierzam iść do przodu i nagradzać nagrodę, ponieważ uważam, że jest to właściwy kierunek i nie chcę, aby nagroda się skończyła bez przyznania jej. – SAHM

+0

To jest pokrewne pytanie, w którym jest bardziej szczegółowy przypadek problemu NSDecimal, który jest prawdopodobnie związany z tym problemem. http://stackoverflow.com/questions/26741233/ios-8-number-conversion-formatowanie-error- canoff-reproduce – SAHM

2

Co wielki błąd! Po prostu znalazłem się przez to oszukany. Tak, tylko do stwierdzenia dogsgods odpowiedzieć:

Nie wolno:

NSInteger x = [myDecimalNumber integerValue]; 

Zamiast to zrobić:

NSInteger x = (NSInteger)[myDecimalNumber doubleValue]; 
0

Zastosowanie myDecimalNumber.intValue zamiast integerValue

0

Można użyć use intValue lub unsignedIntValue dobrze, ale NOT integerValue lub unsignedIntegerValue.Oto test jednostkowy, który pokazuje problem, pokazując, że jest on powiązany z liczbami wymagającymi więcej niż 64 bitów precyzji:

// 
// NSDecimalNumberBugTests.m 
// 
// Created by Lane Roathe on 6/1/17. 
// For Quicken, Inc. 
// 

#import <XCTest/XCTest.h> 

@interface NSDecimalNumberBugTests : XCTestCase 

@end 

@implementation NSDecimalNumberBugTests 

- (void)setUp { 
    [super setUp]; 
    // Put setup code here. This method is called before the invocation of each test method in the class. 
} 

- (void)tearDown { 
    // Put teardown code here. This method is called after the invocation of each test method in the class. 
    [super tearDown]; 
} 

- (void)testBug { 
    // Use XCTAssert and related functions to verify your tests produce the correct results. 
    NSDecimalNumber* decimalLength; 
    NSUInteger interval; 

    // Start with a number that requires 65+ bits 

    // This FAILS (interval is zero) 
    decimalLength = [NSDecimalNumber decimalNumberWithString:@"1.8446744073709551616"]; 
    interval = decimalLength.unsignedIntegerValue; 
    XCTAssert(interval == 1); 

    // This Works, interval is 1 
    interval = decimalLength.unsignedIntValue; 
    XCTAssert(interval == 1); 

    // Now test with a number that fits in 64 bits 

    // This WORKS (interval is 1) 
    decimalLength = [NSDecimalNumber decimalNumberWithString:@"1.8446744073709551615"]; 
    interval = decimalLength.unsignedIntegerValue; 
    XCTAssert(interval == 1); 
} 

@end 
Powiązane problemy