title: how to override/swizzle a method of a private class in runtime objective-c?
body: <p>To give a bit of context of why I'm asking this: basically I would like to change the location of the <code>myLocationButton</code> of the google map on iOS. So I first fetch the actual button like so:</p>
  
  <pre><code>@implementation GMSMapView (UIChanges)
  
  - (UIButton *)myLocationButton
  {
      UIButton *myLocationButton;
      for (myLocationButton in [settingView subviews])
      {
          if ([myLocationButton isMemberOfClass:[UIButton class]])
              break;
      }
      return myLocationButton;
  }
  </code></pre>
  
  <p>Then I try to change it's position in the screen using NSLayoutConstraints (directly changing values of the <code>frame</code> property of the button does nothing with google maps SDK 1.8+): </p>
  
  <pre><code>UIButton *myLocationButton = [mapView_ myLocationButton];
  [myLocationButton setTranslatesAutoresizingMaskIntoConstraints:NO];
  [myLocationButton constraintRightEqualTo:[myLocationButton superview] constant:0];
  [myLocationButton constraintTopEqualTo:[myLocationButton superview] constant:50];
  </code></pre>
  
  <p>where <code>constraintRightEqualTo</code> is defined in a category as:</p>
  
  <pre><code>- (void)constraintRightEqualTo:(UIView *)toView constant:(CGFloat)constant
  {
      NSLayoutConstraint *cn = [NSLayoutConstraint constraintWithItem:self
                                                            attribute:NSLayoutAttributeRight
  
                                                            relatedBy:NSLayoutRelationEqual
                                                               toItem:toView
                                                            attribute:NSLayoutAttributeRight
                                                           multiplier:1 constant:constant];
  
      [toView addConstraint:cn];
  }
  </code></pre>
  
  <p>so far so good? ok.</p>
  
  <p>Now this works just fine in iOS8.. however when I run this in iOS 7 it crashes with this famous error:</p>
  
  <blockquote>
    <p>-[TPMURequestStatusNotificationManager
    makeActionButtonResponsive]:810 - makeActionButtonResponsive
    2014-10-08 16:03:20.775 SmartTaxi[13009:60b] <strong>* Assertion failure in
    -[GMSUISettingsView layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2935.137/UIView.m:8794 2014-10-08
    16:03:20.779 SmartTaxi[13009:60b] *</strong> Terminating app due to uncaught
    exception 'NSInternalInconsistencyException', reason: 'Auto Layout
    still required after executing -layoutSubviews. GMSUISettingsView's
    implementation of -layoutSubviews needs to call super.'</p>
  </blockquote>
  
  <p>the problem is that <code>GMSUISettingsView</code> is not calling <code>[super layoutSubviews]</code>.. </p>
  
  <p>I've seen this kind of error before.. the thing is that it happens with public classes such as <code>UITableViewCell</code>, as opposed to this private one <code>GMSUISettingsView</code> which is hidden in the guts of the google maps SDK for iOS. Had it been public.. i could have easily <a href="http://nshipster.com/method-swizzling/" rel="nofollow noreferrer">swizzled</a> the method <code>layoutsubviews</code> inside of it using an approach similar to <a href="https://stackoverflow.com/a/12941256/766570">this</a> answer. But it's not a public method. How can I in runtime change the definition of it's <code>layoutsubviews</code> to get around this problem? (suggestions to accomplish the same goal using simpler methods are also welcome)</p>
  
  <hr>
  
  <p><strong>UPDATE</strong></p>
  
  <p>so based on feedback + a bit more research I did the following:</p>
  
  <pre><code>@interface AttackerClass : UIView @end
  @implementation AttackerClass
  
  - (void)_autolayout_replacementLayoutSubviews
  {
      struct objc_super superTarget;
      superTarget.receiver = self;
      superTarget.super_class = class_getSuperclass(object_getClass(self));
  
      objc_msgSendSuper(&amp;superTarget, @selector(layoutSubviews));
      NSLog(@":: calling send super")
      // PROBLEM: recursive call.. how do I call the *original* 
      // GMSUISettingsView implementation of layoutSubivews here?
      // replacing this with _autolayout_replacementLayoutSubviews will
      // throw an error b/c GMSUISettingsView doesn't have that method defined
      objc_msgSend(self, @selector(layoutSubviews)); 
      objc_msgSendSuper(&amp;superTarget, @selector(layoutSubviews));
  }            
  @end
  
  
  Method attackerMethod = class_getInstanceMethod([AttackerClass class], @selector(_autolayout_replacementLayoutSubviews));
  Method victimMethod = class_getInstanceMethod(NSClassFromString(@"GMSUISettingsView"), @selector(layoutSubviews));
  
  method_exchangeImplementations(victimMethod, attackerMethod);
  </code></pre>
  
  <p>The problem with this approach is that anytime <code>GMSUISettingsView</code> calls <code>layoutSubviews</code>.. it is in effect calling <code>_autolayout_replacementLayoutSubviews</code>.. which then recursively calls <code>GMSUISettingsView</code> layoutsubviews.. so my app goes into an infinite recursive loop. <a href="https://stackoverflow.com/a/12941256/766570">this answer</a> solved that problem by using a category.. but I can't in this case b/c <code>GMSUISettingsView</code> is a private class.. </p>
  
  <p>another way of asking the same question: how can i retain a reference to the unaltered version of <code>GMSUISettingsView's layoutSubviews</code> and use it in <code>_autolayout_replacementLayoutSubviews</code> so that I don't fall into this recursive call problem.</p>
  
  <p>ideas?</p>