使用Swift的iOS代码结构,什么去哪里,所有代码?

时间:2016-05-31 12:29:23

标签: ios swift model-view-controller

所以我是iOS的新手,但是对Android充满了热情,我开始掌握大部分内容的要点,但我很难理解到底是什么,为什么会这样...... < / p>

当你使用故事板时,它很容易实现MVC模式(或任何其他视图分离模式),但当你在代码中创建所有内容时,我觉得它变得有点混乱。

假设我有一个ViewController,其父视图包含子视图,它们可能包含子视图。现在我应该在哪里创造孩子?在ViewController中(最方便)还是在父视图中(最近的)?

如果我使用ViewController我有参考,我会轻松制作出口等,但ViewController是否也应该像setTitle,setImage,background等那样做?这绝对是最简单的解决方案。缺点是视图只是对象,只会导致ViewController变得膨胀。

如果我使用View I&#39;我很难将回路连接到ViewController,而ViewController最终几乎什么都不做。

Apple也没有多大帮助,官方的FoodTracker教程同时展示了使用插座等的ViewController和Views等。

我现在拥有的基本结构:

updateLayoutStates()
setupLayoutPositions()
updateLayoutPositions()

...

/// Setups the initial constraints for all views
func setupLayoutPositions() {

    // add views by order of appearances
    addSubview(languageBtn)
    addSubview(playBtn)
    addSubview(menuBtn)
    //addSubview(barScrollOverlayView)
    addSubview(barScrollView)
    addSubview(collapseBtn)

    // add bar scroll inner subviws by order of appearance
    barScrollView.addSubview(barScrollContentView)

    barScrollContentView.addSubview(speedContainerView)
    barScrollContentView.addSubview(speedProgress)
    barScrollContentView.addSubview(readingStratBtn)
    // More code that adds constraints etc. etc.

...

/**
 Updates all views based on the current status of the bar
 */
func updateLayoutStates() {
    print("Bar updateLayoutStates")

    // setup base layout
    // setup permanent items, listed by appearance
    languageBtn.backgroundColor = UIColorFromHex(Constants.Colors.dark_blue, alpha: 1)
    languageBtn.setTitle("lang_da".localized, forState: .Normal)
    languageBtn.postSetup()
    languageBtn.setTitleColor(UIColorFromHex(Constants.Colors.white, alpha: 1), forState: .Normal)

    playBtn.setImage(UIImage(named: "Play"), forState: .Normal)
    playBtn.setImage(UIImage(named: "PlayActive"), forState: .Highlighted)
    playBtn.setTitle("label_play_key".localized, forState: .Normal)
    playBtn.postSetup()

   ...

/// updates the positions of all layouts based on the current status of the bar
func updateLayoutPositions() {
    if currentBarState == BarState.EnabledStandardExpanded {
        self.removeConstraint(collapseLeftConstraint)
        self.addConstraint(collapseRightConstraint)
    } else if currentBarState == BarState.EnabledStandardCollapsed {
        self.removeConstraint(collapseRightConstraint)
        self.addConstraint(collapseLeftConstraint)
    }
}

非常感谢所有带有示例的解释,如果我还不够清楚,我会很乐意进一步解释。

2 个答案:

答案 0 :(得分:1)

有很多方法/模式可以解决这个问题,避免视图控制器臃肿。在看了MVC,VIPER,MVVM和其他许多人之后,我非常喜欢Clean Swift的实现。它支持单一用途函数,依赖注入,并使视图控制器保持非常干净。

虽然起初看起来有点矫枉过正(对于非常小的项目而言) - 我最近重构了一个越来越笨重的OS X项目。令人惊讶的是,现在实现新功能,隔离错误和重用代码是多么简单。可能值得一试吗?

坏消息 - 如果你向千位开发者询问他们对此的看法,你至少会得到一千条意见。

好消息 - 该平台足够灵活,适合所有人!

Apple在此提供了MVC指南https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html,我将就此发表您的看法:

有一个非常基本的应用程序选择和安排会议室的例子:

<强>模型 如您所知,模型代表数据结构。我保留每个struct / class 1个文件,并保持代码只表示数据(不是业务逻辑)。我的会议室模型可能类似于:

struct ConferenceRoom {
    let maxOccupancy: Int
    let roomNumber: Int
    let hasProjector: Bool
    var reservations: 
}

<强>控制器 我尝试将业务逻辑保留在控制器中(不要与ViewControllers混淆)。例如:

class ConferenceRoomController {
  var conferenceRooms = [ConferenceRoom]()

  init() {
    ...
  }

  func retrieveConferenceRoomsFromDatastore() -> [ConferenceRoom] {
    ...
  }

  func reserveConferenceRoom(roomNumber: Int, startDate: NSDate, endDate: NSDate) -> Bool {
    ...

  }

  func findRoomsForDateWithCapacity(capacity: Int, date: NSDate) -> [ConferenceRoom] {
    ...
  }
}

查看 这通常是View / ViewController。在IOS中,ViewcController既是视图,也是用于管理视图的控制器,这对许多人来说是一个混乱点,并且因为它基本上可以做任何事情,所以过多的业务逻辑或其他代码会在这里结束(膨胀)。我尝试只在这里放置与显示数据相关的功能(不是显示什么 - 那是控制器)。如果我正在以预定方式向视图添加子视图,我也会在此处执行此操作。

class ConferenceRoomScheduler: UIViewController {
  @IBOutlet var numberOfParticipants: UITextField!
  @IBOutlet var reservationDate: UITextField!
  @IBOutlet var tableView: UITableView!
  @IBOutlet var submitButton: UIButton!

  let conferenceRoomController = ConferenceRoomController()

  @IBAction func submitButtonPressed(sender: UIButton) {
    let participants = Int(numberOfParticipants.text!)
    if let participants = participants {
      conferenceRoomController.findRoomsForDateWithCapacity(participants, date: NSDate())
    } else {
      print("Not a number")
    }
  }
}

这些类不完整,但希望提供一些放置在哪里的例子。我发现这些类型的决策随着您为平台开发更加舒适而发展。我同意 - 像Clean-Swift这样的一些模式似乎会花费大量时间和管道,如果你不熟悉具体的实现,你可能会这样做。例如,当我开始IOS开发时,我可能花费数小时整理一个简单的tableView,它看起来很复杂。现在,在完成了太多次计算后,一个功能超出基本功能的功能齐全的tableView只需几分钟即可完成设置。应用程序架构对我来说也是一样的。 Clean-Swift(以及其他人)不再显得过于沉重(而且这些好处会影响最初的感知复杂性)。

答案 1 :(得分:1)

一方面,你在谈论良好的架构。另一方面,您需要一些特定视图结构的帮助。

1)对于第一部分,你有很多资源。 DJohnsen已经提到MVVM和VIPER,我认为这是一个很好的谷歌搜索字符串。 我认为对建筑主题感到满意总是好的。每个架构都有权衡。 一个很好的起点是Uncle Bobs“清洁代码”。

从那里出现了许多想法。

2)关于您的观看问题:

如果您有嵌套的视图层次结构,那么考虑视图控制器包含可能是个好主意。一旦看到,您的视图就是由许多其他视图组成的,并且它会变得更复杂,您可能希望拆分组件。 你总是要考虑你想要解决的具体问题:

  • 您只想显示一个标签和一个按钮吗?将它们直接添加到视图控制器并连接插座或设置目标/操作。

  • 您是否拥有标题,自定义子视图,也可能是tableView等的复杂视图?使用子视图控制器

但要打破它:

视图控制器和视图彼此非常接近。 在iOS中,我开始以下列方式处理视图和视图控制器:

  • 视图控制器应该是愚蠢的。它们的唯一目的是管理子控制器或设置几个视图的属性。视图控制器还管理高级屏幕处理(设备旋转,状态栏处理等)并与表示层通信。

  • 视图更愚蠢,应该只设置子视图,布局(设置布局约束)并提供一些自定义方法(可以由视图控制器使用)。

这一切听起来有点难:但我认为这对初学者来说是一个很好的指导方针。过了一段时间,你会感到舒服。

你问的问题很好但是你会在一段时间后自己回答。我认为最重要的是你应该只将特定于视图的视图放入视图控制器和视图中。不多了。

所有其他人很快就升级为宗教战争:)。

干杯
奥兰多