Apa praktik terbaik yang Anda gunakan saat menulis Objective-C dan Cocoa? [Tutup]

346

Saya tahu tentang HIG (yang cukup praktis!), Tetapi praktik pemrograman apa yang Anda gunakan saat menulis Objective-C, dan lebih khusus lagi ketika menggunakan Cocoa (atau CocoaTouch).

piksel
sumber
lihat posting blog ini, sangat bagus. ironwolf.dangerousgames.com/blog/archives/913
user392412

Jawaban:

398

Ada beberapa hal yang sudah mulai saya lakukan yang menurut saya tidak standar:

1) Dengan munculnya properti, saya tidak lagi menggunakan "_" untuk awalan variabel kelas "pribadi". Lagi pula, jika variabel dapat diakses oleh kelas lain, tidakkah seharusnya ada properti untuknya? Saya selalu tidak menyukai awalan "_" untuk membuat kode lebih buruk, dan sekarang saya bisa mengabaikannya.

2) Berbicara tentang hal-hal pribadi, saya lebih suka menempatkan definisi metode pribadi dalam file .m dalam ekstensi kelas seperti:

#import "MyClass.h"

@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end

@implementation MyClass

Mengapa mengacaukan file .h dengan hal-hal yang tidak dipedulikan orang luar? Kosong () berfungsi untuk kategori pribadi dalam file .m, dan mengeluarkan kompilasi peringatan jika Anda tidak mengimplementasikan metode yang dideklarasikan.

3) Saya telah mengambil untuk menempatkan dealloc di bagian atas file .m, tepat di bawah arahan @sintesis. Bukankah seharusnya yang Anda miliki berada di urutan teratas dalam daftar hal-hal yang ingin Anda pikirkan di kelas? Itu terutama berlaku di lingkungan seperti iPhone.

3.5) Dalam sel tabel, buat setiap elemen (termasuk sel itu sendiri) buram untuk kinerja. Itu berarti mengatur warna latar belakang yang sesuai dalam segala hal.

3.6) Saat menggunakan NSURLConnection, sebagai aturan Anda mungkin ingin menerapkan metode delegasi:

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
      return nil;
}

Saya menemukan sebagian besar panggilan web sangat unik dan ini lebih merupakan pengecualian daripada aturan yang Anda ingin cached tanggapan, terutama untuk panggilan layanan web. Menerapkan metode seperti yang ditunjukkan menonaktifkan caching tanggapan.

Yang juga menarik, adalah beberapa kiat khusus iPhone yang bagus dari Joseph Mattiello (diterima di milis iPhone). Ada lebih banyak, tetapi ini adalah yang paling berguna menurut saya (perhatikan bahwa beberapa bit sekarang telah sedikit diedit dari aslinya untuk memasukkan rincian yang ditawarkan dalam tanggapan):

4) Hanya gunakan presisi ganda jika Anda harus, seperti ketika bekerja dengan CoreLocation. Pastikan Anda mengakhiri konstanta Anda di 'f' untuk membuat gcc menyimpannya sebagai pelampung.

float val = someFloat * 2.2f;

Ini sebagian besar penting ketika someFloatsebenarnya merupakan dobel, Anda tidak memerlukan matematika mode campuran, karena Anda kehilangan presisi dalam 'val' pada penyimpanan. Sementara angka floating-point didukung dalam perangkat keras pada iPhone, masih mungkin membutuhkan lebih banyak waktu untuk melakukan aritmatika presisi ganda sebagai lawan dari presisi tunggal. Referensi:

Pada ponsel lama seharusnya perhitungan beroperasi pada kecepatan yang sama tetapi Anda dapat memiliki lebih banyak komponen presisi tunggal dalam register daripada dua kali lipat, sehingga untuk banyak perhitungan presisi tunggal akan berakhir menjadi lebih cepat.

5) Tetapkan properti Anda sebagai nonatomic. Mereka atomicsecara default dan pada sintesis, kode semaphore akan dibuat untuk mencegah masalah multi-threading. 99% dari Anda mungkin tidak perlu khawatir tentang hal ini dan kodenya jauh lebih sedikit membengkak dan lebih hemat memori ketika diatur ke nonatomik.

6) SQLite bisa menjadi cara yang sangat, sangat cepat untuk men-cache set data yang besar. Aplikasi peta misalnya dapat men-cache ubinnya ke file SQLite. Bagian yang paling mahal adalah disk I / O. Hindari banyak tulisan kecil dengan mengirim BEGIN;dan di COMMIT;antara blok besar. Kami menggunakan penghitung waktu 2 detik misalnya yang diatur ulang pada setiap pengiriman baru. Ketika kedaluwarsa, kami mengirimkan COMMIT; , yang menyebabkan semua tulisan Anda masuk dalam satu potongan besar. SQLite menyimpan data transaksi ke disk dan melakukan pembungkus Begin / End ini menghindari pembuatan banyak file transaksi, mengelompokkan semua transaksi menjadi satu file.

Juga, SQL akan memblokir GUI Anda jika ada di utas utama Anda. Jika Anda memiliki kueri yang sangat panjang, ide yang bagus untuk menyimpan kueri Anda sebagai objek statis, dan menjalankan SQL Anda di utas terpisah. Pastikan untuk membungkus apa pun yang memodifikasi database untuk string kueri dalam @synchronize() {}blok. Untuk pertanyaan singkat tinggalkan saja hal-hal di utas utama untuk kenyamanan yang lebih mudah.

Lebih banyak kiat pengoptimalan SQLite ada di sini, meskipun dokumen tersebut kedaluwarsa, banyak poin yang mungkin masih bagus;

http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html

Kendall Helmstetter Gelner
sumber
3
Tip-off bagus tentang aritmatika ganda.
Adam Ernst
8
Ekstensi kelas sekarang merupakan cara yang disukai untuk metode pribadi: developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/…
Casebash
9
Saran Anda tentang dobel pada iPhone kedaluwarsa stackoverflow.com/questions/1622729/…
Casebash
3
Tidak ketinggalan zaman; sepenuhnya salah: iPhone asli yang didukung mengapung dan menggandakan perangkat keras pada kecepatan yang kira-kira sama. SQLite juga tidak menyimpan transaksi dalam memori; mereka dijurnal di disk. Hanya kueri panjang yang memblokir UI Anda; itu kurang berantakan untuk menjalankan semuanya di utas utama dan menggunakan kueri yang lebih cepat.
tc.
1
@ tc: Saya mengoreksi item SQL tentang transaksi, perhatikan bahwa saya sendiri tidak menulis empat atau lebih item terakhir itu. Saya juga menjelaskan bagian tentang memindahkan kueri ke latar belakang hanya untuk kueri yang sangat lama (kadang-kadang Anda tidak bisa membuatnya lebih pendek). Tetapi untuk menyebut semuanya "salah" karena beberapa poin saya merasa agak ekstrim. Selain itu, jawaban di atas sudah menyatakan: "Pada ponsel lama seharusnya perhitungan beroperasi pada kecepatan yang sama" tetapi perhatikan bagian tentang jumlah register presisi tunggal yang lebih besar yang membuatnya masih lebih disukai.
Kendall Helmstetter Gelner
109

Jangan gunakan string yang tidak dikenal sebagai string format

Ketika metode atau fungsi mengambil argumen string format, Anda harus memastikan bahwa Anda memiliki kontrol atas konten string format.

Misalnya, saat mencatat string, tergoda untuk meneruskan variabel string sebagai satu-satunya argumen untuk NSLog:

    NSString *aString = // get a string from somewhere;
    NSLog(aString);

Masalah dengan ini adalah bahwa string dapat berisi karakter yang ditafsirkan sebagai format string. Ini dapat menyebabkan masalah output, crash, dan masalah keamanan. Sebagai gantinya, Anda harus mengganti variabel string menjadi string format:

    NSLog(@"%@", aString);
mmalc
sumber
4
Saya pernah digigit oleh yang ini sebelumnya.
Adam Ernst
Ini adalah saran yang bagus untuk bahasa pemrograman apa pun
Tom Fobear
107

Gunakan konvensi penamaan dan pemformatan standar Cocoa dan terminologi alih-alih apa pun yang Anda gunakan dari lingkungan lain. Ada yang banyak pengembang Kakao di luar sana, dan ketika salah satu dari mereka mulai bekerja dengan kode Anda, itu akan jauh lebih mudah didekati jika terlihat dan terasa mirip dengan kode Cocoa lain.

Contoh apa yang harus dilakukan dan apa yang tidak boleh dilakukan:

  • Jangan mendeklarasikan id m_something;dalam antarmuka objek dan menyebutnya variabel anggota atau bidang ; gunakan somethingatau _somethinguntuk namanya dan sebut itu variabel instan .
  • Jangan beri nama pengambil -getSomething; nama Kakao yang tepat adalah adil -something.
  • Jangan beri nama setter -something:; harus-setSomething:
  • Nama metode diselingi dengan argumen dan termasuk titik dua; itu -[NSObject performSelector:withObject:], tidak NSObject::performSelector.
  • Gunakan inter-caps (CamelCase) dalam nama metode, parameter, variabel, nama kelas, dll. Daripada underbars (garis bawah).
  • Nama kelas dimulai dengan huruf besar, variabel dan nama metode dengan huruf kecil.

Apa pun yang Anda lakukan, jangan gunakan notasi Hungaria gaya Win16 / Win32. Bahkan Microsoft menyerah pada itu dengan pindah ke platform .NET.

Chris Hanson
sumber
5
Saya berpendapat, jangan gunakan setSomething: / something at all - alih-alih gunakan properti. Pada titik ini ada beberapa orang yang benar-benar perlu menargetkan Tiger (satu-satunya alasan untuk tidak menggunakan properti)
Kendall Helmstetter Gelner
18
Properti masih menghasilkan metode accessor untuk Anda, dan atribut pengambil = / setter = pada properti memungkinkan Anda menentukan nama metode. Selain itu, Anda dapat menggunakan sintaks [foo something] alih-alih sintaks foo.something dengan properti. Jadi penamaan accessor masih relevan.
Chris Hanson
3
Ini adalah referensi yang bagus untuk seseorang yang datang dari C ++, di mana saya melakukan sebagian besar hal yang Anda sarankan.
Clinton Blackmore
4
Setter tidak seharusnya menyebabkan sesuatu disimpan ke database. Ada alasan mengapa Core Data memiliki -simpan: metode pada NSManagedObjectContext, daripada memiliki setter menghasilkan pembaruan segera.
Chris Hanson
2
Saya ragu itu bukan pilihan, namun mungkin perlu mengunjungi kembali arsitektur aplikasi Anda. (Untuk lebih jelasnya: Saya tidak mengatakan "Anda harus menggunakan Data Inti." Saya mengatakan "Setter tidak boleh menyimpan ke database.") Memiliki konteks untuk mengelola grafik objek, daripada menyimpan objek individual di dalamnya , Hampir selalu keduanya mungkin dan solusi yang lebih baik.
Chris Hanson
106

IBOutlet

Secara historis, manajemen memori outlet sudah buruk. Praktik terbaik saat ini adalah mendeklarasikan outlet sebagai properti:

@interface MyClass :NSObject {
    NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end

Menggunakan properti membuat semantik manajemen memori menjadi jelas; itu juga menyediakan pola yang konsisten jika Anda menggunakan sintesis variabel instan.

mmalc
sumber
1
bukankah memuat nib akan menahannya dua kali? (Sekali dalam pena, kedua dengan penugasan ke properti). Apakah saya harus melepaskan yang ada di dealloc?
Kornel
6
Anda harus menumpahkan outlet di viewDidUnload (iPhone OS 3.0+) atau dalam metode setView: kustom untuk menghindari kebocoran. Jelas Anda juga harus melepaskan dealloc.
Frank Szczerba
2
Ingatlah bahwa tidak semua orang setuju dengan gaya ini: weblog.bignerdranch.com/?p=95
Michael
Ini adalah cara Apple melakukan sesuatu juga. "Pengembangan iPhone 3 Awal" menyebutkan perubahan ini dari versi sebelumnya juga.
ustun
Saya menyebutkan ini di komentar lain, tetapi harus meletakkannya di sini: Begitu sintesis ivar dinamis mulai terjadi untuk aplikasi iOS (jika / kapan?), Anda akan senang Anda meletakkan IBOutlet di properti vs. ivar!
Joe D'Andrea
97

Gunakan LLVM / Dentang Analisis Statis

CATATAN: Di bawah Xcode 4 ini sekarang dibangun ke dalam IDE.

Anda menggunakan Clang Static Analyzer untuk - secara tidak mengejutkan - menganalisis kode C dan Objective-C Anda (belum ada C ++) di Mac OS X 10.5. Sepele untuk menginstal dan menggunakan:

  1. Unduh versi terbaru dari halaman ini .
  2. Dari baris perintah, cdke direktori proyek Anda.
  3. Jalankan scan-build -k -V xcodebuild.

(Ada beberapa kendala tambahan dll., Khususnya Anda harus menganalisis proyek dalam konfigurasi "Debug" - lihat http://clang.llvm.org/StaticAnalysisUsage.html untuk detailnya - tapi itu lebih atau kurang apa intinya.)

Penganalisa kemudian menghasilkan satu set halaman web untuk Anda yang menunjukkan kemungkinan manajemen memori dan masalah dasar lainnya yang tidak dapat dideteksi oleh kompiler.

mmalc
sumber
1
Saya mengalami beberapa kesulitan untuk menjalankannya sampai saya mengikuti instruksi ini: oiledmachine.com/posts/2009/01/06/…
bbrown
15
Di XCode 3.2.1 pada Snow Leopard, sudah ada di dalamnya. Anda dapat menjalankannya secara manual, menggunakan Run -> Build and Analyze , atau Anda dapat mengaktifkannya untuk semua build melalui pengaturan build "Run Static Analyzer". Perhatikan bahwa alat ini saat ini hanya mendukung C dan Objective-C, tetapi tidak C ++ / Objective-C ++.
oefe
94

Ini yang halus tapi praktis. Jika Anda menyerahkan diri sebagai delegasi ke objek lain, setel ulang delegasi objek itu sebelum Anda dealloc.

- (void)dealloc
{
self.someObject.delegate = NULL;
self.someObject = NULL;
//
[super dealloc];
}

Dengan melakukan ini, Anda memastikan tidak ada lagi metode delegasi yang akan dikirim. Saat Anda akandealloc dan menghilang ke eter Anda ingin memastikan bahwa tidak ada yang dapat mengirimi Anda pesan lagi secara tidak sengaja. Ingat diri Anda sendiri. Beberapa objek dapat disimpan oleh objek lain (bisa tunggal atau di kolam autorelease atau apa pun) dan sampai Anda mengatakan "berhenti mengirimi saya pesan!", Ia berpikir objek Anda yang baru saja akan dealloced adalah permainan yang adil.

Masuk ke kebiasaan ini akan menyelamatkan Anda dari banyak crash aneh yang menyulitkan untuk debug.

Prinsipal yang sama berlaku untuk Pengamatan Nilai Kunci, dan NSNotifikasi juga.

Edit:

Yang lebih defensif, ubah:

self.someObject.delegate = NULL;

ke:

if (self.someObject.delegate == self)
    self.someObject.delegate = NULL;
schwa
sumber
8
Tidak ada yang halus tentang ini, dokumentasi dengan jelas mengatakan bahwa Anda diminta untuk melakukan ini. Dari Memory Management Programming Guide for Cocoa: Additional cases of weak references in Cocoa include, but are not restricted to, table data sources, outline view items, notification observers, and miscellaneous targets and delegates. In most cases, the weak-referenced object is aware of the other object’s weak reference to it, as is the case for circular references, and is responsible for notifying the other object when it deallocates.
johne
Lebih baik menggunakan nil daripada NULL, karena NULL tidak akan membebaskan memori.
Naveen Shan
@NaveenShan nil == NULL. Mereka persis sama kecuali itu niladalah iddan NULLadalah a void *. Pernyataan Anda tidak benar.
@WTP ya, nil == NULL, tetapi menggunakan nil jelas merupakan cara yang disukai, jika Anda melihat melalui apel contoh fragmen kode, mereka menggunakan nil di mana-mana, dan seperti yang Anda katakan, nil adalah id, yang membuatnya lebih disukai daripada kekosongan * , dalam kasus di mana Anda mengirim id, yaitu.
Ahti
1
@Ahti tepatnya, dan Nil(huruf besar) adalah tipe Class*. Meskipun mereka semua sama, menggunakan yang salah dapat memperkenalkan bug kecil yang jahat, terutama di Objective-C ++.
86

@endell

Dari pada:

@interface MyClass (private)
- (void) someMethod
- (void) someOtherMethod
@end

Menggunakan:

@interface MyClass ()
- (void) someMethod
- (void) someOtherMethod
@end

Baru di Objective-C 2.0.

Ekstensi kelas dijelaskan dalam Referensi Objective-C 2.0 Apple.

"Ekstensi kelas memungkinkan Anda untuk mendeklarasikan API tambahan yang diperlukan untuk kelas di lokasi selain dari dalam kelas utama @interface blok"

Jadi mereka adalah bagian dari kelas aktual - dan BUKAN kategori (pribadi) selain kelas. Perbedaan yang halus tapi penting.

schwa
sumber
Anda bisa melakukan itu tetapi saya suka memberi label secara eksplisit sebagai bagian "pribadi" (lebih banyak dokumentasi daripada fungsional) meskipun tentu saja sudah banyak yang jelas dari itu yang terletak di file .m ...
Kendall Helmstetter Gelner
2
Kecuali ada adalah perbedaan antara kategori swasta dan ekstensi kelas: "Kelas ekstensi memungkinkan Anda untuk menyatakan tambahan API diperlukan untuk kelas di lokasi lain selain di dalam blok kelas @ antarmuka utama, seperti yang digambarkan dalam contoh berikut:" Lihat link di edit.
schwa
Saya setuju ada perbedaan di mana kompiler akan memperingatkan Anda ketika Anda belum menerapkan metode CE - tetapi saya tidak menemukan aspek itu sangat penting ketika semua metode berada di file yang sama, dan semua pribadi. Saya masih lebih suka aspek rawatan dari menandai blok referensi maju pribadi
Kendall Helmstetter Gelner
3
Saya benar-benar tidak melihat (Pribadi) sebagai yang lebih dapat dikelola daripada (). Jika Anda begitu khawatir maka komentar yang baik dapat membantu. Tapi jelas hidup dan biarkan hidup. YMMV dll.
schwa
17
Ada keuntungan yang agak penting untuk digunakan ()daripada (Private)(atau beberapa nama kategori lainnya): Anda dapat mendeklarasikan ulang properti sebagai readwrite sementara untuk umum mereka hanya dibaca saja. :)
Pascal
75

Hindari autorelease

Karena Anda biasanya (1) tidak memiliki kendali langsung selama masa pakainya, objek autoreleased dapat bertahan untuk waktu yang relatif lama dan secara tidak perlu meningkatkan jejak memori aplikasi Anda. Sementara di desktop ini mungkin ada konsekuensi kecil, pada platform yang lebih terbatas ini bisa menjadi masalah yang signifikan. Oleh karena itu, pada semua platform, dan terutama pada platform yang lebih terbatas, ini dianggap praktik terbaik untuk menghindari menggunakan metode yang akan mengarah ke objek autoreleased dan sebaliknya Anda didorong untuk menggunakan pola alokasi / init.

Jadi, daripada:

aVariable = [AClass convenienceMethod];

jika memungkinkan, Anda sebaiknya menggunakan:

aVariable = [[AClass alloc] init];
// do things with aVariable
[aVariable release];

Saat Anda menulis metode Anda sendiri yang mengembalikan objek yang baru dibuat, Anda dapat memanfaatkan konvensi penamaan Cocoa untuk menandai ke penerima yang harus dilepaskan dengan menambahkan nama metode dengan "baru".

Jadi, bukannya:

- (MyClass *)convenienceMethod {
    MyClass *instance = [[[self alloc] init] autorelease];
    // configure instance
    return instance;
}

Anda bisa menulis:

- (MyClass *)newInstance {
    MyClass *instance = [[self alloc] init];
    // configure instance
    return instance;
}

Karena nama metode dimulai dengan "baru", konsumen API Anda tahu bahwa mereka bertanggung jawab untuk melepaskan objek yang diterima (lihat, misalnya, metode NSObjectController'snewObject ).

(1) Anda dapat mengambil kendali dengan menggunakan kolam autorelease lokal Anda sendiri. Untuk lebih lanjut tentang ini, lihat Autorelease Pools .

mmalc
sumber
6
Saya menemukan manfaat tidak menggunakan autorelease melebihi biayanya (yaitu lebih banyak bug kebocoran memori). Kode pada utas utama seharusnya cukup berjalan singkat (atau jika tidak Anda akan membekukan UI) dan untuk berjalan lebih lama, kode latar belakang intensif-memori, Anda selalu dapat membungkus bagian-bagian yang membutuhkan banyak memori dalam kumpulan autorelease lokal.
adib
56
Saya tidak setuju. Anda harus menggunakan objek autoreleased bila memungkinkan. Jika mereka menambah jejak memori terlalu banyak Anda harus menggunakan yang lain NSAutoreleasePool. Tetapi hanya setelah Anda mengkonfirmasi bahwa ini benar-benar masalah. Optimalisasi prematur dan semua itu ...
Sven
3
Saya menghabiskan kurang dari 40 detik. suatu hari mengetik [someObject release] dan membaca "extra line" ketika membuat objek baru, tapi saya pernah membakar 17 jam untuk menemukan bug autorelease yang hanya akan muncul dalam kasus khusus dan tidak memberikan kesalahan yang masuk akal di konsol. Jadi saya setuju dengan adib ketika ia mengatakannya seperti "Saya menemukan manfaat dari tidak menggunakan autorelease melebihi biayanya".
RickiG
7
Saya setuju dengan Sven. Sasaran utama haruslah kejelasan kode dan mengurangi kesalahan pengkodean, dengan pengoptimalan memori hanya jika diperlukan. Mengetik autorelease [[[Foo alokasi] init]] cepat dan Anda segera berurusan dengan masalah melepaskan objek baru ini. Saat membaca kode Anda tidak perlu mencari-cari rilis yang sesuai untuk memastikan tidak bocor.
Mike Weller
3
Siklus hidup objek autoreleased didefinisikan dengan baik dan dapat ditentukan pada tingkat yang cukup.
Eonil
69

Beberapa di antaranya telah disebutkan, tetapi inilah yang dapat saya pikirkan dari atas kepala saya:

  • Ikuti aturan penamaan KVO. Bahkan jika Anda tidak menggunakan KVO sekarang, dalam pengalaman saya sering kali itu masih bermanfaat di masa depan. Dan jika Anda menggunakan KVO atau binding, Anda perlu tahu bahwa segala sesuatunya berjalan sebagaimana mestinya. Ini mencakup tidak hanya metode pengaksesan dan variabel instan, tetapi ke-banyak hubungan, validasi, kunci dependen pemberitahuan otomatis, dan sebagainya.
  • Masukkan metode pribadi dalam kategori. Bukan hanya antarmuka, tetapi implementasinya juga. Sebaiknya ada jarak secara konseptual antara metode pribadi dan non-pribadi. Saya memasukkan semua yang ada di file .m saya.
  • Masukkan metode utas latar belakang dalam suatu kategori.Sama seperti di atas. Saya menemukan bahwa menjaga penghalang konseptual yang baik adalah baik ketika Anda memikirkan apa yang ada di utas utama dan apa yang tidak.
  • Gunakan #pragma mark [section]. Biasanya saya mengelompokkan dengan metode saya sendiri, penggantian setiap subclass, dan informasi atau protokol formal apa pun. Ini membuatnya jauh lebih mudah untuk melompat ke apa yang saya cari. Pada topik yang sama, kelompokkan metode serupa (seperti metode delegasi tampilan tabel) bersama-sama, jangan hanya menempelkannya di mana saja.
  • Awali metode pribadi & ivar dengan _. Saya suka tampilannya, dan saya cenderung tidak menggunakan ivar ketika saya maksudkan sebuah properti secara tidak sengaja.
  • Jangan gunakan metode / properti mutator di init & dealloc. Saya tidak pernah mengalami hal buruk karena itu, tetapi saya dapat melihat logikanya jika Anda mengubah metode untuk melakukan sesuatu yang tergantung pada keadaan objek Anda.
  • Masukkan IBOutlet di properti. Saya sebenarnya baru saja membaca ini di sini, tetapi saya akan mulai melakukannya. Terlepas dari manfaat memori, tampaknya lebih baik gaya (setidaknya bagi saya).
  • Hindari menulis kode yang tidak benar-benar Anda butuhkan. Ini benar-benar mencakup banyak hal, seperti membuat ivars ketika #defineakan melakukan, atau caching array bukannya mengurutkannya setiap kali data dibutuhkan. Ada banyak yang bisa saya katakan tentang ini, tetapi intinya adalah jangan menulis kode sampai Anda membutuhkannya, atau profiler memberitahu Anda untuk melakukannya. Itu membuat banyak hal lebih mudah untuk dipertahankan dalam jangka panjang.
  • Selesaikan apa yang Anda mulai. Memiliki banyak kode kereta yang setengah jadi, adalah cara tercepat untuk membunuh proyek yang mati. Jika Anda memerlukan metode rintisan yang baik-baik saja, cukup tandai dengan memasukkannya ke NSLog( @"stub" )dalam, atau bagaimanapun Anda ingin melacak hal-hal.
Marc Charbonneau
sumber
3
Saya menyarankan agar Anda menempatkan metode pribadi dalam kelanjutan kelas. (ie @interface MyClass () ... @end in .m Anda)
Jason Medeiros
3
Alih-alih #PRAGMA Anda dapat menggunakan komentar // Tandai: [Bagian] yang lebih portabel dan berfungsi secara identik.
aleemb
Kecuali jika ada sintaks khusus yang saya lewatkan, // Tandai: tidak menambahkan label di menu tarik-turun fungsi Xcode, yang benar-benar setengah alasan menggunakannya.
Marc Charbonneau
6
Anda perlu menggunakan huruf besar, "// MARK: ...", untuk membuatnya muncul di drop down.
Rhult
3
Sehubungan dengan itu Finish what you startAnda juga dapat menggunakan // TODO:untuk menandai kode untuk penyelesaian yang akan muncul di drop down.
iwasrobbed
56

Tulis tes unit. Anda dapat menguji banyak hal dalam Kakao yang mungkin lebih sulit dalam kerangka kerja lain. Misalnya, dengan kode UI, Anda biasanya dapat memverifikasi bahwa segala sesuatu terhubung sebagaimana mestinya dan percaya bahwa semuanya akan berfungsi saat digunakan. Dan Anda dapat mengatur negara & memanggil metode delegasi dengan mudah untuk mengujinya.

Anda juga tidak memiliki visibilitas metode publik vs. terlindungi vs pribadi yang menghalangi penulisan tes untuk internal Anda.

Chris Hanson
sumber
Kerangka uji apa yang Anda rekomendasikan?
melfar
13
Xcode mencakup OCUnit, kerangka kerja pengujian unit Objective-C, dan dukungan untuk menjalankan kumpulan uji unit sebagai bagian dari proses pembuatan Anda.
Chris Hanson
55

Golden Rule: Jika kamu allocmaka kamu release!

UPDATE: Kecuali Anda menggunakan ARC

logancautrell
sumber
26
Juga jika Anda copy, mutableCopy, newatau retain.
Sven
54

Jangan menulis Objective-C seolah-olah itu Java / C # / C ++ / etc.

Saya pernah melihat tim yang biasa menulis aplikasi web Java EE mencoba menulis aplikasi desktop Cocoa. Seolah-olah itu adalah aplikasi web Java EE. Ada banyak AbstractFooFactory dan FooFactory dan IFoo dan Foo terbang di sekitar ketika semua yang mereka butuhkan adalah kelas Foo dan mungkin protokol Fooable.

Bagian dari memastikan Anda tidak melakukan ini adalah benar-benar memahami perbedaan dalam bahasa. Misalnya, Anda tidak memerlukan pabrik abstrak dan kelas pabrik di atas karena metode kelas Objective-C dikirimkan sama dinamisnya dengan metode instance, dan dapat ditimpa dalam subkelas.

Chris Hanson
sumber
10
Sebagai pengembang Java yang telah menulis sebuah pabrik abstrak di Objective-C saya menemukan ini menarik. Maukah Anda menjelaskan sedikit lebih banyak tentang bagaimana ini bekerja - mungkin dengan sebuah contoh?
teko
2
Apakah Anda masih percaya kami tidak perlu kelas pabrik abstrak setelah semua waktu yang lalu sejak Anda memposting jawaban ini?
kirk.burleson
50

Pastikan Anda mem-bookmark halaman Magic Debugging . Ini harus menjadi perhentian pertama Anda ketika membenturkan kepala ke dinding saat mencoba menemukan sumber bug Cocoa.

Misalnya, ini akan memberi tahu Anda bagaimana menemukan metode di mana Anda pertama kali mengalokasikan memori yang kemudian menyebabkan kerusakan (seperti saat penghentian aplikasi).

mj1531
sumber
1
Sekarang ada versi khusus iOS dari halaman Debugging Magic .
Jeethu
38

Cobalah untuk menghindari apa yang sekarang saya putuskan untuk memanggil Newbiecategoryaholism. Ketika pendatang baru di Objective-C menemukan kategori mereka sering menjadi liar, menambahkan kategori kecil yang berguna untuk setiap kelas yang ada ( "Apa? Saya bisa menambahkan metode untuk mengubah angka menjadi angka romawi menjadi NSNumber rock on!" ).

Jangan lakukan ini.

Kode Anda akan lebih portabel dan lebih mudah dipahami tanpa banyak metode kategori kecil yang ditaburkan di atas dua lusin kelas dasar.

Sebagian besar waktu ketika Anda benar-benar berpikir Anda membutuhkan metode kategori untuk membantu merampingkan beberapa kode Anda akan menemukan Anda tidak pernah akhirnya menggunakan kembali metode tersebut.

Ada bahaya lain juga, kecuali jika Anda menempatkan metode kategori Anda (dan siapa selain ddribin yang benar-benar gila?) Ada kemungkinan bahwa Apple, atau plugin, atau sesuatu yang berjalan di ruang alamat Anda juga akan menentukan kategori yang sama metode dengan nama yang sama dengan efek samping yang sedikit berbeda ....

BAIK. Sekarang Anda telah diperingatkan, abaikan "jangan lakukan bagian ini". Tetapi berolahraga dengan menahan diri.

schwa
sumber
Saya suka jawaban Anda, saran saya adalah dengan tidak menggunakan kategori untuk menyimpan kode utilitas kecuali Anda akan mereplikasi beberapa kode di lebih dari satu tempat dan kode jelas milik kelas yang akan Anda kategorikan ...
Kendall Helmstetter Gelner
Saya hanya ingin memasukkan dan menyuarakan dukungan saya untuk metode kategori namespacing. Sepertinya hal yang tepat untuk dilakukan.
Michael Buckley
+1 jika hanya untuk angka romawi. Saya benar-benar akan melakukannya!
Brian Postow
14
Counter-point: Selama satu setengah tahun terakhir saya telah mengikuti kebijakan sebaliknya: "Jika itu dapat diterapkan dalam suatu kategori, lakukanlah." Sebagai hasilnya, kode saya jauh lebih ringkas, lebih ekspresif, dan lebih mudah dibaca daripada kode sampel verbose yang disediakan Apple. Saya telah kehilangan total sekitar 10 menit untuk satu konflik namespace, dan saya mungkin telah memperoleh beberapa bulan dari efisiensi yang saya buat untuk diri saya sendiri. Untuk masing-masing, tetapi saya mengadopsi kebijakan ini mengetahui risikonya, dan saya sangat senang saya melakukannya.
cduhn
7
Saya tidak setuju. Jika itu akan menjadi fungsi dan itu berlaku untuk objek Foundation, dan Anda bisa memikirkan nama yang baik, masukkan dalam kategori. Kode Anda akan lebih mudah dibaca. Saya pikir yang benar-benar poin penting di sini adalah: melakukan segalanya dengan tidak berlebihan.
mxcl
37

Tahan subklas dunia. Dalam Cocoa banyak dilakukan melalui pendelegasian dan penggunaan runtime yang mendasarinya yang dalam kerangka kerja lain dilakukan melalui subclassing.

Sebagai contoh, di Jawa Anda sering menggunakan instance dari *Listenersubclass anonim dan .NET Anda banyak menggunakan EventArgssubclass Anda . Di Cocoa, Anda tidak melakukan keduanya - target-aksi digunakan sebagai gantinya.

Chris Hanson
sumber
6
Atau dikenal sebagai "Komposisi atas warisan".
Andrew Ebling
37

Urutkan string sesuai keinginan pengguna

Saat Anda mengurutkan string untuk disajikan kepada pengguna, Anda tidak harus menggunakan compare:metode sederhana . Sebagai gantinya, Anda harus selalu menggunakan metode perbandingan lokal seperti localizedCompare:atau localizedCaseInsensitiveCompare:.

Untuk detail lebih lanjut, lihat Menelusuri, Membandingkan, dan Menyortir String .

mmalc
sumber
31

Properti yang Dideklarasikan

Anda biasanya harus menggunakan fitur Objective-C 2.0 Declared Properties untuk semua properti Anda. Jika tidak publik, tambahkan di ekstensi kelas. Menggunakan properti yang dideklarasikan membuat semantik manajemen memori segera menjadi jelas, dan membuatnya lebih mudah bagi Anda untuk memeriksa metode dealloc Anda - jika Anda mengelompokkan deklarasi properti Anda bersama-sama, Anda dapat dengan cepat memindai dan membandingkannya dengan penerapan metode dealloc Anda.

Anda harus berpikir keras sebelum tidak menandai properti sebagai 'nonatomik'. Seperti yang dicatat oleh Panduan Bahasa Pemrograman Objective C , properti adalah atom secara default, dan menimbulkan overhead yang besar. Selain itu, hanya membuat semua properti Anda tidak membuat aplikasi Anda aman. Juga perhatikan, tentu saja, bahwa jika Anda tidak menentukan 'nonatomik' dan mengimplementasikan metode pengakses Anda sendiri (daripada mensintesisnya), Anda harus mengimplementasikannya dengan cara atom.

mmalc
sumber
26

Pikirkan tentang nilai nil

Sebagaimana dicatat oleh pertanyaan ini , pesan-pesan menjadi nilvalid di Objective-C. Meskipun ini sering merupakan keuntungan - yang mengarah pada kode yang lebih bersih dan lebih alami - fitur ini kadang-kadang dapat menyebabkan bug yang aneh dan sulit dilacak jika Anda mendapatkan nilnilai saat Anda tidak mengharapkannya.

mmalc
sumber
Saya punya ini: #define SXRelease(o); o = nildan sama untuk CFReleasedan free. Ini menyederhanakan segalanya.
26

Gunakan NSAssert dan teman-teman. Saya menggunakan nil sebagai objek yang valid sepanjang waktu ... terutama mengirim pesan ke nil benar-benar valid di Obj-C. Namun jika saya benar-benar ingin memastikan keadaan variabel, saya menggunakan NSAssert dan NSParameterAssert, yang membantu melacak masalah dengan mudah.

NikWest
sumber
23

Sederhana tapi sering dilupakan. Menurut spec:

Secara umum, metode di kelas yang berbeda yang memiliki pemilih yang sama (nama yang sama) juga harus berbagi jenis argumen dan pengembalian yang sama. Batasan ini dikenakan oleh kompiler untuk memungkinkan pengikatan dinamis.

dalam hal ini semua penyeleksi bernama yang sama, bahkan jika dalam kelas yang berbeda , akan dianggap memiliki tipe pengembalian / argumen yang identik. Ini adalah contoh sederhana.

@interface FooInt:NSObject{}
-(int) print;
@end

@implementation FooInt
-(int) print{
    return 5;
}
@end

@interface FooFloat:NSObject{}
-(float) print;
@end

@implementation FooFloat
-(float) print{
    return 3.3;
}
@end

int main (int argc, const char * argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];    
    id f1=[[FooFloat alloc]init];
    //prints 0, runtime considers [f1 print] to return int, as f1's type is "id" and FooInt precedes FooBar
    NSLog(@"%f",[f1 print]);

    FooFloat* f2=[[FooFloat alloc]init];
    //prints 3.3 expectedly as the static type is FooFloat
    NSLog(@"%f",[f2 print]);

    [f1 release];
    [f2 release]
    [pool drain];

    return 0;
}   
Comptrol
sumber
itu mudah untuk dilupakan. Meskipun demikian Penting
Brock Woolf
3
Ini hanya masalah ketika menahan diri dari pengetikan statis. Jika kompiler mengetahui tipe, argumen dan tipe pengembalian dapat berbeda tanpa masalah. Personnaly, saya menemukan ini tidak sering menjadi masalah. Apple juga memiliki banyak metode yang memiliki nama yang sama tetapi berbeda dalam jenis pengembalian. Akhirnya, ada flag compiler untuk memperingatkan Anda dalam kasus yang ambigu.
Nikolai Ruhe
Jika kita mengikuti pedoman konvensi penamaan Apple, situasi ini tidak akan terjadi :)
Eonil
22

Jika Anda menggunakan Leopard (Mac OS X 10.5) atau lebih baru, Anda dapat menggunakan aplikasi Instruments untuk menemukan dan melacak kebocoran memori. Setelah membuat program Anda di Xcode, pilih Jalankan> Mulai dengan Alat Kinerja> Kebocoran.

Bahkan jika aplikasi Anda tidak menunjukkan kebocoran, Anda mungkin menyimpan benda terlalu lama. Di Instrumen, Anda bisa menggunakan instrumen ObjectAlloc untuk ini. Pilih instrumen ObjectAlloc dalam dokumen Instrumen Anda, dan buka detail instrumen (jika belum ditampilkan) dengan memilih View> Detail (harus memiliki tanda centang di sebelahnya). Di bawah "Allokasi Lifespan" di detail ObjectAlloc, pastikan Anda memilih tombol radio di sebelah "Created & Still Living".

Sekarang setiap kali Anda berhenti merekam aplikasi Anda, memilih alat ObjectAlloc akan menunjukkan kepada Anda berapa banyak referensi untuk setiap objek yang masih hidup dalam aplikasi Anda di kolom "# Net". Pastikan Anda tidak hanya melihat kelas Anda sendiri, tetapi juga kelas objek tingkat atas file NIB Anda. Misalnya, jika Anda tidak memiliki jendela di layar, dan Anda melihat referensi ke NSWindow yang masih hidup, Anda mungkin belum merilisnya dalam kode Anda.

mj1531
sumber
21

Bersihkan di dealloc.

Ini adalah salah satu hal yang paling mudah untuk dilupakan - esp. saat pengkodean pada 150mph. Selalu, selalu, selalu bersihkan atribut / variabel anggota Anda di dealloc.

Saya suka menggunakan atribut Objc 2 - dengan notasi titik baru - jadi ini membuat pembersihan tidak menyakitkan. Seringkali sesederhana:

- (void)dealloc
{
    self.someAttribute = NULL;
    [super dealloc];
}

Ini akan menangani rilis untuk Anda dan mengatur atribut ke NULL (yang saya anggap pemrograman defensif - jika metode lain lebih jauh di dealloc mengakses variabel anggota lagi - jarang tetapi bisa terjadi).

Dengan GC dihidupkan dalam 10.5, ini tidak diperlukan lagi - tetapi Anda mungkin masih perlu membersihkan sumber daya lain yang Anda buat, Anda bisa melakukannya dengan metode finalisasi.

schwa
sumber
12
Secara umum Anda tidak boleh menggunakan metode accessor di dealloc (atau init).
mmalc
1
Terlepas dari alasan kinerja (pengakses sedikit lebih lambat dari akses langsung) mengapa saya tidak boleh menggunakan pengakses di dealloc atau init?
schwa
1
(A) Alasan kinerja adalah alasan yang cukup memadai dalam diri mereka sendiri (terutama jika accessors Anda adalah atom). (B) Anda harus menghindari efek samping yang mungkin dimiliki oleh pengakses. Yang terakhir ini terutama masalah jika kelas Anda mungkin subkelas.
mmalc
3
Saya akan mencatat bahwa jika Anda menjalankan runtime modern dengan ivars yang disintesis Anda harus menggunakan accessors di dealloc. Banyak kode runtime modern adalah GC, tetapi tidak semuanya.
Louis Gerbarg
1
Pandangan yang lebih luas tentang apakah atau tidak menggunakan metode / properti accessor dalam -initdan -deallocmetode dapat ditemukan di sini: mikeash.com/?page=pyblog/…
Johan Kool
17

Semua komentar ini bagus, tapi saya benar-benar terkejut tidak ada yang menyebutkan Panduan Gaya Objective-C Google yang diterbitkan beberapa waktu lalu. Saya pikir mereka telah melakukan pekerjaan yang sangat teliti.

slf
sumber
7
Hmm, contoh pertama sudah penuh dengan omong kosong. Jangan pernah mendokumentasikan idiom bahasa. Jika saya menemukan komentar semacam itu di file header, saya tidak akan repot membaca.
Stephan Eggermont
5
Oh mataku !!!!! Saya tidak percaya apa yang saya lihat.
Eonil
13

Jangan lupa bahwa NSWindowController dan NSViewController akan merilis objek tingkat atas dari file NIB yang mereka atur.

Jika Anda memuat file NIB secara manual, Anda bertanggung jawab untuk melepaskan objek tingkat atas NIB itu ketika Anda selesai menggunakannya.

mj1531
sumber
12

Satu yang agak jelas untuk digunakan pemula: gunakan fitur indentasi otomatis Xcode untuk kode Anda. Bahkan jika Anda menyalin / menempel dari sumber lain, setelah Anda menempelkan kode, Anda dapat memilih seluruh blok kode, klik kanan padanya, dan kemudian pilih opsi untuk indentasi ulang segala sesuatu di dalam blok itu.

Xcode sebenarnya akan mem-parsing melalui bagian itu dan membuat indentasi berdasarkan kurung, loop, dll. Ini jauh lebih efisien daripada menekan spasi atau tombol tab untuk setiap baris.

iWasRobbed
sumber
Anda bahkan dapat mengatur Tab ke indentasi dan kemudian lakukan Cmd-A dan Tab.
Plumenator
10

Saya tahu saya mengabaikan ini ketika pertama kali masuk ke pemrograman Kakao.

Pastikan Anda memahami tanggung jawab manajemen memori terkait file NIB. Anda bertanggung jawab untuk merilis objek tingkat atas dalam file NIB apa pun yang Anda muat. Baca Dokumentasi Apple tentang masalah ini.

mj1531
sumber
6
Ini tidak benar. Apakah Anda bertanggung jawab untuk melepaskan objek tingkat atas tergantung pada kelas apa yang Anda warisi dan platform apa yang Anda gunakan. Lihat developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/… di antara yang lainnya.
mmalc
10

Nyalakan semua peringatan GCC, lalu matikan yang secara teratur disebabkan oleh header Apple untuk mengurangi kebisingan.

Juga sering menjalankan analisis statis Dentang; Anda dapat mengaktifkannya untuk semua build melalui pengaturan build "Run Static Analyzer".

Tulis pengujian unit dan jalankan dengan setiap build.

Oefe
sumber
Dan, jika Anda bisa, nyalakan "Treat Warnings as Errors". Izinkan tidak ada peringatan.
Peter Hosey
2
Sebuah skrip yang berguna untuk mengatur proyek Anda dengan peringatan yang direkomendasikan tersedia di sini: rentzsch.tumblr.com/post/237349423/hoseyifyxcodewarnings-scpt
Johan Kool
10

Variabel dan properti

1 / Menjaga header Anda tetap bersih, menyembunyikan implementasi,
Jangan sertakan variabel instan di header Anda. Variabel pribadi dimasukkan ke dalam kelanjutan kelas sebagai properti. Variabel publik menyatakan sebagai properti publik di header Anda. Jika seharusnya hanya dibaca, mendeklarasikannya sebagai hanya baca dan menimpanya sebagai readwrite dalam lanjutan kelas. Pada dasarnya saya tidak menggunakan variabel sama sekali, hanya properti.

2 / Berikan properti Anda nama variabel non-default, misalnya:


@synthesize property = property_;

Alasan 1: Anda akan menangkap kesalahan yang disebabkan oleh lupa "diri." saat menetapkan properti. Alasan 2: Dari percobaan saya, Leak Analyzer di Instrumen memiliki masalah untuk mendeteksi kebocoran properti dengan nama default.

3 / Jangan pernah menggunakan mempertahankan atau melepaskan langsung pada properti (atau hanya dalam situasi yang sangat luar biasa). Di dealloc Anda, tetapkan saja nihil. Properti retensi dimaksudkan untuk menangani retain / release sendiri. Anda tidak pernah tahu apakah seorang setter tidak, misalnya, menambah atau menghapus pengamat. Anda harus menggunakan variabel secara langsung hanya di dalam setter dan pengambilnya.

Tampilan

1 / Masukkan setiap definisi tampilan ke xib, jika Anda bisa (pengecualian biasanya konten dinamis dan pengaturan layer). Menghemat waktu (lebih mudah daripada menulis kode), mudah diubah dan menjaga kode Anda tetap bersih.

2 / Jangan mencoba mengoptimalkan tampilan dengan mengurangi jumlah tampilan. Jangan membuat UIImageView dalam kode Anda, bukan xib hanya karena Anda ingin menambahkan subview ke dalamnya. Gunakan UIImageView sebagai latar belakang. Kerangka kerja tampilan dapat menangani ratusan tampilan tanpa masalah.

3 / IBOutlet tidak harus selalu dipertahankan (atau kuat). Perhatikan bahwa sebagian besar IBOutlet Anda adalah bagian dari hierarki tampilan Anda dan dengan demikian secara implisit dipertahankan.

4 / Lepaskan semua IBOutlets dalam viewDidUnload

5 / Panggil viewDidUnload dari metode dealloc Anda. Itu tidak secara implisit disebut.

Penyimpanan

1 / Autorelease objek saat Anda membuatnya. Banyak bug disebabkan oleh pemindahan panggilan rilis Anda ke cabang if-else atau setelah pernyataan pengembalian. Pelepasan alih-alih autorelease harus digunakan hanya dalam situasi luar biasa - misalnya ketika Anda menunggu runloop dan Anda tidak ingin objek Anda autoreleased terlalu dini.

2 / Bahkan jika Anda menggunakan Penghitungan Referensi Authomatic, Anda harus memahami dengan sempurna cara kerja metode pelepasan-pelepasan. Menggunakan retain-release secara manual tidak lebih rumit dari ARC, dalam kedua kasus Anda harus memikirkan kebocoran dan mempertahankan-siklus. Pertimbangkan untuk menggunakan retain-release secara manual pada proyek besar atau hierarki objek yang rumit.

Komentar

1 / Jadikan kode Anda didokumentasikan secara otomatis. Setiap nama variabel dan nama metode harus memberi tahu apa yang dilakukannya. Jika kode ditulis dengan benar (Anda perlu banyak latihan dalam hal ini), Anda tidak memerlukan komentar kode apa pun (tidak sama dengan komentar dokumentasi). Algoritma bisa rumit tetapi kode harus selalu sederhana.

2 / Terkadang, Anda perlu komentar. Biasanya untuk menggambarkan perilaku kode yang tidak jelas atau peretasan. Jika Anda merasa harus menulis komentar, pertama-tama cobalah untuk menulis ulang kode menjadi lebih sederhana dan tanpa perlu komentar.

Lekukan

1 / Jangan terlalu meningkatkan indentasi. Sebagian besar kode metode Anda harus diindentasi pada level metode. Blok bersarang (jika, untuk dll.) Mengurangi keterbacaan. Jika Anda memiliki tiga blok bersarang, Anda harus mencoba menempatkan blok dalam ke dalam metode terpisah. Empat atau lebih blok bersarang tidak boleh digunakan. Jika sebagian besar kode metode Anda berada di dalam if, abaikan kondisi if, contoh:


if (self) {
   //... long initialization code ...
}

return self;

if (!self) {
   return nil;
}

//... long initialization code ...

return self;

Memahami kode C, terutama C struct

Perhatikan bahwa Obj-C hanya lapisan OOP ringan di atas bahasa C. Anda harus memahami bagaimana struktur kode dasar dalam pekerjaan C (enum, struct, array, pointer dll). Contoh:


view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height + 20);

sama dengan:


CGRect frame = view.frame;
frame.size.height += 20;
view.frame = frame;

Dan masih banyak lagi

Lindungi dokumen standar pengodean Anda sendiri dan seringlah perbarui. Cobalah belajar dari bug Anda. Pahami mengapa bug dibuat dan cobalah menghindarinya menggunakan standar pengkodean.

Standar pengkodean kami saat ini memiliki sekitar 20 halaman, campuran dari Standar Java Coding, Google Obj-C / C ++ Standar dan tambahan kami sendiri. Dokumentasikan kode Anda, gunakan indentasi standar standar, spasi putih dan garis kosong di tempat yang tepat, dll.

Sulthan
sumber
9

Lebih fungsional .

Objective-C adalah bahasa berorientasi objek, tetapi kerangka kerja Kakao gaya-fungsional sadar, dan dirancang gaya fungsional dalam banyak kasus.

  1. Ada pemisahan sifat berubah-ubah. Gunakan kelas yang tidak berubah sebagai primer, dan objek yang bisa berubah sebagai sekunder. Misalnya, gunakan NSArray terutama, dan gunakan NSMutableArray hanya ketika Anda membutuhkannya.

  2. Ada fungsi murni. Tidak banyak, beli banyak framework API yang didesain seperti fungsi murni. Lihatlah fungsi seperti CGRectMake()atau CGAffineTransformMake(). Jelas bentuk pointer terlihat lebih efisien. Namun argumen tidak langsung dengan pointer tidak dapat menawarkan efek samping bebas. Merancang struktur semaksimal mungkin. Pisahkan benda negara. Gunakan -copyalih-alih -retainsaat memberikan nilai ke objek lain. Karena keadaan bersama dapat memengaruhi mutasi ke nilai di objek lain secara diam-diam. Jadi tidak bisa bebas efek samping. Jika Anda memiliki nilai dari eksternal dari objek, salinlah. Jadi, penting juga merancang keadaan bersama seminimal mungkin.

Namun jangan takut menggunakan fungsi tidak murni juga.

  1. Ada evaluasi malas. Lihat sesuatu seperti -[UIViewController view]properti. Tampilan tidak akan dibuat saat objek dibuat. Ini akan dibuat saat pemanggil membaca viewproperti pada saat pertama. UIImagetidak akan dimuat sampai benar-benar ditarik. Ada banyak implementasi seperti desain ini. Desain semacam ini sangat membantu untuk manajemen sumber daya, tetapi jika Anda tidak tahu konsep evaluasi malas, tidak mudah untuk memahami perilaku mereka.

  2. Ada penutupan. Gunakan blok C sebanyak mungkin. Ini akan sangat menyederhanakan hidup Anda. Tapi baca sekali lagi tentang manajemen blok-memori sebelum menggunakannya.

  3. Ada semi-otomatis GC. NSAutoreleasePool. Gunakan -autoreleaseprimer. Gunakan manual -retain/-releasesekunder saat Anda benar-benar membutuhkannya. (mis: optimasi memori, penghapusan sumber daya eksplisit)

Eonil
sumber
2
As ke 3) Saya akan mengusulkan pendekatan yang berlawanan: Gunakan retain / rilis manual sedapat mungkin! Siapa yang tahu bagaimana kode ini akan digunakan - dan jika itu akan digunakan dalam loop yang ketat dapat meledakkan penggunaan memori Anda secara tidak perlu.
Eiko
@ Eiko Itu hanya Optimasi Prematur , tidak bisa menjadi panduan umum.
Eonil
1
Saya pikir ini lebih merupakan hal desain, terutama ketika mengerjakan kelas model. Saya menganggap memori tumbuh sebagai efek samping, dan bukan itu yang saya ingin sering muncul. Lebih buruk lagi, pengembang lain yang menggunakan kode saya tidak memiliki kesempatan selain untuk membungkus panggilan mahal ke dalam kumpulan autorelease (jika mungkin sama sekali - objek saya mungkin dikirim ke beberapa kode perpustakaan lainnya). Dan masalah-masalah itu sulit didiagnosis kemudian, tetapi murah untuk dihindari sejak awal. Jika Anda menyalin / autorelease objek yang melewati, Anda mungkin hilang jika mereka jauh lebih besar dari yang Anda harapkan. Saya lebih santai dengan kode GUI.
Eiko
@ Eiko Saya setuju autoreleaseakan menyimpan memori lebih lama secara umum, dan manual retain/releasedapat mengurangi konsumsi memori dalam case ini. Namun itu harus menjadi panduan untuk optimasi kasus khusus (bahkan Anda selalu merasa!), Tidak bisa menjadi alasan untuk menggeneralisasi optimasi prematur sebagai praktik . Dan nyatanya, saran Anda tidak berlawanan dengan saya. Saya menyebutkannya sebagai kasus yang sangat dibutuhkan :)
Eonil