Object_getInstanceVariable يعمل مع Float ، int ، Bool ، ولكن ليس للمضاعفة؟
-
10-07-2019 - |
سؤال
لدي object_getInstanceVariable
للعمل كما هنا ومع ذلك ، يبدو أنه يعمل فقط من أجل العوامات والملحوم و ints لا تتضاعف. أظن أنني أفعل شيئًا خاطئًا ولكني كنت أذهب في دوائر مع هذا.
float myFloatValue;
float someFloat = 2.123f;
object_getInstanceVariable(self, "someFloat", (void*)&myFloatValue);
الأعمال ، و myfloatvalue = 2.123
لكن عندما أحاول
double myDoubleValue;
double someDouble = 2.123f;
object_getInstanceVariable(self, "someDouble", (void*)&myDoubleValue);
انا حصلت myDoubleValue = 0
. إذا حاولت ضبط myDoubleValue
قبل الوظيفة على سبيل المثال. double myDoubleValue = 1.2f
, ، لا تتغير القيمة عندما أقرأها بعد object_getInstanceVariable
مكالمة. ضبط myIntValue
لبعض القيمة الأخرى قبل getinstancevar
وظيفة أعلاه إرجاع 2 كما ينبغي ، أي. تم تغييره.
ثم حاولت
Ivar tmpIvar = object_getInstanceVariable(self, "someDouble", (void*)&myDoubleValue);
إذا فعلت ivar_getName(tmpIvar)
أحصل على "يومًا ما" ، لكن myDoubuleValue = 0
ساكن! ثم أحاول ivar_getTypeEncoding(tmpIvar)
وأحصل على "D" كما ينبغي.
لتلخيص ، إذا typeEncoding = float
, إنه يعمل ، إذا كان مزدوجًا ، فسيتم تعيين النتيجة ولكنه يقرأ بشكل صحيح المتغير وقيمة الإرجاع (IVAR) صحيحة أيضًا.
يجب أن أفعل شيئًا أساسيًا لا أستطيع رؤيته ، لذا أقدر إذا تمكن شخص ما من الإشارة إليه.
المحلول
object_getInstanceVariable
هي وظيفة صغيرة مشوشة. إنها موثق أن المعلمة الأخيرة هي أ void **
المعلمة - أي أنك تمر بعنوان أ void *
متغير واحصل على مؤشر إلى متغير المثيل - ولكن يتم تنفيذه كما لو كان void *
المعلمة - أي أنك تمرر عنوان المتغير الذي تريد الاحتفاظ بنسخة من متغير المثيل. المشكلة هي أن التنفيذ يتجاهل حجم متغير المثيل ويقوم فقط بنسخة مؤشر. لذلك أي شيء بنفس حجم المؤشر سيعمل بشكل مثالي. إذا كنت تعمل على بنية 32 بت ، فسيتم نسخ 32 بت فقط. (يجب أن تشهد نفس السلوك مع long long
متغير مثيل كذلك.)
الحل هو استخدام واجهة برمجة التطبيقات الأولية ، ترميز القيمة الرئيسية, ، استخدام -valueForKey:
.
الحل الآخر: إذا أردت كتابة نسخة ثابتة ، قل كفئة لـ NSObject ، فسيبدو شيء من هذا القبيل:
@implementation NSObject (InstanceVariableForKey)
- (void *)instanceVariableForKey:(NSString *)aKey {
if (aKey) {
Ivar ivar = object_getInstanceVariable(self, [aKey UTF8String], NULL);
if (ivar) {
return (void *)((char *)self + ivar_getOffset(ivar));
}
}
return NULL;
}
@end
ثم يبدو رمزك هكذا:
double myDoubleValue = *(double *)[self instanceVariableForKey:@"someDouble"];
نصائح أخرى
ماذا عن استخدام valueforkey:؟
NSNumber * value = [self valueForKey:[NSString stringWithUTF8String:ivar_getName(tmpIvar)]];
NSLog(@"Double value: %f", [value doubleValue];
ملاحظة: هذا يتطلب منك أن يكون لديك طريقة "SomeFloat". إذا كنت ترغب في استخدام setValue: forkey: ، ستحتاج أيضًا إلى "metsomefloat:" الطريقة. يتم تنفيذ ذلك بسهولة عن طريق إعلان IVAR باعتباره property وتوليفه.