objective c - الثوابت في Objective-C




cocoa constants (9)

أستخدم فئة singleton ، حتى أتمكن من سخرية الصف وتغيير الثوابت إذا لزم الأمر للاختبار. فئة الثوابت تبدو كالتالي:

#import <Foundation/Foundation.h>

@interface iCode_Framework : NSObject

@property (readonly, nonatomic) unsigned int iBufCapacity;
@property (readonly, nonatomic) unsigned int iPort;
@property (readonly, nonatomic) NSString * urlStr;

@end

#import "iCode_Framework.h"

static iCode_Framework * instance;

@implementation iCode_Framework

@dynamic iBufCapacity;
@dynamic iPort;
@dynamic urlStr;

- (unsigned int)iBufCapacity
{
    return 1024u;
};

- (unsigned int)iPort
{
    return 1978u;
};

- (NSString *)urlStr
{
    return @"localhost";
};

+ (void)initialize
{
    if (!instance) {
        instance = [[super allocWithZone:NULL] init];
    }
}

+ (id)allocWithZone:(NSZone * const)notUsed
{
    return instance;
}

@end

ويستخدم مثل هذا (لاحظ استخدام الاختزال للثوابت c - يحفظ الكتابة [[Constants alloc] init] كل مرة:

#import "iCode_FrameworkTests.h"
#import "iCode_Framework.h"

static iCode_Framework * c; // Shorthand

@implementation iCode_FrameworkTests

+ (void)initialize
{
    c  = [[iCode_Framework alloc] init]; // Used like normal class; easy to mock!
}

- (void)testSingleton
{
    STAssertNotNil(c, nil);
    STAssertEqualObjects(c, [iCode_Framework alloc], nil);
    STAssertEquals(c.iBufCapacity, 1024u, nil);
}

@end

أقوم بتطوير تطبيق Cocoa ، وأنا أستخدم نظام NSString المستمر كطريقة لتخزين الأسماء الرئيسية لتفضيلاتي.

أتفهم أن هذه فكرة جيدة لأنها تسمح بتغيير المفاتيح بسهولة إذا لزم الأمر. بالإضافة إلى ذلك ، فكلها "فصل بياناتك عن فكرة المنطق".

على أي حال ، هل هناك طريقة جيدة لجعل هذه الثوابت محددة مرة واحدة للتطبيق كله؟ أنا متأكد من أن هناك طريقة سهلة وذكية ، لكن فصولي الآن فقط تعيد تعريف ما يستخدمونه.


أسهل طريقة:

// Prefs.h
#define PREFS_MY_CONSTANT @"prefs_my_constant"

طريقة افضل:

// Prefs.h
extern NSString * const PREFS_MY_CONSTANT;

// Prefs.m
NSString * const PREFS_MY_CONSTANT = @"prefs_my_constant";

فائدة واحدة من الثانية هي أن تغيير قيمة ثابت لا يتسبب في إعادة بناء البرنامج بأكمله.


أنا نفسي لدي رأس مخصص لإعلان NSStrings ثابت يستخدم لتفضيلات مثل ذلك:

extern NSString * const PPRememberMusicList;
extern NSString * const PPLoadMusicAtListLoad;
extern NSString * const PPAfterPlayingMusic;
extern NSString * const PPGotoStartupAfterPlaying;

ثم التصريح عنها في ملف .m المصاحب:

NSString * const PPRememberMusicList = @"Remember Music List";
NSString * const PPLoadMusicAtListLoad = @"Load music when loading list";
NSString * const PPAfterPlayingMusic = @"After playing music";
NSString * const PPGotoStartupAfterPlaying = @"Go to startup pos. after playing";

وقد خدم هذا النهج بشكل جيد.

تحرير: لاحظ أن هذا يعمل بشكل أفضل إذا تم استخدام السلاسل في ملفات متعددة. إذا كان هناك ملف واحد فقط يستخدمه ، فيمكنك فقط القيام #define kNSStringConstant @"Constant NSString" في الملف .m الذي يستخدم السلسلة.


إذا كنت تحب مساحة الاسم ثابتة ، فيمكنك الاستفادة من البنية ، الجمعة Q & A 2011-08-19: الثوابت والدالات التي لها اسم

// in the header
extern const struct MANotifyingArrayNotificationsStruct
{
    NSString *didAddObject;
    NSString *didChangeObject;
    NSString *didRemoveObject;
} MANotifyingArrayNotifications;

// in the implementation
const struct MANotifyingArrayNotificationsStruct MANotifyingArrayNotifications = {
    .didAddObject = @"didAddObject",
    .didChangeObject = @"didChangeObject",
    .didRemoveObject = @"didRemoveObject"
};

الإجابة المقبولة (والصحيحة) تقول "يمكنك تضمين هذا الملف [Constants.h] ... في رأس pre-compiled للمشروع."

كمبتدئ ، واجهت صعوبة في القيام بذلك دون مزيد من التوضيح - إليك الطريقة التالية: في ملف YourAppNameHere-Prefix.pch (هذا هو الاسم الافتراضي للرأس المحول برمجيًا في Xcode) ، قم باستيراد Constants.h الخاص بك داخل كتلة #ifdef __OBJC__ .

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

لاحظ أيضاً أن ملفات Constants.h و Constants.m يجب أن تحتوي على أي شيء آخر فيها باستثناء ما هو موضح في الإجابة المقبولة. (لا توجد واجهة أو تنفيذ).


تعديل بسيط لاقتراح @ krizz ، بحيث يعمل بشكل صحيح إذا كان ملف رأس الثوابت سيتم إدراجه في PCH ، وهو أمر طبيعي إلى حد ما. نظرًا لأن الأصل يتم استيراده إلى PCH ، فلن .m الملف .m وبالتالي لا تحصل على أي رموز ويكون الرابط غير سعيد.

ومع ذلك ، يسمح التعديل التالي للعمل. انها معقدة بعض الشيء ، لكنها تعمل.

ستحتاج إلى 3 ملفات ، ملف .h الذي يحتوي على التعريفات الثابتة ، الملف .h والملف .h ، .m ConstantList.h ، Constants.h و Constants.m ، على التوالي. محتويات Constants.h ببساطة:

// Constants.h
#define STR_CONST(name, value) extern NSString* const name
#include "ConstantList.h"

وملف Constants.m يبدو مثل:

// Constants.m
#ifdef STR_CONST
    #undef STR_CONST
#endif
#define STR_CONST(name, value) NSString* const name = @ value
#include "ConstantList.h"

وأخيراً ، يحتوي الملف ConstantList.h على التصريحات الفعلية فيه وهذا كل شيء:

// ConstantList.h
STR_CONST(kMyConstant, "Value");
…

زوجان من الأشياء ملاحظة:

  1. اضطررت إلى إعادة تعريف الماكرو في الملف #undef بعد #undef جي ماكرو لاستخدامه.

  2. كما اضطررت إلى استخدام #include بدلاً من #import لهذا للعمل بشكل صحيح وتجنب المحول البرمجي رؤية القيم precompiled مسبقًا.

  3. سيتطلب ذلك إعادة تجميع PCH (وربما المشروع بأكمله) كلما تم تغيير أي قيم ، وهذا ليس هو الحال إذا كانت منفصلة (ومكررة) كالمعتاد.

نأمل أن يكون مفيدا لشخص ما.


كما قال أبيزر ، يمكنك وضعها في ملف PCH. وهناك طريقة أخرى غير قذرة للغاية تتمثل في جعل ملف التضمين لكل مفاتيحك ثم تضمين ذلك في الملف الذي تستخدم فيه المفاتيح أو تضمينه في PCH. معهم في ملف التضمين الخاص بهم ، على الأقل يمنحك مكان واحد للبحث عن وتعريف كل هذه الثوابت.


هناك أيضا شيء واحد أن أذكر. إذا كنت بحاجة إلى ثابت غير عالمي ، فيجب عليك استخدام كلمة رئيسية static .

مثال

// In your *.m file
static NSString * const kNSStringConst = @"const value";

وبسبب الكلمة الأساسية static ، فإن هذا const غير مرئي خارج الملف.

تصحيح بسيط بواسطة QuinnTaylor : تظهر المتغيرات الثابتة داخل وحدة تجميع . عادة ، هذا ملف .m مفرد (كما هو موضح في هذا المثال) ، ولكن يمكن أن يعضك إذا قمت بالإعلان عنه في عنوان تم تضمينه في مكان آخر ، حيث ستحصل على أخطاء رابط بعد التحويل البرمجي


// Prefs.h
extern NSString * const RAHUL;

// Prefs.m
NSString * const RAHUL = @"rahul";




constants