0

How to override object creation (alloc) and to add a custom logic? The reason is I always build my universal apps using 3 classes for each module (screen), for example

1. LoginViewController  // this inherits from BaseViewController and holds common code for both ipad and iphone 
2. LoginViewController_iphone // custom logic for iphone only
3. LoginViewController_ipad // custom logic for ipad only

The cool part with that is I'm using controllers without suffixes around the code because they all extend from BaseViewController and it has overriden alloc method, which does smart logic and auto picks correct class upon calling VC alloc/init.

Now, as we all started slowly to transition to Swift, I managed to override and implement alloc method in Swift 1.2 as well. Here's the implementation:

class BaseViewController: UIViewController {

  override class func alloc() -> BaseViewController {

    var viewControllerClassName : String = NSStringFromClass(self)

    if ((viewControllerClassName.lowercaseString.rangeOfString("ipad") == nil) && (viewControllerClassName.lowercaseString.rangeOfString("iphone") == nil)) {

        switch (UIDevice.currentDevice().userInterfaceIdiom) {

        case .Pad:

            viewControllerClassName += "_ipad";

        case .Phone:

            viewControllerClassName += "_iphone";

        default:

            viewControllerClassName += "";
        }

        let viewControllerClass : AnyClass = NSClassFromString(viewControllerClassName)

        return viewControllerClass.alloc() as! BaseViewController

    } else {

        return super.alloc() as! BaseViewController
    }
}

Today, I downloaded Xcode 7 beta 6 with Swift 2 and tried to compile the project but got annoying surprise message "alloc() is unavailable in Swift: use object initializers instead". Well, I don't mind the other devs prefer using a different approach, however having more flexibility is better than having less. Has anybody an idea how to override creation of class object and add the custom logic?

Centurion
  • 14,106
  • 31
  • 105
  • 197
  • It's probably best to keep this kind of Objective-C hacks in Objective-C. Pure swift types would not use alloc anyway. – Nikolai Ruhe Aug 31 '15 at 15:15
  • @NikolaiRuhe True, but still some hacks will be needed anyway, for example Reflection thingies, SideMenu solutions with method swizzling, dependency injection frameworks like Typhoon. This is what I'm looking for during my initial steps with Swift because Objc has a lot of power regardless of its exotic syntax and therefore transitioning large scale app solutions from Objc to Swift is not as smooth as it should be, at least for now :) – Centurion Aug 31 '15 at 16:24

2 Answers2

1

Alloc being callable was an oversight, according to Chris Lattner, the developer of Swift.

You're going to have to migrate to object initializers.

  • Thanks for the reference. Damn it, hate to fallback to less elegant solutions as there's no way to have similar functionality when working with storyboards. Because view controller names are hardcoded within the storyboards and there's no way to auto pick related ipad or iphone subclass. – Centurion Aug 31 '15 at 15:21
  • 1
    And you can't handle these layout differences via a single storyboard that utilizes Adaptive UI and size classes? One of the upcoming iOS 9 features is split-view (overlay or side-by-side apps), so your "iPad" view controller may find itself needing to support compact mode. –  Aug 31 '15 at 15:26
  • In normal apps, iPad is not just resizable version of iPhone. You need to use extra space wisely on iPad (add extra controls) and therefore single xib/storyboard file is not suitable for both ipad and ipad in such cases. – Centurion Aug 31 '15 at 16:18
  • 1
    Correct. iPad is not just resizable version of iPhone. It's laid out differently. But Adaptive UI *is* designed to do exactly what you want. One storyboard **can** contain both an iPad and an iPhone layout, and the system uses the right layout, depending on size classes. The gist of [Adaptive UI](https://developer.apple.com/design/adaptivity/) is to change from thinking in terms of devices, to thinking in terms of horizontal and vertical sizes (UITraitCollection). Then your app adapts to anything, whether it's iPhone, iPad, portrait, landscape, split-screen, etc. –  Aug 31 '15 at 16:37
1

The behavior you describe would not work on pure Swift types. There's no proper Swift concept for doing a similar thing in Swift (at least none that I'm aware of).

When resorting to Objective-C runtime trickery it seems OK to implement these tricks in Objective-C.

Nikolai Ruhe
  • 81,520
  • 17
  • 180
  • 200