Bir iOS uygulamasında global sabitler nerede saklanır?


111

İOS uygulamamdaki modellerin çoğu bir web sunucusunu sorguluyor. Sunucunun temel URL'sini depolayan bir yapılandırma dosyasına sahip olmak istiyorum. Şunun gibi görünecek:

// production
// static NSString* const baseUrl = "http://website.com/"

// testing
static NSString* const baseUrl = "http://192.168.0.123/"

Bir satırı veya diğerini yorumlayarak, modellerimin işaret ettiği sunucuyu anında değiştirebilirim. Sorum şu, iOS'ta küresel sabitleri depolamak için en iyi uygulama nedir? Android programlamada, bu yerleşik dizeler kaynak dosyamız var . Herhangi bir Aktivitede (bir UIViewController'ın eşdeğeri ), bu dize sabitlerini şununla alabiliriz:

String string = this.getString(R.string.someConstant);

İOS SDK'nın sabitleri depolamak için benzer bir yeri olup olmadığını merak ediyordum. Değilse, bunu yapmak için Objective-C'de en iyi uygulama nedir?

Yanıtlar:


145

Ayrıca yapabilirsin

#define kBaseURL @"http://192.168.0.123/"

bir "sabitler" başlık dosyasında diyelim constants.h. O zaman yap

#include "constants.h"

bu sabite ihtiyacınız olan her dosyanın en üstünde.

Bu şekilde, aşağıdaki gibi derleyici bayraklarına bağlı olarak sunucular arasında geçiş yapabilirsiniz:

#ifdef DEBUG
    #define kBaseURL @"http://192.168.0.123/"
#else
    #define kBaseURL @"http://myproductionserver.com/"
#endif

"constants.h"Yaklaşımı kullanıyorum, staticdeğişkenleri temel alıyorum #ifdef VIEW_CONSTANTS ... #endif. Bu nedenle, uygulama çapında bir sabitler dosyam var, ancak diğer kod dosyalarımın her biri , sabitler dosyasından #defineönce eklenecek farklı sabit kümelerinden #includeoluşuyor (tüm bu "tanımlanmış ancak kullanılmayan" derleyici uyarılarını durdurur).

2
Bu çözümde karşılaştığım iki sorun var. İlk olarak, kullandığımda #decalare" geçersiz önişleme yönergesi bildirimi " diyen bir derleme hatası aldım . Ben de #definebunun yerine olarak değiştirdim . Diğer sorun sabiti kullanmaktır. static NSString* const fullUrl = [NSString stringWithFormat:@"%@%@", kbaseUrl, @"script.php"]İle başka bir sabit oluşturmak istedim , ancak görünüşe göre bir ifadeyle const oluşturmak yasadışı. " Başlatıcı elemanı sabit değil " hatasını alıyorum .
JoJo

1
@Cyrille Android uygulaması gerçekten ilginç, iOS'ta hayal bile edemeyeceğiniz bazı olasılıklar var!
Cevabınız

8
Mümkünse #define yerine const'ı tercih edin - daha iyi derleme zamanı denetimi elde edersiniz ve hata ayıklama daha iyi çalışır.
occulus

2
@AnsonYao genellikle bu benim başıma geldiğinde # #define kBaseURL @"http://192.168.0.123/";
define'dan

168

Pekala, beyanı ilişkili olduğu arayüzler için yerel olarak istiyorsunuz - uygulama çapında sabitler dosyası iyi bir şey değil.

Ayrıca, extern NSString* consta kullanmak yerine basitçe bir sembol bildirmek tercih edilir #define:


SomeFile.h

extern NSString* const MONAppsBaseUrl;

SomeFile.m

#import "SomeFile.h"

#ifdef DEBUG
NSString* const MONAppsBaseUrl = @"http://192.168.0.123/";
#else
NSString* const MONAppsBaseUrl = @"http://website.com/";
#endif

C ++ uyumlu Extern bildiriminin çıkarılmasının yanı sıra, genellikle Apple'ın Obj-C çerçevelerinde kullanıldığını göreceğiniz şey budur.

Sabitin yalnızca bir dosya veya işlev tarafından görülmesi gerekiyorsa, o zaman static NSString* const baseUrlsizin *.miçin iyidir.


26
Kabul edilen yanıtın neden #define - const'ı savunmak için 40 oy aldığından emin değilim.
occulus

1
Kesinlikle const NSString #define'dan daha iyidir, bu kabul edilen cevap olmalıdır. #define, tanımlanan değer her kullanıldığında yeni bir dize oluşturur.
jbat100

1
@ jbat100 Yeni bir dize oluşturduğunu sanmıyorum. Derleyicinin, kodunuzun aynı statik dizeyi 300.000 kez oluşturup oluşturmadığını algıladığını ve yalnızca bir kez oluşturacağını düşünüyorum. @"foo"ile aynı değil [[NSString alloc] initWithCString:"foo"].
Abhi Beckert

@AbhiBeckert jbat'ın yapmaya çalıştığı nokta #define, kullanıldığında sabitinizin kopyaları ile sonuçlanmasının mümkün olmasıdır (yani işaretçi eşitliği başarısız olabilir) - NSString değişmez ifadesi çalıştırıldığında geçici bir ifade oluşturmaz.
justin

1
#Define'ın kötü bir fikir olduğuna katılıyorum, sadece birden fazla nesne oluşturacağına dair yaptığı hatayı düzeltmek istedim. Ayrıca, sabitler için bile işaretçi eşitliğine güvenilemez. NSUserDefaults veya başka bir şeyden yüklenebilir. Her zaman isEqual: kullanın.
Abhi Beckert

39

Global sabitleri tanımlama şeklim:


AppConstants.h

extern NSString* const kAppBaseURL;

AppConstants.m

#import "AppConstants.h"

#ifdef DEBUG
NSString* const kAppBaseURL = @"http://192.168.0.123/";
#else
NSString* const kAppBaseURL = @"http://website.com/";
#endif

Ardından {$ APP} -Prefix.pch dosyanızda:

#ifdef __OBJC__
  #import <UIKit/UIKit.h>
  #import <Foundation/Foundation.h>
  #import "AppConstants.h"
#endif

Herhangi bir sorunla karşılaşırsanız, önce Ön Derleme Önek Başlığı seçeneğinin HAYIR olarak ayarlandığından emin olun.


5

Ayrıca, dize sabitlerini şu şekilde birleştirebilirsiniz:

  #define kBaseURL @"http://myServer.com"
  #define kFullURL kBaseURL @"/api/request"

4

Bunu yapmanın başka bir yolunun çok daha basit olduğunu düşünüyorum ve bunu .pch önek dosyasında olduğu gibi TÜM dosyalara değil, ihtiyacınız olan dosyalara dahil edeceksiniz:

#ifndef Constants_h
#define Constants_h

//Some constants
static int const ZERO = 0;
static int const ONE = 1;
static int const TWO = 2;

#endif /* Constants_h */

Bundan sonra, bu başlık dosyasını istediğiniz başlık dosyasına dahil edersiniz. Bunu, dahil edilmesini istediğiniz belirli sınıfın başlık dosyasına dahil edersiniz:

#include "Constants.h"

Testlerimde, statik sabitler hata ayıklayıcıda (Xcode lldb) kullanılamaz. "error: use of undeclared identifier .."
jk7

3
  1. YOURPROJECT-Prefix.pch dosyasında global sabiti tanımlıyorum.
  2. #define BASEURl @"http://myWebService.appspot.com/xyz/xx"
  3. BASEURL kullanmak için projenin herhangi bir yerinde:

    NSString *LOGIN_URL= [BASEURl stringByAppendingString:@"/users/login"];

Güncellendi: Xcode 6'da projenizde oluşturulan varsayılan .pch dosyasını bulamazsınız. Bu yüzden lütfen kullan projenize .pch dosyası eklemek için Xcode 6'daki PCH Dosyasını .

Güncellemeler: SWIFT için

  1. Yeni Swift dosyası oluşturun [sınıfsız boş] [AppGlobalMemebers] deyin
  2. & Üyeyi hemen bildir / tanımla

    Misal:

    var STATUS_BAR_GREEN : UIColor  = UIColor(red: 106/255.0, green: 161/255.0, blue: 7/255.0, alpha: 1)  //
    1. Appdelegate veya Singleton sınıfı veya herhangi bir sınıf dosyasında uygulama global üyesini tanımlamak istiyorsanız, belirtilen üyeyi sınıf tanımının üzerinde bildirin

2

Küresel bildirimler ilginç ama benim için kodlama yöntemimi derinden değiştiren şey, küresel sınıf örneklerine sahip olmaktı. Onunla nasıl çalışılacağını gerçekten anlamam birkaç günümü aldı, bu yüzden burada hızlıca özetledim

Temel veri erişimini veya bazı ticaret mantıklarını yeniden gruplandırmak için küresel sınıf örnekleri (gerekirse proje başına 1 veya 2) kullanıyorum.

Örneğin, tüm restoran masalarını işleyen merkezi bir nesneye sahip olmak istiyorsanız, başlangıçta nesnenizi oluşturursunuz ve işte budur. Bu nesne, veritabanı erişimlerini idare edebilir VEYA kaydetmeniz gerekmiyorsa, hafızada işleyebilir. Merkezileştirildi, sadece kullanışlı arayüzler gösteriliyor ...!

Bu harika bir yardım, nesne odaklı ve tüm eşyalarınızı aynı yere götürmenin iyi bir yolu

Birkaç satır kod:

@interface RestaurantManager : NSObject
    +(id) sharedInstance;
    -(void)registerForTable:(NSNumber *)tableId;
@end 

ve nesne uygulaması:

@implementation RestaurantManager

+ (id) sharedInstance {
    static dispatch_once_t onceQueue;

    dispatch_once(&onceQueue, ^{
        sharedInstance = [[self alloc] init];
        NSLog(@"*** Shared instance initialisation ***");
    });
    return sharedInstance;
}

-(void)registerForTable:(NSNumber *)tableId {
}
@end

kullanmak gerçekten çok basit:

[[RestaurantManager sharedInstance] registerForTable: [NsNumber numberWithInt: 10]]


3
Bu tasarım modelinin teknik adı Singleton'dur. en.wikipedia.org/wiki/Singleton_pattern
Basil Bourque

Statik verileri (Statik Sınıfları Değil) sharedmanager'da tutmak iyi bir fikir değildir.
Önder OZCAN

1

Kabul edilen cevabın 2 zayıf yönü var. Birincisi, kullanımı #definedaha zor olan diğerlerinin de işaret ettiği gibi, bunun yerine extern NSString* const kBaseUrlyapıyı kullanın . İkincisi, sabitler için tek bir dosya tanımlar. IMO, bu yanlıştır çünkü sınıfların çoğunun bu sabitlere erişmesi gerekmez veya hepsine erişmek için tüm sabitler orada bildirilirse dosya şişirilebilir. Sabitleri 3 farklı katmanda modülerleştirmek daha iyi bir çözüm olabilir:

  1. Sistem katmanı: SystemConstants.hveya AppConstants.h sistemdeki herhangi bir sınıf tarafından erişilebilen genel kapsamdaki sabitleri açıklayan. Burada yalnızca ilişkili olmayan farklı sınıflardan erişilmesi gereken sabitleri bildirin.

  2. Modül / Alt sistem katmanı:, ModuleNameConstants.hbir modül / alt sistem içinde bir dizi ilgili sınıf için tipik olan bir dizi sabiti açıklar.

  3. Sınıf katmanı: Sabitler sınıfta bulunur ve yalnızca kendisi tarafından kullanılır.

Yalnızca 1,2 soru ile ilgilidir.


0

Daha önce kullandığım bir yaklaşım, bir dosya oluşturmak Settings.plistve NSUserDefaultskullanarak başlattıktan sonra onu yüklemek registerDefaults:. Daha sonra içeriğine aşağıdakilerle erişebilirsiniz:

// Assuming you've defined some constant kMySettingKey.
[[NSUserDefaults standardUserDefaults] objectForKey:kMySettingKey];

Herhangi bir Android geliştirme yapmamış olsam da, bu, anlattığınız dizeler kaynak dosyasına benziyor gibi geliyor. Tek dezavantajı, ön işlemciyi ayarlar arasında geçiş yapmak için kullanamamanızdır (örn. DEBUGKipte). Sanırım farklı bir dosya yükleyebilirsiniz.

NSUserDefaults dokümantasyon.


9
İstediğiniz tek şey sabit olduğunda bu biraz fazla değil mi ve ayrıca neden onu potansiyel olarak değiştirilebilir bir dosyaya koyasınız? (Özellikle ana sunucunuzun IP'si kadar kritik bir şey olduğunda, uygulamanız olmadan çalışmazsa).
Cyrille

Bu yaklaşım çeşitli faydalar, ayarlarınız doğru biçimde (döndürülen o en önemli varlık olduğunu hissetmek NSString, NSNumbervs.). Elbette, #defineaynı şeyi yapmak için e'lerinizi sarabilirsiniz , ancak o zaman düzenlemek o kadar kolay olmaz. plistDüzenleme arayüzü de güzel. :) Oraya şifreleme anahtarları gibi süper gizli şeyler koymaman gerektiğini kabul etsem de, olmamaları gereken yerlerde dolaşan kullanıcılar için fazla endişelenmiyorum - uygulamayı bozarlarsa, bu onların kendi hatası .
Chris Doble

1
Elbette, argümanlarınıza katılıyorum. Sizin de söylediğiniz gibi, e-postalarımı #definedoğru türü döndürmek için sarıyorum, ancak bu tür sabit dosyalarını düzenlemeye alışkınım, çünkü Pascal Eski bir 286'da :) Ve her yerde dolaşan kullanıcıya gelince, ben de aynı fikirdeyim, bu onların hatası. Bu sadece bir zevk meselesi, gerçekten.
Cyrille

@Chris Doble: Hayır, Android'deki kaynak dosyaları NSUserDefaults ile aynı değildir. SharedPreferences ve Preferences, NSUserDefaults'un Android eşdeğeridir (ancak NSUserDefaults'dan daha güçlüdür). Android'deki kaynakların amacı, yerelleştirme ve diğer birçok kullanım için mantığı içerikten ayırmaktır.
mrd

0

Bir numara için aşağıdaki gibi kullanabilirsiniz

#define MAX_HEIGHT 12.5

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.