سؤال

أحد يعرف لماذا هذا الجذر View Controller's viewDidLoad يتم استدعاؤه مرتين عند الإطلاق؟إنه يقودني إلى الجنون!

إليك تتبع المكدس من المرة الأولى حتى viewDidLoad:

#0  0x0000276a in -[RootViewController viewDidLoad] at RootViewController.m:71
#1  0x3097548f in -[UIViewController view]
#2  0x00002734 in -[RootViewController initWithCoder:] at RootViewController.m:39
#3  0x30ab5ce4 in -[UIClassSwapper initWithCoder:]
#4  0x30514636 in _decodeObjectBinary
#5  0x30514035 in _decodeObject
#6  0x30ab5a1d in -[UIRuntimeConnection initWithCoder:]
#7  0x30514636 in _decodeObjectBinary
#8  0x30515f27 in -[NSKeyedUnarchiver _decodeArrayOfObjectsForKey:]
#9  0x305163b0 in -[NSArray(NSArray) initWithCoder:]
#10 0x30514636 in _decodeObjectBinary
#11 0x30514035 in _decodeObject
#12 0x30ab4dde in -[UINib instantiateWithOptions:owner:loadingResourcesFromBundle:]
#13 0x30ab6eb3 in -[NSBundle(NSBundleAdditions) loadNibNamed:owner:options:]
#14 0x308f85f1 in -[UIApplication _loadMainNibFile]
#15 0x30901a15 in -[UIApplication _runWithURL:sourceBundleID:]
#16 0x308fef33 in -[UIApplication handleEvent:withNewEvent:]
#17 0x308fad82 in -[UIApplication sendEvent:]
#18 0x309013e1 in _UIApplicationHandleEvent
#19 0x32046375 in PurpleEventCallback
#20 0x30245560 in CFRunLoopRunSpecific
#21 0x30244628 in CFRunLoopRunInMode
#22 0x308f930d in -[UIApplication _run]
#23 0x309021ee in UIApplicationMain
#24 0x000022e4 in main at main.m:14

والمرة الثانية:

#0  0x0000276a in -[RootViewController viewDidLoad] at RootViewController.m:71
#1  0x30ab50cd in -[UINib instantiateWithOptions:owner:loadingResourcesFromBundle:]
#2  0x30ab6eb3 in -[NSBundle(NSBundleAdditions) loadNibNamed:owner:options:]
#3  0x308f85f1 in -[UIApplication _loadMainNibFile]
#4  0x30901a15 in -[UIApplication _runWithURL:sourceBundleID:]
#5  0x308fef33 in -[UIApplication handleEvent:withNewEvent:]
#6  0x308fad82 in -[UIApplication sendEvent:]
#7  0x309013e1 in _UIApplicationHandleEvent
#8  0x32046375 in PurpleEventCallback
#9  0x30245560 in CFRunLoopRunSpecific
#10 0x30244628 in CFRunLoopRunInMode
#11 0x308f930d in -[UIApplication _run]
#12 0x309021ee in UIApplicationMain
#13 0x000022e4 in main at main.m:14
هل كانت مفيدة؟

المحلول

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

لالتطبيق بسيطة مع بنك الاستثمار القومي واحد فقط، وهذا لا ينبغي أن يحدث. ولكن في التطبيق أكثر تعقيدا التي يمكن تحميل وتفريغ التحكم رأي، وهذا يحدث في كل وقت.

نصائح أخرى

وكان هذا نفس القضية عندما كان بلدي التطبيق إطلاق أول. ما وجدته هو أنه في ملف MainWindow.xib بلدي، وكنت وضع كل من بلدي التطبيقات المندوب منفذ viewController، ومنفذ rootViewController نافذتي لبلدي تحكم عرض الجذر. عند إنشاء طريقة عرض استنادا ملف المشروع في كسكودي، didFinishLaunchingWithOptions المتعلق بتفويض تطبيقك سيتم ملؤها سابقا:

self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;

وأعتقد أن ايفار self.viewController يتم إنشاء مثيل من قبل MainWindow.xib يحصل على استدعاء didFinishLaunchingWithOptions. ثم رمز قبل بالسكان فوق يحدد rootViewController نافذة ل. إذا كان الأمر كذلك، جنبا إلى جنب، يمكنك تحديد منفذ rootViewController لنافذة في ملف MainWindow.xib الخاص بك، والواقع أن تنشأ تحكم عرض الجذر مرتين، وأضاف كما تحكم عرض جذر نافذة على مرتين.

وفعلت بعض التصحيح وهنا ما وجدته حول ترتيب ViewController التحميل:

initWithNibName:bundle:     self = <original instance>, retainedOutlet = 0x0  
loadView >>>                self = <original instance>, retainedOutlet = 0x0  
      initWithCoder:        self = <coder instance>,    retainedOutlet = 0x0  
      initWithCoder:        self = <coder instance>,    retainedOutlet = 0x0  
      setView:              self = <original instance>, retainedOutlet = 0x0  
      setRetainedOutlet:    self = <original instance>, retainedOutlet = 0x1613c40  
      viewDidLoad           self = <coder instance>,    retainedOutlet = 0x0  
      awakeFromNib          self = <coder instance>,    retainedOutlet = 0x0  
loadView <<<  
viewDidLoad                 self = <original instance>, retainedOutlet = 0x1613c40  
viewWillAppear:             self = <original instance>, retainedOutlet = 0x1613c40  
dealloc                     self = <coder instance>,    retainedOutlet = 0x0
viewDidAppear:              self = <original instance>, retainedOutlet = 0x1613c40

وخلال طريقة loadView، ويسمى initWithCoder: ويتم إنشاء نسخة جديدة من viewController. هذا هو ما يتم تمريرها إلى عدد قليل من الطرق (مثل viewDidLoad). يتم تدمير النسخة في وقت لاحق في مكالمة dealloc. والخبر السار هو أنه في هذه النسخة، احتفظ لم يتم تكوين المنافذ، بحيث يمكنك استخدام هذا بمثابة اختبار لمعرفة ما اذا كان عليك تهيئة المتغيرات، استدعاء الأساليب الأخرى، والأهم من ذلك، إذا كان يجب إطلاق سراح وتدمير الكائنات أثناء dealloc.

والوجبات الجاهزة رئيسية هي: سوف viewController الحقيقي لها خصائص IBOutlet المحتفظ بها تكوين. إذا كنت في طريقة متجاوزة لها أن تزداد دعا عدة مرات، والتحقق من مجرد واحدة من الخصائص الخاصة بك IBOutlet الاحتفاظ بها لNULL. إذا NULL أنها، ثم العودة فورا.

وأي شخص حصل على أي أدلة لماذا هذا يحدث بهذه الطريقة؟

والآثار الجانبية لهذا: لا يمكنك استخدام awakeFromNib موثوق

.

وأنت لا يمكن أن نفترض سوف يطلق viewDidLoad مرة واحدة فقط. إذا كنت تهيئة الأشياء وتريد ضمان قيام التهيئة إما في طريقة الحرف الأول أو إذا كنت تقوم بتحميل ملف من بنك الاستثمار القومي من أسلوب awakeFromNib.

وكان لي مشكلة مماثلة، وكان نتيجة لإعادة تسمية ملفي XIB والطبقة ViewController لها (مالك ملف). لا تفعل ذلك - كما حصل فعلا وجهات النظر والمندوبين misdefined داخل XML وكان غير قابلة للاسترداد. وفي الوقت نفسه، كان إشارة إلى حمولة VC الأصلي الذي كان من المفترض أن يكون لي VC الجديد. وأعتقد أن سبب الوالدين لإعادة نفسها ثم VC كنت حاولت حقا أن الاحتجاج. في الأساس، وأنا خلقت العودية غير مباشرة للVC التي لديها إدخالات viewDidLoad X2 في بلدي أثر.

وأنا لا أعتقد أن هناك أي سبب وجيه لviewDidLoad X2 كما هو نشأة ويمكن استدعاء التهيئة أخرى مع افتراض الخطأ شروط مسبقة. في كل مرة رأيت viewDidLoad X2، كان خطأ ترميز من جهتي - في كثير من الأحيان عندما كنت إعادة بيع ديون وتتحرك الطبقات VC حول

.

إذا كان هناك سبب وجيه لأكثر من التركيز على الدعوة viewDidLoad، يرجى شخص (أبل ديف هل أنت الاستماع) شرح ذلك بالتفصيل الفني - لقد كنت تبحث عن هذا الجواب لعدة أشهر الآن

لقد واجهت هذه المشكلة ولكن تمكنت من حلها.

حل:

إعادة تسمية فئة وحدة تحكم العرض التي يتم تحميلها مرتين.

تفاصيل:

أعد تسميته واجعل الاسم الجديد شيئًا جديدًا تمامًا. إعادة تسمية الملف لا يوقف مشكلة التحميل مرتين.قد يكون إنشاء مشروع جديد (كما اقترحه الآخرون) أمرًا مبالغًا فيه، على الأقل جرب الحلول الأبسط أولاً!أعد تسمية فئة الوجهة VC.

تَلمِيح:إذا أدت إعادة تسمية الفصل إلى حل مشكلتك، فمن الواضح أنه يتعين عليك تحديث جميع مراجعك إلى هذا الفصل.يمكنك تسريع ذلك باستخدام Command+Shift+F للبحث على مستوى المشروع.

وأنا واجهت نفس المشكلة كما كنت إعادة تصميم ViewController من الصفر للتخلص من ملف XIB وجعل الطبقة قابلة لإعادة الاستخدام. كان هذا المثال ViewController الثاني الذي سيحصلون على رسالة viewDidLoad تليها رسالة dealloc.

وتبين لي أن هذا هو نتيجة للطريقة loadView لم يتم تعريف في ViewController. وloadView الافتراضي دعا awakeFromNib، مع الخاصية nibName لتعيين اسم الفئة. على الرغم من أنني قد أزالت الملف XIB من المشروع، كان لا يزال في دليل التطبيق على جهاز محاكاة.

وذلك على الرغم من أنك يمكن أن مجرد إعادة المحتويات والإعدادات من جهاز محاكاة للتخلص من viewDidLoad الثانية، قد يكون طريقة أفضل للتو إعادة تعريف loadView مثل هذا:

- (void)loadView {
    self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease];
    self.view.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; 
}

فمن المنطقي إذا كنت تنظر في وثائق للخاصية عرض UIViewController's:

<اقتباس فقرة>   

إذا كنت الوصول إلى هذه الخاصية ولها   القيمة هي معدومة في الوقت الراهن، وجهة نظر   تحكم تلقائيا المكالمات   بإرجاع طريقة loadView و   أدى عرض. وloadView الافتراضي   محاولات طريقة لتحميل وجهة نظر من   ملف بنك الاستثمار القومي المرتبطة العرض   تحكم (إن وجدت). إذا وجهة نظركم   لايوجد تحكم أسوشيتد   ملف بنك الاستثمار القومي، يجب تجاوز   طريقة loadView واستخدامها لخلق   العرض الجذري وجميع subviews لها.

في حالتي، وأنا لم تلاحظ أنني عينت في الواقع rootViewController مرتين في:

وapplication:didFinishLaunchingWithOptions: وapplicationDidBecomeActive:

فقط للإضافة إلى ذلك، إذا كنت تستخدم وظيفة النظام، مثل TouchID، إذن applicationWillResignActive في AppDelegate الخاص بك، سيتم استدعاؤه وإذا قلت ذلك، سيتم إعادة تعيين وحدات التحكم إلى وحدة التحكم الجذر الآمنة، ثم سيتم إعادة استدعائك، و أداءSegueWithIdentifier(self.MAIN_SEGUE ,sender:الذات) لن تطلق النار!

حدث هذا لي عندما قمت بدمج مشروع من القصة المصورة بالطريقة القديمة باستخدام xibs لبناء طرق العرض.كان السبب الرئيسي للعودة هو حقيقة أنني لم أتمكن من وضع عرض مشروط بشكل صحيح.الطريقة التي أفعل بها ذلك عادةً هي من خلال وجود طريقة تفويض من UIButton لإنشاء مثيل لوحدة تحكم عرض معينة، وتعيين بعض خصائصها (الخاصية الأكثر استيرادًا هي المفوض حتى أتمكن من استبعاد وحدة تحكم العرض المشروطة مرة أخرى) ثم تقديمها ذلك بطريقة مشروطة.في طريقة القصة المصورة الجديدة، من المفترض أن يتم ذلك من خلال جزء.لا يمكن تخصيص عملية النقل إلا عن طريق إنشاء فئة مخصصة تعمل على توسيع فئة UIStoryboardSegue.أجد بهذه الطريقة الكثير من المتاعب مقارنة بالطريقة البسيطة التي كانت عليها من قبل، لذلك اندمجت مرة أخرى.

كيف تسبب هذا في تحميل وحدة التحكم في العرض مرتين؟عند نقل الكود من مشروع القصة المصورة إلى مشروع xib، قمت بعمل بضع xibs (واحد لكل ViewController) و نسخ كائن viewcontroller من لوحة العمل.أدى هذا إلى ظهور xib ليس به طريقة عرض، بل وحدة تحكم في العرض؛مما يعني أنني قمت بوضع وحدة تحكم العرض في وحدة تحكم العرض (نظرًا لأن مالك الملف هو أيضًا مثيل لوحدة التحكم في العرض).لا أعتقد في حالتك أنك واجهت هذه المشكلة ولكني آمل أن تساعد شخصًا ما في يوم من الأيام.

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

وماذا لو لم التعليمات البرمجية الوصول إلى خاصية عرض عندما لم يتم تحميل حتى الآن، وسوف تحكم عرض خلق رأي فارغة فقط ويمكن أن يؤدي view did load بطريق الخطأ.

والخطأ الأكثر شيوعا هو الوصول إلى خاصية عرض أثناء التهيئة. قد يكون بعض استرجاع الممتلكات (واضع) التي يتذرع بها xib يجب الوصول إلى خاصية عرض عن طريق الخطأ.

وماذا لو كان المشروح بعض الممتلكات مع IBInspectable يجب عليك أن تحقق isViewLoaded قبل تطبيق بعض قيمة عرضها.


-(void) setSomeProperty:(UIColor*) someColor
{
  _someColor = someColor;
  if(self.isViewLoaded) {
    // self.view causes view creation and invokes 'viewDidLoad' then the view is not ready yet.
    self.view.backgroundColor = someColor;
  }
}

-(void) viewDidLoad
{
  [super viewDidLoad]
  if(_someColor){
    self.view.backgroundColor = _someColor;
  }
}

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