ios - كيف يمكنني تحريك التغييرات القيد؟




animation ios6 autolayout (11)

أعمل على تحديث تطبيق قديم باستخدام AdBannerView وعندما لا يكون هناك إعلان ، يتم إيقافه. عندما يكون هناك إعلان ينزلق على الشاشة. الاشياء الاساسية.

النمط القديم ، أنا وضعت الإطار في كتلة الرسوم المتحركة. نمط جديد ، لدي IBOutlet إلى القيد الذي يحدد الموقع Y ، في هذه الحالة يكون المسافة من أسفل المنظر العلوي ، وتعديل الثابت.

- (void)moveBannerOffScreen {
    [UIView animateWithDuration:5
             animations:^{
                          _addBannerDistanceFromBottomConstraint.constant = -32;
                     }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen {
    [UIView animateWithDuration:5
             animations:^{
                         _addBannerDistanceFromBottomConstraint.constant = 0;
             }];
    bannerIsVisible = TRUE;
}

وتتحرك اللافتة ، تمامًا كما هو متوقع ، ولكن بدون رسوم متحركة.

حدث: تمت إعادة مشاهدة فيديو WWDC12 " أفضل الممارسات لتخطيط التصميم التلقائي " والذي يشمل الرسوم المتحركة. يناقش كيفية تحديث القيود باستخدام CoreAnimation .

لقد حاولت مع التعليمات البرمجية التالية ، ولكن الحصول على نفس النتائج بالضبط.

- (void)moveBannerOffScreen {
    _addBannerDistanceFromBottomConstraint.constant = -32;
    [UIView animateWithDuration:2
                     animations:^{
                         [self.view setNeedsLayout];
                     }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen {
    _addBannerDistanceFromBottomConstraint.constant = 0;
    [UIView animateWithDuration:2
                     animations:^{
                         [self.view setNeedsLayout];
                     }];
    bannerIsVisible = TRUE;
}

في ملاحظة جانبية ، لقد تحققت عدة مرات ويتم تنفيذ ذلك على الموضوع الرئيسي.


Answers

حل العامل والمختبر للتو ل Swift 3 مع Xcode 8.3.3:

self.view.layoutIfNeeded()
self.calendarViewHeight.constant = 56.0

UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
        self.view.layoutIfNeeded()
    }, completion: nil)

فقط ضع في اعتبارك أن self.calendarViewHeight هو قيد يشير إلى customView (CalendarView). اتصلت .layoutIfNeeded () على self.view وليس على self.calendarView

نأمل أن تكون هذه المساعدة.


حل العمل 100٪ سويفت 3.1

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

self.view.layoutIfNeeded() // Force lays of all subviews on root view
UIView.animate(withDuration: 0.5) { [weak self] in // allowing to ARC to deallocate it properly
       self?.tbConstraint.constant = 158 // my constraint constant change
       self?.view.layoutIfNeeded() // Force lays of all subviews on root view again.
}

القصة المصورة ، رمز ، نصائح وعدد قليل Gotchas

الإجابات الأخرى على ما يرام ولكن هذا واحد يسلط الضوء على عدد قليل من الحالات الهامة إلى حد ما من القيود المتحركة باستخدام مثال حديث. ذهبت من خلال الكثير من الاختلافات قبل أن أدرك ما يلي:

أدخل القيود التي تريد استهدافها في متغيرات Class للاحتفاظ بمرجع قوي. في سويفت استخدمت المتغيرات الكسولة:

lazy var centerYInflection:NSLayoutConstraint = {
       let temp =  self.view.constraints.filter({ $0.firstItem is MNGStarRating }).filter ( { $0.secondItem is UIWebView }).filter({ $0.firstAttribute == .CenterY }).first
        return temp!
}()

بعد بعض التجارب لاحظت أنه يجب على المرء الحصول على القيد من وجهة نظر ABOVE (ويعرف أيضا باسم superview) وجهات النظر حيث يتم تعريف القيد. في المثال أدناه (كل من MNGStarRating و UIWebView هما نوعان من العناصر أقوم بإنشاء قيد بينهما ، وهما معاينتان ضمن self.view).

تصفية تسلسل

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

القيود المتحركة باستخدام سويفت

Nota Bene - هذا المثال هو حل Storyboard / code ويفترض أن أحده قد وضع قيودًا افتراضية في لوحة العمل. يمكن للمرء بعد ذلك تحريك التغييرات باستخدام الكود.

بافتراض أنك تقوم بإنشاء خاصية لتصفية معايير دقيقة والوصول إلى نقطة انعطاف محددة للرسم المتحرك (بالطبع يمكنك أيضًا تصفية مصفوفة وتكرارها إذا كنت تحتاج إلى قيود متعددة):

lazy var centerYInflection:NSLayoutConstraint = {
    let temp =  self.view.constraints.filter({ $0.firstItem is MNGStarRating }).filter ( { $0.secondItem is UIWebView }).filter({ $0.firstAttribute == .CenterY }).first
    return temp!
}()

....

في وقت اخر...

@IBAction func toggleRatingView (sender:AnyObject){

    let aPointAboveScene = -(max(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height) * 2.0)

    self.view.layoutIfNeeded()


    //Use any animation you want, I like the bounce in springVelocity...
    UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.75, options: [.CurveEaseOut], animations: { () -> Void in

        //I use the frames to determine if the view is on-screen
        if CGRectContainsRect(self.view.frame, self.ratingView.frame) {

            //in frame ~ animate away
            //I play a sound to give the animation some life

            self.centerYInflection.constant = aPointAboveScene
            self.centerYInflection.priority = UILayoutPriority(950)

        } else {

            //I play a different sound just to keep the user engaged
            //out of frame ~ animate into scene
            self.centerYInflection.constant = 0
            self.centerYInflection.priority = UILayoutPriority(950)
            self.view.setNeedsLayout()
            self.view.layoutIfNeeded()
         }) { (success) -> Void in

            //do something else

        }
    }
}

العديد من الأدوار الخاطئة

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

  1. احترس من zPositioning. في بعض الأحيان عندما يحدث أي شيء على ما يبدو ، يجب إخفاء بعض طرق العرض الأخرى أو استخدام مصحح طرق العرض لتحديد موقع العرض المتحرك. حتى أنني عثرت على حالات تم فيها فقدان سمة وقت معرفة من قبل المستخدم في xml الخاص بلوحة القصة وأدت إلى تغطية العرض المتحرك (أثناء العمل).

  2. استغرقي دقيقة دائمًا في قراءة الوثائق (الجديدة والقديمة) ، والمساعدة السريعة ، والرؤوس. تستمر Apple في إجراء الكثير من التغييرات لإدارة قيود AutoLayout بشكل أفضل (انظر طرق عرض التكديس). أو على الأقل كتاب الطبخ AutoLayout . ضع في اعتبارك أنه في بعض الأحيان تكون أفضل الحلول موجودة في الوثائق / مقاطع الفيديو القديمة.

  3. العب حولها مع القيم الموجودة في الرسم المتحرك واعتبر استخدام متغيرات animateWithDuration الأخرى.

  4. لا تقم بترقيم قيم تخطيط محددة كمعايير لتحديد التغييرات للثوابت الأخرى ، بدلاً من استخدام القيم التي تسمح لك بتحديد موقع العرض. CGRectContainsRect مثال واحد

  5. إذا لزم الأمر ، لا تتردد في استخدام هوامش التخطيط المرتبطة بمشاهدة المشاركة في تعريف القيد let viewMargins = self.webview.layoutMarginsGuide : على سبيل المثال
  6. لا تعملين ليس عليك القيام به ، فكل وجهات النظر التي تحتوي على قيود على لوحة العمل لها قيود مرتبطة بخاصية self.viewName.const الخاصية
  7. تغيير أولوياتك لأي قيود أقل من 1000. أقوم بتعيين المنجم إلى 250 (منخفض) أو 750 (عالي) على لوحة العمل. (إذا حاولت تغيير 1000 أولوية إلى أي شيء في التعليمات البرمجية ، فسيحدث تعطل في التطبيق نظرًا لأن 1000 مطلوب)
  8. لا تنظر على الفور في محاولة استخدام activateConstraints و deactivateConstraints (لديهم مكانهم ولكن عندما تعلم فقط أو إذا كنت تستخدم لوحة القصة باستخدام هذه ربما يعني الكثير الخاص بك ~ لديهم مكان على الرغم من كما هو موضح أدناه)
  9. ضع في اعتبارك عدم استخدام addConstraints / removeConstraints إلا إذا كنت تضيف بالفعل قيدًا جديدًا في التعليمة البرمجية. لقد وجدت أنه في معظم الأوقات أقوم بتخطيط وجهات النظر في لوحة العمل بالقيود المطلوبة (وضع العرض خارج الشاشة) ، ثم في التعليمات البرمجية ، فأنا أحرك القيود التي تم إنشاؤها مسبقًا في لوحة العمل لتحريك العرض.
  10. قضيت الكثير من الوقت الضائع في بناء القيود مع الطبقة NSAnchorLayout الجديدة والفئات الفرعية. هذه الأعمال على ما يرام ولكن الأمر استغرقني بعض الوقت لأدرك أن جميع القيود التي أحتاجها موجودة بالفعل في لوحة العمل. إذا قمت ببناء قيود في التعليمات البرمجية ، فمن المؤكد أن استخدام هذه الطريقة لتجميع القيود الخاصة بك:

عينة سريعة من الحلول لتجنب عند استخدام القصص المصورة

private var _nc:[NSLayoutConstraint] = []
    lazy var newConstraints:[NSLayoutConstraint] = {

        if !(self._nc.isEmpty) {
            return self._nc
        }

        let viewMargins = self.webview.layoutMarginsGuide
        let minimumScreenWidth = min(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height)

        let centerY = self.ratingView.centerYAnchor.constraintEqualToAnchor(self.webview.centerYAnchor)
        centerY.constant = -1000.0
        centerY.priority = (950)
        let centerX =  self.ratingView.centerXAnchor.constraintEqualToAnchor(self.webview.centerXAnchor)
        centerX.priority = (950)

        if let buttonConstraints = self.originalRatingViewConstraints?.filter({

            ($0.firstItem is UIButton || $0.secondItem is UIButton )
        }) {
            self._nc.appendContentsOf(buttonConstraints)

        }

        self._nc.append( centerY)
        self._nc.append( centerX)

        self._nc.append (self.ratingView.leadingAnchor.constraintEqualToAnchor(viewMargins.leadingAnchor, constant: 10.0))
        self._nc.append (self.ratingView.trailingAnchor.constraintEqualToAnchor(viewMargins.trailingAnchor, constant: 10.0))
        self._nc.append (self.ratingView.widthAnchor.constraintEqualToConstant((minimumScreenWidth - 20.0)))
        self._nc.append (self.ratingView.heightAnchor.constraintEqualToConstant(200.0))

        return self._nc
    }()

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

ملاحظة: خذ لحظات من قراءة قسم AutoLayout في الأسفل والأدلة الأصلية. هناك طريقة لاستخدام هذه التقنيات لتكملة الرسوم المتحركة الديناميكية الخاصة بك.

UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 1.0, options: [.CurveEaseOut], animations: { () -> Void in

            //
            if self.starTopInflectionPoint.constant < 0  {
                //-3000
                //offscreen
                self.starTopInflectionPoint.constant = self.navigationController?.navigationBar.bounds.height ?? 0
                self.changeConstraintPriority([self.starTopInflectionPoint], value: UILayoutPriority(950), forView: self.ratingView)

            } else {

                self.starTopInflectionPoint.constant = -3000
                 self.changeConstraintPriority([self.starTopInflectionPoint], value: UILayoutPriority(950), forView: self.ratingView)
            }

        }) { (success) -> Void in

            //do something else
        }

    }

Snippet من دليل AutoLayout (لاحظ أن المقتطف الثاني يستخدم OS X). راجع للشغل - لم يعد هذا في الدليل الحالي بقدر ما أستطيع أن أرى. التقنيات المفضلة تستمر في التطور.

تغييرات متحركة بواسطة Auto Layout

إذا كنت بحاجة إلى التحكم الكامل في تحريك التغييرات التي تم إجراؤها بواسطة Auto Layout ، فيجب إجراء تغييرات القيد برمجياً. المفهوم الأساسي هو نفسه لكل من نظامي التشغيل iOS و OS X ، ولكن هناك بعض الاختلافات الطفيفة.

في تطبيق iOS ، سيبدو رمزك على النحو التالي:

[containerView layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0 animations:^{
     // Make all constraint changes here
     [containerView layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];

في نظام التشغيل OS X ، استخدم الشفرة التالية عند استخدام الرسوم المتحركة المدعومة بالطبقة:

[containterView layoutSubtreeIfNeeded];
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
     [context setAllowsImplicitAnimation: YES];
     // Make all constraint changes here
     [containerView layoutSubtreeIfNeeded];
}];

عند عدم استخدام الرسوم المتحركة المدعومة بالطبقة ، يجب عليك تحريك الثابت باستخدام رسوم متحركة القيد:

[[constraint animator] setConstant:42];

لأولئك الذين يتعلمون بصريا أفضل هذا الفيديو المبكر من شركة آبل .

اعرني انتباهك جيدا

في كثير من الأحيان في الوثائق هناك ملاحظات صغيرة أو أجزاء من التعليمات البرمجية التي تؤدي إلى أفكار أكبر. على سبيل المثال ، يعد إرفاق قيود التخطيط التلقائي بالرسوم المتحركة الديناميكية فكرة كبيرة.

حظا سعيدا، وربما تكون القوة معك.


هناك مقال يتحدث عن هذا: http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was

فيه ، مشفرة مثل هذا:

- (void)handleTapFrom:(UIGestureRecognizer *)gesture {
    if (_isVisible) {
        _isVisible = NO;
        self.topConstraint.constant = -44.;    // 1
        [self.navbar setNeedsUpdateConstraints];  // 2
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded]; // 3
        }];
    } else {
        _isVisible = YES;
        self.topConstraint.constant = 0.;
        [self.navbar setNeedsUpdateConstraints];
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded];
        }];
    }
}

آمل أن يساعد.


في سياق الرسوم المتحركة المقيدة ، أود أن أذكر موقفًا محددًا حيث قمت بتحريك القيد على الفور ضمن إعلام لوحة المفاتيح.

حدد القيد مساحة أعلى من حقل نص إلى أعلى الحاوية. عند فتح لوحة المفاتيح ، أقوم فقط بتقسيم الثابت على 2.

لم أتمكن من تحقيق حركة رسوم متحركة متجانسة مباشرة داخل إخطار لوحة المفاتيح. ما يقرب من نصف مرات العرض سوف يقفز فقط إلى موقعه الجديد - دون تحريك.

حدث لي قد يكون هناك بعض التخطيط إضافية يحدث نتيجة لفتح لوحة المفاتيح. إضافة كتلة dispatch_after بسيطة مع تأخير 10ms جعلت تشغيل الرسوم المتحركة في كل مرة - لا القفز.


ملاحظتان مهمتان:

  1. يجب عليك الاتصال على layoutIfNeeded داخل كتلة الرسوم المتحركة. توصي Apple فعليًا باستدعائها مرة واحدة قبل كتلة الرسوم المتحركة للتأكد من اكتمال جميع عمليات التخطيط المعلقة

  2. تحتاج إلى الاتصال بشكل محدد على وجهة نظر الوالدين (على سبيل المثال self.view ) ، وليس وجهة نظر الطفل التي لديها قيود تعلق عليها. سيؤدي القيام بذلك إلى تحديث كافة طرق العرض المقيدة ، بما في ذلك تحريك طرق العرض الأخرى التي قد تكون مقيدة في طريقة العرض التي قمت بها بتغيير القيد (على سبيل المثال ، يتم إرفاق العرض B إلى أسفل العرض A وقمت فقط بتغيير إزاحة العرض A الأعلى وتريد عرض B لتحريك معها)

جرب هذا:

ج موضوعية

- (void)moveBannerOffScreen {
    [self.view layoutIfNeeded];

    _addBannerDistanceFromBottomConstraint.constant = -32;
    [UIView animateWithDuration:5
        animations:^{
            [self.view layoutIfNeeded]; // Called on parent view
        }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen { 
    [self.view layoutIfNeeded];

    _addBannerDistanceFromBottomConstraint.constant = 0;
    [UIView animateWithDuration:5
        animations:^{
            [self.view layoutIfNeeded]; // Called on parent view
        }];
    bannerIsVisible = TRUE;
}

سويفت 3

_addBannerDistanceFromBottomConstraint.constant = 0

UIView.animate(withDuration: 5) {
    self.view.layoutIfNeeded()
}

حل Swift 4

UIView.animate

ثلاث خطوات بسيطة:

  1. قم بتغيير القيود ، على سبيل المثال:

    heightAnchor.constant = 50
    
  2. أخبر view الذي يحتوي على أن تخطيطه متسخ وأن autolayout يجب إعادة حساب التخطيط:

    self.view.setNeedsLayout()
    
  3. في قالب الرسوم المتحركة ، أخبر التخطيط بإعادة حساب التخطيط ، وهو ما يعادل إعداد الإطارات مباشرةً (في هذه الحالة ، سيقوم autolayout بتعيين الإطارات):

    UIView.animate(withDuration: 0.5) {
        self.view.layoutIfNeeded()
    }
    

أكمل أبسط مثال:

heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
    self.view.layoutIfNeeded()
}

ملاحظة جانبية

هناك خطوة 0 اختيارية - قبل تغيير القيود التي قد ترغب في استدعاء self.view.layoutIfNeeded() للتأكد من أن نقطة البداية للرسوم المتحركة هي من الحالة مع وجود قيود قديمة مطبقة (في حالة وجود بعض التغييرات الأخرى في القيود لا يجب تضمينه في الرسوم المتحركة):

otherConstraint.constant = 30
// this will make sure that otherConstraint won't be animated but will take effect immediately
self.view.layoutIfNeeded()

heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
    self.view.layoutIfNeeded()
}

UIViewPropertyAnimator

نظرًا لأن نظام التشغيل iOS 10 حصلنا على آلية جديدة UIViewPropertyAnimator المتحركة - UIViewPropertyAnimator ، يجب أن نعرف أن الآلية نفسها تنطبق عليها. الخطوات هي نفسها في الأساس:

heightAnchor.constant = 50
self.view.setNeedsLayout()
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
    self.view.layoutIfNeeded()
}
animator.startAnimation()

نظرًا لأن animator عبارة عن تغليف للرسم المتحرك ، يمكننا الرجوع إليها واستدعاءها لاحقًا. ومع ذلك ، نظرًا لأننا في لوحة الرسوم المتحركة نقوم فقط بإخبار autolayout بإعادة حساب الإطارات ، يجب علينا تغيير القيود قبل استدعاء startAnimation . لذلك شيء من هذا القبيل ممكن:

// prepare the animator first and keep a reference to it
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
    self.view.layoutIfNeeded()
}

// at some other point in time we change the constraints and call the animator
heightAnchor.constant = 50
self.view.setNeedsLayout()
animator.startAnimation()

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

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


// Step 1, update your constraint
self.myOutletToConstraint.constant = 50; // New height (for example)

// Step 2, trigger animation
[UIView animateWithDuration:2.0 animations:^{

    // Step 3, call layoutIfNeeded on your animated view's parent
    [self.view layoutIfNeeded];
}];

حل سريع:

yourConstraint.constant = 50
UIView.animateWithDuration(1, animations: yourView.layoutIfNeeded)

بشكل عام ، تحتاج فقط إلى تحديث القيود واستدعاء layoutIfNeeded داخل كتلة الرسوم المتحركة. يمكن أن يكون هذا إما تغيير خاصية .constant لـ NSLayoutConstraint ، أو إضافة قيود إزالة (iOS 7) ، أو تغيير خاصية .active للقيود (iOS 8 و 9).

عينة من الرموز:

[UIView animateWithDuration:0.3 animations:^{
    // Move to right
    self.leadingConstraint.active = false;
    self.trailingConstraint.active = true;

    // Move to bottom
    self.topConstraint.active = false;
    self.bottomConstraint.active = true;

    // Make the animation happen
    [self.view setNeedsLayout];
    [self.view layoutIfNeeded];
}];

نموذج الإعداد:

جدال

هناك بعض الأسئلة حول ما إذا كان يجب تغيير القيد قبل كتلة الرسوم المتحركة ، أو داخلها (راجع الإجابات السابقة).

ما يلي هو محادثة على تويتر بين Martin Pilkington الذي يقوم بتدريس iOS ، و Ken Ferry الذي كتب Auto Layout. يوضح كين أنه على الرغم من أن تغيير الثوابت خارج كتلة الرسوم المتحركة قد يعمل حاليًا ، إلا أنه ليس آمنًا ويجب تغييرها فعلاً داخل كتلة الرسوم المتحركة. https://twitter.com/kongtomorrow/status/440627401018466305

الرسوم المتحركة:

مشروع عينة

في ما يلي مشروع بسيط يوضح كيف يمكن عرض صورة متحركة. إنه يستخدم Objective C ويقوم بتحريك العرض عن طريق تغيير الخاصية .active للعديد من القيود. https://github.com/shepting/SampleAutoLayoutAnimation


عند استخدام ARC ، فأنت ببساطة لا تتصل بـ [super dealloc] بشكل صريح - يقوم المترجم [super dealloc] لك (كما هو موضح في مستند Clang LLVM ARC ، الفصل 7.1.2 ):

- (void) dealloc
{
    [observer unregisterObject:self];
    // [super dealloc]; //(provided by the compiler)
}




ios animation ios6 autolayout