هل يقوم NSNumber بإضافة أي بايت إضافية إلى الرقم الذي يحمله؟

StackOverflow https://stackoverflow.com/questions/1149051

سؤال

أنا أعمل مع الهدف - ج وأحتاج إلى إضافة Int's من NSArray إلى NSMutabledata (أعد أستعد لإرسال البيانات عبر اتصال). إذا قمت بلف INT's مع NSNumber ثم قم بإضافتها إلى NSMutabledata، فكيف يمكنني معرفة عدد البايتات الموجودة في NSNumber Int؟ هل سيكون من الممكن استخدام SizeOf () منذ ذلك الحين وفقا لتوثيق Apple، "NSNUMBER هو فئة فرعية من NSValue التي توفر قيمة مثل أي نوع C Scalar (رقمي)."؟

مثال:

NSNumber *numero = [[NSNumber alloc] initWithInt:5];

NSMutableData *data = [[NSMutableData alloc] initWithCapacity:0];

[data appendBytes:numero length:sizeof(numero)];
هل كانت مفيدة؟

المحلول

Numero ليست قيمة رقمية، فهي مؤشر لكائن أعد قيمة رقمية. ما تحاول القيام به لن يعمل، سيكون الحجم دائما يساوي مؤشر (4 منصات 32 بت و 8 مقابل 64 بت)، وسوف يلغي بعض قيمة مؤشر القمامة إلى بياناتك بدلا من الرقم.

حتى لو كنت في محاولة إلغاء الأمر، لا يمكنك الوصول مباشرة إلى دعم البايتات NSNumber ونتوقع أن تعمل. ما يجري هو تفاصيل التنفيذ الداخلي، وقد تختلف من إطلاق سراحه بالإفراج عنه، أو حتى بين تكوينات مختلفة لنفس الإصدار (32 بت VS 64 بت 64 بت، iPhone VS Mac OS X، ARM VS I386 VS PPC). قد يؤدي تعبئة بايت وإرسالها عبر السلك إلى شيء لا يتحمل بشكل صحيح على الجانب الآخر، حتى لو تمكنت من الوصول إلى البيانات الفعلية.

تحتاج حقا إلى التوصل إلى ترميز عدد صحيح يمكنك وضعه في بياناتك ثم حزمة وتفكير NSNUMBERS في ذلك. شيء مثل:

NSNumber *myNumber = ... //(get a value somehow)
int32_t myInteger = [myNumber integerValue]; //Get the integerValue out of the number
int32_t networkInteger = htonl(myInteger); //Convert the integer to network endian
[data appendBytes:&networkInteger sizeof(networkInteger)]; //stuff it into the data

على الجانب الاستقبال، يمكنك إخراج عدد صحيح وإعادة إنشاء NSNumber مع Numberwithinteger: بعد استخدام NTOHL لتحويله إلى تنسيق المضيف الأصلي.

قد تتطلب المزيد من العمل قليلا إذا كنت تحاول إرسال الحد الأدنى من التمثيلات، إلخ.

الخيار الآخر هو استخدام فئة فرعية NSCODER وأخبر NSNUMBER لتشفير نفسه باستخدام المبرمج الخاص بك، لأن ذلك سيكون محايدا منصة، ولكن قد يكون مبالغا فيه على ما تحاول القيام به.

نصائح أخرى

أولا، nsnumber * numero هو "مؤشر إلى نوع NSNumber"، ونوع NSNumber هو كائن موضوعي C. بشكل عام، ما لم يقدر على وجه التحديد في مكان ما في الوثائق، فإن قاعدة الإبهام في البرمجة الموجهة للكائنات هي أن "التفاصيل الداخلية لكيفية تختار كائن تمثيل حالتها الداخلية خاصة بتنفيذ الكائنات، وينبغي معالجتها كأسود صندوق." مرة أخرى، ما لم تقول الوثائق أنه يمكنك القيام بذلك بطريقة أخرى، لا يمكنك افتراض أن NSNumber يستخدم نوعا بدائيا int لتخزين int القيمة التي أعطيتها.

فيما يلي تقريب تقريبي لما يحدث "وراء الكواليس" عندك appendBytes:numero:

typedef struct {
  Class isa;
  double dbl;
  long long ll;
} NSNumber;

NSNumber *numero = malloc(sizeof(NSNumber));
memset(numero, 0, sizeof(NSNumber));
numero->isa = objc_getClass("NSNumber");

void *bytes = malloc(1024);

memcpy(bytes, numero, sizeof(numero)); // sizeof(numero) == sizeof(void *)

هذا يجعل من الواضح أكثر قليلا أن ما كنت نبض NSMutableData هدف data هي أول أربع بايت من أي وقت مضى numero يشير إلى (الذي، لكائن في OBJ-C هو دائما isa, ، فئة الكائنات). أظن أن ما كنت تريد القيام به هو نسخ المؤشر إلى كائن مثيل (قيمة Numero)، وفي هذه الحالة يجب أن تستخدمها &numero. وبعد هذه مشكلة إذا كنت تستخدم GC كما المخزن المؤقت المستخدمة من قبل NSMutableData لا يتم مسح ضوئيا (أي نظام GC لن "رؤية" الكائن واستعادة منه، وهو أمر ضمان كبير لتصريح عشوائي في وقت لاحق.)

من الواضح أنه من الواضح أنه حتى لو وضعت المؤشر إلى مثيل NSNumber كائن من الداخل data, ، هذا المؤشر لديه معنى فقط في سياق العملية التي أنشأتها. يكون المؤشر إلى هذا الكائن أقل معنى إذا قمت بإرسال المؤشر إلى كمبيوتر آخر - يحتوي الكمبيوتر الاستقبال على طريقة (عملية أو تافهة) لقراءة الذاكرة التي يشير المؤشر إليها في جهاز الكمبيوتر المرسل.

نظرا لأنك يبدو أن تواجه مشاكل في هذا الجزء من العملية، اسمحوا لي أن أقدم توصية ستوفر لك ساعات لا تحصى من تصحيح الأخطاء في التنفيذ الصعبة للغاية التي لا بد لها أن تعمل في:

التخلي عن هذه الفكرة بأكملها من محاولة إرسال البيانات الثنائية الخام بين الآلات وترسل فقط معلومات تنسيق ASCII / UTF-8 بينها.

إذا كنت تعتقد أن هذا هو بعض الطريقة التي ستكون بطيئا، أو غير فعالة، فأدعني أوصي بإحضار كل شيء باستخدام إصدار بسيطة ASCII / UTF-8 الإصدار الموافق أولا. ثق بي، تصحيح البيانات الثنائية الخام ليست متعة، والقدرة على فقط NSLog(@"I got: %@", dataString) يستحق وزنه بالذهب عند تصحيح مشاكلك الحتمية. ثم، بمجرد أن تجرب كل شيء، وأنت واثق من أنك لست بحاجة إلى إجراء المزيد من التغييرات على ما تحتاجه إلى تبادله، "منفذ" (لعدم وجود كلمة أفضل) يقوم بتنفيذ إصدار ثنائي فقط إذا، وفقط إذا, ، ينص التنميط مع Shark.App كمنطقة مشكلة. كنقطة مرجعية، في هذه الأيام أستطيع scp ملف بين الآلات وشبه رابط جيجابت مع النقل. scp ربما يجب أن تفعل حوالي خمسة آلاف مرة أكبر من المعالجة لكل بايت لضغط البيانات وتشفيرها من هذا التشريف البسيط أثناء نقل 80 ميجابايت / ثانية. ومع ذلك، على الأجهزة الحديثة، فهذا بالكاد يكفي لزعم مقياس وحدة المعالجة المركزية يعمل في شريط قوائم الخاص بي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top