2009-04-02 43 views
7

Tôi mới bắt đầu (đọc rất nhiều trong vài ngày qua). Dưới đây là một số câu hỏi mà tôi đã xếp chồng lên nhau, hy vọng ai đó có thể trả lời chúng.Một số người mới bắt đầu Câu hỏi mục tiêu-C/iPhone

1. (tự! = Nil) kiểm tra mã khởi tạo. Tại sao làm điều đó? Để ngăn tình cờ truy cập vào một số mã "chỉ chạy một lần" được gói trong đó? Từ đâu có thể truy cập ngẫu nhiên này đến từ đâu? Làm như vậy kiểm tra cho thấy rằng tôi không có quyền kiểm soát những gì đang xảy ra.

 
- (id)init { 
    self = [super init] 
    if (self != nil) { 
    // Code.. 
    } 
    return self; 
} 

2. Làm thế nào mà bạn không cần phải giải phóng bất cứ điều gì mà các phương pháp tĩnh trở lại? (hoặc đây là ý tưởng tôi có)

3. Làm thế nào là str = @ "Xin chào!" khác nhau từ

str = [[NSString alloc] initWithString:@"Hi there!"];

Như tôi hiểu, bạn phải giải phóng str trong mua lại với phương pháp thứ hai, nhưng không phải với đầu tiên? Nếu vậy, khi nào người đầu tiên được thả ra? Cái nào là thích hợp hơn (không chú ý đến chiều dài gõ)?

4. Tự động phát hành gì, nếu iphone không có bộ sưu tập rác? Tôi đã nhận thấy một cái gì đó gọi là "một hồ bơi autorelease" được tạo ra trong main.m. Là [myObject autorelease]; một cách để thêm myObject vào gói "autorelease pool" gần nhất, nó sẽ phát hành nó? Về cơ bản, một số phép thuật để tránh tự giải phóng nó? Tại sao lại sử dụng nó?

Vâng, hiện tại. Cảm ơn mọi câu trả lời!

Trả lời

11
  1. Trong mục tiêu-C, có thể trả lại một trường hợp khác với tự từ -init. Các lớp làm điều này, ví dụ, để thực thi một cá thể singleton, hoặc trong trường hợp các nhóm lớp. Ví dụ: NSNumber trả về một phân lớp phụ thuộc vào loại giá trị được chuyển đến bộ khởi tạo của nó. Vì vậy, khi bạn gọi [[NSNumber alloc] initWithLong:long_value], NSNumber 's -initWithLong: initializer được gọi sau khi NSNumber' s +alloc, nhưng một lớp con của NSNumber có thể được trả lại cho người gọi oringial.Do đó, mẫu

    self = [super init];

    gán lại self với giá trị [super init] để self trỏ đến ví dụ thực tế mà [super init] trả về. Nếu +alloc hoặc phương thức init của siêu không thành công, kết quả của [super init] có thể là nil. Để tránh những tác dụng phụ trong trường hợp của một khởi thất bại, mô hình sau đó trở thành

    - (id) init { 
        if(self = [super init]) { 
        // do initialization of instance variables etc. 
        } 
    
        return self; 
    } 
    

    Lưu ý rằng bạn phải trả lại self (hoặc nil hoặc một ví dụ khác) từ phương pháp init. Bạn nên gán tự cho [super init] và bạn có thể kiểm tra nil trước khi thực hiện thêm công việc.

  2. Bạn có thể phải giải phóng giá trị trả về của phương pháp cổ xưa. Bạn nên đọc quản lý bộ nhớ Cocoa guide. Quy tắc nói chung khá đơn giản: Nếu phương thức bạn gọi có "mới", "phân bổ" hoặc "sao chép" trong chữ ký của nó, kết quả thuộc về người gọi và người gọi phải gọi -release trên trường hợp đó hoặc sẽ có bộ nhớ rò rỉ. Tất nhiên bạn nên gọi -retain trên bất kỳ thứ gì khác (nghĩa là không phải từ phương thức "phân bổ", "mới" hoặc "sao chép") mà bạn muốn giữ tham chiếu và sau đó gọi -release hoặc -autorelease khi bạn hoàn tất với trường hợp đó.

  3. str = @"Hi there!", giả sử str được khai báo là NSString *str; gán địa chỉ của chuỗi liên tục @"Hi there!" to the value of the str variable. You do not need to retain or release string constants. str = [[NSString alloc] initWithString: @ "Hi there!"]; allocates a new string instance. The value of str will be the address of this instance. Each call of str = [[NSString alloc] initWithString: @ "Xin chào!"]; again will allocate a new instance. So after str2 = [[NSString alloc] initWithString: @ "Xin chào!"]; , str! = Str2 , while after str2 = @ "Xin chào!", str==str2. Xem this câu trả lời là tốt.

  4. -autorelease thêm người nhận vào số NSAutoreleasPool hiện tại. Khi hồ bơi được thoát nước (thường là vào cuối vòng lặp chạy vòng lặp hiện tại, hoặc khi hồ bơi được thoát nước thủ công), hồ bơi gọi -release trên tất cả các trường hợp trong hồ bơi. Nếu điều này -release giảm số lượng giữ lại 0, đối tượng được deallocated (và -dealloc gọi) giống như bất kỳ khác -release. Sử dụng một autorelease hồ bơi thường cau mày khi trên iPhone bởi vì nó có thể khiến bạn tích lũy nhiều trường hợp không sử dụng trong hồ bơi trước khi nó được thoát nước ở cuối vòng lặp chạy lặp lại. Nếu bạn có thể sử dụng -release thay vì -autorelease, bạn thường nên làm như vậy. Một lần nữa, hãy xem quản lý bộ nhớ Cocoa guide để biết thêm thông tin.

+0

Câu trả lời tuyệt vời! –

+0

Như vậy cũng là một khó khăn, đầy những ví dụ trả lời. Cảm ơn bạn, hầu hết nó là rõ ràng bây giờ. Đã chấp nhận. – Karolis

1

1: Kiểm tra này là để đảm bảo rằng hàm tạo siêu trả về một đối tượng mới.

2: phương pháp tĩnh không đề cập đến một thể hiện

3: "Hi there"

str = @"Hi there!"

này gán địa chỉ của chuỗi liên tục vào con trỏ str

str = [[NSString alloc] initWithString:@"Hi there!"];

Điều này phân bổ chuỗi và sao chép "Xin chào!" cho nó. Điều này có nghĩa là a) str có thể sửa đổi được và b) cần phải được deallocated khi bạn đang thực hiện với nó.

+0

Nhưng theo nghĩa chung, cả hai cách sử dụng str sẽ tiêu thụ cùng một lượng bộ nhớ, chỉ là điều đầu tiên là không thay đổi. Không sử dụng phương pháp thứ hai đảm bảo không gian được giải phóng bất cứ khi nào tôi cần nó? Đơn giản chỉ cần asigning @ "Hi there!" chiếm không gian quá, phải không? Nhưng không kiểm soát được không gian đó trong bộ nhớ, đúng không? – Karolis

+0

NSString là không thay đổi, vì vậy str không thể sửa đổi trong cả hai trường hợp. –

+0

Không, str là vùng chứa có thể thay đổi được cho một chuỗi không thay đổi được. –

1

gọi

self = [super init]; 

thể trở lại con số không nếu cha không thể khởi tạo riêng của mình đối với một số lý do nào khác, kể cả bộ nhớ là không có sẵn, hoặc điều kiện tiên quyết nhất định đã không được đáp ứng. Nếu đó là trường hợp, bạn không muốn cố gắng thiết lập các biến của bản thân, hoặc tự thiết lập như một đại biểu, hoặc thêm tự vào một mảng, nếu tự là không.

Hồ bơi tự động sửa là thứ được tạo ra khi mọi sự kiện iPhone gửi ứng dụng của bạn. Nó được tạo trước khi bất kỳ mã nào chạy và được phát hành sau khi tất cả mã của bạn được thực hiện, cho mỗi sự kiện. Bất kỳ đối tượng nào bạn gọi autorelease sẽ được đưa vào nhóm tự động phát hiện hành. Bất kỳ đối tượng nào trong nhóm tự động phát hành sẽ được phát hành nhiều lần khi chúng được thêm vào, sau khi mã của bạn hoàn tất.Bằng cách này, bạn không phải lo lắng về việc ai chịu trách nhiệm giải phóng một đối tượng được tạo ra bởi một phương thức và trả về một phương thức khác.

Bạn có thể tạo các nhóm tự động phát hành riêng của mình nếu cần.

str = [[NSString alloc] initWithString:@"Hi there!"]; 

Dòng này tạo chuỗi không nằm trong nhóm tự động phát hành, vì vậy bạn phải phát hành theo cách thủ công. Chỉ cần viết

@"Hi there!"; 

trả về chuỗi mà bạn không phải lo lắng về việc phát hành. Mở rộng ví dụ trước của bạn:

str = [[[NSString alloc] initWithString:@"Hi there!"] autorelease]; 

sẽ là một phương pháp tạo chuỗi khác mà bạn không cần phải lo lắng về việc phát hành.

Một sự khác biệt giữa thu gom rác và bể tự động là bộ sưu tập rác hoạt động với tham chiếu vòng tròn. Sử dụng các bể tự động, bạn không muốn có hai đối tượng giữ lại lẫn nhau và hy vọng rằng một khi không có gì khác đề cập đến chúng, chúng sẽ biến mất; họ sẽ không.

+0

Vì vậy, lợi ích của việc đưa các đối tượng vào các nhóm autorelease không phải giải phóng chúng bằng tay, nhưng nhược điểm là mất quyền kiểm soát trên * khi * để giải phóng nó? Về cơ bản, nếu tôi cung cấp cho đối tượng của tôi để autorelease hồ bơi, tôi ở đó là lòng thương xót cho phát hành nó bất cứ khi nào điều đó xảy ra? – Karolis

+0

Bạn có thể mất quyền kiểm soát khi bạn phát hành nó, nhưng không bị mất khi nó được giải phóng. Nếu bạn muốn giữ xung quanh một đối tượng đã được đặt trong một nhóm autorelease, bạn có thể chỉ cần gọi [obj retain] để số lượng giữ lại của nó vẫn lớn hơn 1 sau khi nhóm tự động phát hành nó. –

1
  1. Nếu tựnil sau khi khởi động siêu thì có lẽ bạn đang ra khỏi bộ nhớ. Hành động hợp lý duy nhất của bạn là trả lại nil và hy vọng mọi thứ được xử lý một cách duyên dáng hơn nữa lên ngăn xếp.

  2. Phương pháp tĩnh không được phép phân bổ trên heap, do đó không có gì để giải phóng.

  3. Trong trường hợp đầu tiên, chuỗi được biên dịch vào phân đoạn dữ liệu của ứng dụng của bạn và không thể được giải phóng. Trong trường hợp thứ hai, bạn đang cấp phát bộ nhớ từ heap và sao chép chuỗi tĩnh của bạn (từ phân đoạn dữ liệu) vào trong đó.

  4. Đó là bộ sưu tập rác đơn giản. Về lý do tại sao sử dụng nó, câu trả lời đơn giản là không. Bạn không nên sử dụng tự động phát trên iPhone do tài nguyên giới hạn.

+0

Về cơ bản, str = @ "Xin chào!" nằm trong phân đoạn dữ liệu này cho toàn bộ thời gian chạy ứng dụng, bất kể phần mã làm việc asignment có đạt được hay không? Nói cách khác, tôi càng có nhiều chuỗi như vậy, bộ nhớ càng nhiều thì ứng dụng của tôi sẽ yêu cầu ban đầu? Cảm ơn – Karolis

+0

"Xin chào!" nằm trong phần bss, str (có nghĩa là, lưu trữ cho 4-8 byte cần để đại diện cho một địa chỉ) nằm trong phần dữ liệu. str được khởi tạo với địa chỉ của chuỗi trong phần bss. –

2
  1. Có một trường phái tư tưởng rằng trong hầu hết các trường hợp, bố trí con trỏ self là cái gì mà hệ thống nên làm, và không phải là lập trình viên.

Ngoài ra, nhiều người muốn giữ dòng chính của luồng chương trình là không thể thụt lề càng tốt. Trong trường hợp đó, mã khởi tạo có thể được viết lại là:

- (id)init { 
    if (![super init]) { 
     return nil; // There is a problem so bail early. 
    } 
    // Initialisation code here. 
    return self 
} 

Will Shipley giải thích điều này tốt hơn nhiều so với tôi.

+0

Cảm ơn, bài đăng trên blog đó rất hữu ích. Và khó hiểu. Tôi hiểu nó nói về Cocoa, không Cocoa Touch, vì vậy có thể làm kiểm tra này vẫn còn hợp lệ cho những lý do được đề cập bởi những người khác trong môi trường iPhone (trong số các tình huống bộ nhớ)? – Karolis

+0

Nếu bạn mới bắt đầu, nó có thể gây nhầm lẫn. Tôi đưa nó lên như một ví dụ rằng có nhiều cách khác để viết những thứ đơn giản như những người khởi tạo. Đánh dấu chuỗi "Pimp My Code" của Wil và quay lại sau vài tháng; bạn sẽ thấy hữu ích khi nghĩ đến việc viết mã Cocoa/Obj-C. – Abizern

+0

Mục tiêu-C là ngôn ngữ. Ca cao và Cocoa Touch là các khung công tác. Mặc dù một số mẫu khác nhau giữa hai nguyên tắc, các nguyên tắc của Objective-C (bao gồm cả mẫu init) áp dụng cho cả hai. –

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