2016-08-19 14 views
6

Tôi hiện đang bị nhầm lẫn bởi con trỏ tới con trỏ mặc dù tôi đã đọc Why does NSError need double indirection? (pointer to a pointer)NSError * vs NSError ** và hơn thế nữa.Không thể hiểu hành vi truyền con trỏ NSError/NSObject

Tôi đã thực hiện một số suy nghĩ và vẫn có một số câu hỏi.

Ở đây tôi đã viết này:

NSError *error = [NSError errorWithDomain:@"before" code:0 userInfo:nil]; 
NSLog(@"outside error address: %p", &error]; 
[self doSomethingWithObj:nil error:&error]; 

Để kiểm tra các NSError phương pháp trên, tôi đã viết này:

- (id)doSomethingWithObj:(NSObject *)obj error:(NSError *__autoreleasing *)error 
{ 
    NSLog(@"inside error address: %p", error); 
    id object = obj; 
    if (object != nil) 
    { 
     return object; 
    } 
    else 
    { 
     NSError *tmp = [NSError errorWithDomain:@"after" code:0 userInfo:nil]; 
     *error = tmp; 
     return nil; 
    } 
} 

Nhưng tôi phát hiện ra rằng hai địa chỉ khai thác gỗ là khác nhau. Tại sao vậy?

2016-08-19 19:00:16.582 Test[4548:339654] outside error address: 0x7fff5b3e6a58 
2016-08-19 19:00:16.583 Test[4548:339654] inside error address: 0x7fff5b3e6a50 

Chúng không giống nhau vì đó chỉ là bản sao giá trị đơn giản? Nếu chúng khác nhau, làm thế nào để con trỏ trỏ đến cùng một ví dụ NSError?

+2

Trình biên dịch phải làm điều gì đó với con trỏ đến con trỏ, có lẽ để xử lý ARC. Trong phiên bản mới nhất của con trỏ Objective-C có quá nhiều thông minh, vì vậy những gì từng là một bản sao giá trị đơn giản có thể không còn đơn giản như vậy nữa. Bạn có thể muốn tái cụm từ câu hỏi này theo cách không liên quan gì đến 'NSError' - nói," Con trỏ trỏ đến thay đổi khi được truyền như tham số phương thức ", hoặc một cái gì đó tương tự. – dasblinkenlight

+1

Nhưng NSError * __autoreleasing * là một mẫu được sử dụng ở mọi nơi và được trình biên dịch nhận ra và xử lý khác nhau. – gnasher729

Trả lời

0

Vì vậy, sau khi khởi tạo trên dòng đầu tiên, error là một con trỏ đến đối tượng NSError.

Trong nhật ký đầu tiên, bạn đang ghi lại địa chỉ mà tại đó con trỏ được giữ. Đó là ảnh hưởng của nhà điều hành địa chỉ &. Dù sao, đó là địa chỉ được chuyển vào phương thức doSomething.

Bạn đang chuyển vào: pointer -> pointer -> nserror-object.

Nhưng hãy chú ý đến số hai chiều trong chữ ký của doSomething. Chú thích tự động làm cho nó khó phát hiện, nhưng nó là NSError **.

Vì vậy, trình biên dịch lấy tham số của bạn và 'unwraps' nó hai lần.

Nó bắt đầu dưới dạng con trỏ -> pointer -> nserror-object. Sau đó, sau khi indirection đầu tiên nó trở thành con trỏ -> nserror-object. Sau đó, sau lần thứ hai, nó trở thành nserror-object.

Ergo, bạn đang ghi lại hai thứ khác nhau. Đầu tiên là địa chỉ của con trỏ tới đối tượng nserror. Thứ hai là địa chỉ của chính đối tượng nserror.

EDIT: @MANIAK_dobrii chỉ ra rằng đối tượng được trỏ tới bởi errorchính nó khác nhau trong trường hợp trước và sau.

Đó là sự thật. Nếu một lỗi xảy ra trong doSomething thì nó tạo ra một cá thể NSError hoàn toàn mới trong mệnh đề else. Sau đó nó sẽ nạp lại vào con trỏ error. Đó là lý do tại sao bạn sẽ thấy hai địa chỉ khác nhau, sau đó con trỏ error trỏ đến một đối tượng khác hoàn toàn.

+0

Không phải trường hợp, lỗi đã là một con trỏ đến dụ NSError, & lỗi là một con trỏ trỏ đến con trỏ đó. Vấn đề là trước khi gọi phương thức và sau đó bằng cách nào đó khác nhau. Tôi không biết tại sao là tốt và tôi cho rằng chúng giống nhau. –

+0

@MANIAK_dobrii Có, tôi đang nói rằng 'lỗi đã là một con trỏ đến dụ NSError, & lỗi là một con trỏ trỏ tới con trỏ đó'. Nhưng tôi nghĩ rằng tôi thấy quan điểm của bạn. Có, chúng khác nhau bởi vì, trong phương thức này, một cá thể NSError khác được tách thành khối khác và được nạp vào con trỏ. Đó là một đối tượng khác. – ncke

+0

Đó không phải là trường hợp. @ gnasher729 đưa ra câu trả lời chính xác. Đó là ARC rối tung xung quanh, tôi nhớ đọc về điều đó trong một số tài liệu kêu vang xung quanh __autoreleasing cho con trỏ đôi, do đó, cung cấp cho nó một cái nhìn. Ngoài ra, xin lỗi, tôi không rõ ràng trong "sau (gọi phương thức)", tôi có nghĩa là sau khi gọi phương thức bên trong cuộc gọi, tức là trong suốt cuộc gọi. –

4

Biến trong người gọi có loại NSError*. Địa chỉ có loại NSError* *. Hàm này mong đợi NSError* __autoreleasing *. Do đó trình biên dịch tạo biến ẩn của loại NSError* __autoreleasing, sao chép NSError* vào biến ẩn trước cuộc gọi và sao chép nó trở lại sau cuộc gọi để nhận ngữ nghĩa của quyền __autoreleasing.

+0

Câu trả lời hay! Tôi thực sự quên có một cái gì đó trong tài liệu clang tương tự như vậy. Bạn có thể gợi ý điều gì đó để đọc chi tiết không? –

+0

@ gnasher729 Tôi không chắc liệu lý do có liên quan đến '__autoreleasing' kể từ khi tôi thử nghiệm lại lần nữa hay không: sau khi tôi xóa từ khóa' __autoreleasing', tôi gặp cùng một vấn đề - các địa chỉ khác nhau cho bên trong và bên ngoài con trỏ. – Boris

Các vấn đề liên quan