Ios 在Swift中,不是';实例化函数之外的对象不是最佳做法吗?
在Swift中,我们似乎推断出类内的类型,而不是函数外的类型。我理解,如果一个变量只在一个函数中声明,那么它将只在给定的范围内存在。实例化函数之外的对象不是最好的做法吗?这样我们可以在编写viewController时引用相同的对象,同时避免崩溃的可能性?如果不是,那么在ViewController顶部推断变量,然后在函数中实例化对象的目的是什么 下面是我在教程中遵循的示例代码。请注意,mapView是如何在viewController顶部推断出来的,但在loadView方法中实例化的。这是否会使mapView对象只能由loadView函数访问,而不能由其他方法访问:Ios 在Swift中,不是';实例化函数之外的对象不是最佳做法吗?,ios,swift,Ios,Swift,在Swift中,我们似乎推断出类内的类型,而不是函数外的类型。我理解,如果一个变量只在一个函数中声明,那么它将只在给定的范围内存在。实例化函数之外的对象不是最好的做法吗?这样我们可以在编写viewController时引用相同的对象,同时避免崩溃的可能性?如果不是,那么在ViewController顶部推断变量,然后在函数中实例化对象的目的是什么 下面是我在教程中遵循的示例代码。请注意,mapView是如何在viewController顶部推断出来的,但在loadView方法中实例化的。这是否会
import Foundation
import UIKit
import MapKit
import CoreLocation
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
var mapView: MKMapView!
var problemChild: Int!
override func viewWillDisappear(_ animated: Bool) {
print("the view disappeared")
}
override func loadView() {
mapView = MKMapView()
view = mapView
mapView.delegate = self
mapView.isPitchEnabled = true
// let atlLongLat = MKCoordinateRegion.init(center: CLLocationCoordinate2D.init(latitude: CLLocationDegrees.init(33.7490), longitude: CLLocationDegrees.init(84.3880)), span: MKCoordinateSpan.init(latitudeDelta: 33.7490, longitudeDelta: 84.3880))
//mapView.setRegion(atlLongLat, animated: true)
mapView.showsPointsOfInterest = true
mapView.showsBuildings = true
mapView.showsCompass = true
mapView.showsTraffic = true
let locationManager = CLLocationManager()
locationManager.delegate = self
let locationAuthStatus = CLLocationManager.authorizationStatus()
if locationAuthStatus == .notDetermined {
locationManager.requestWhenInUseAuthorization()
}
mapView.showsUserLocation = true
let segmentedControl = UISegmentedControl.init(items: ["Standard", "Hybrid", "Satellite"])
segmentedControl.selectedSegmentIndex = 0
segmentedControl.translatesAutoresizingMaskIntoConstraints = false
segmentedControl.backgroundColor = UIColor.yellow
view.addSubview(segmentedControl)
let zoomButtonFrame = CGRect.init(x: 0, y: 0, width: view.bounds.width, height: 400)
let zoomButton = UIButton.init(frame: zoomButtonFrame)
zoomButton.backgroundColor = UIColor.green
zoomButton.setTitle("Where Am I?", for: .normal)
zoomButton.setTitleColor(UIColor.black, for: .normal)
zoomButton.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(zoomButton)
let guide = view.safeAreaLayoutGuide
let topConstraint = segmentedControl.topAnchor.constraint(equalTo: guide.topAnchor, constant: 8)
let zoomButtonTopConstraint = zoomButton.topAnchor.constraint(equalTo: segmentedControl.bottomAnchor, constant: 559)
let margins = view.layoutMarginsGuide
let zoomButtonLeadingConstraint = zoomButton.leadingAnchor.constraint(equalTo: margins.leadingAnchor)
let leadingConstraint = segmentedControl.leadingAnchor.constraint(equalTo: margins.leadingAnchor)
let trailingConstraint = segmentedControl.trailingAnchor.constraint(equalTo: margins.trailingAnchor)
let zoomButtonTrailingConstraint = zoomButton.trailingAnchor.constraint(equalTo: margins.trailingAnchor)
topConstraint.isActive = true
leadingConstraint.isActive = true
trailingConstraint.isActive = true
zoomButtonTopConstraint.isActive = true
zoomButtonLeadingConstraint.isActive = true
zoomButtonTrailingConstraint.isActive = true
segmentedControl.addTarget(self, action:#selector(mapTypeChanged(segControl:)), for: .valueChanged)
zoomButton.addTarget(self, action: #selector(zoomButtonTapped(zoomButt:)), for: .touchUpInside)
}
@objc func mapTypeChanged(segControl: UISegmentedControl) {
switch segControl.selectedSegmentIndex {
case 0:
mapView.mapType = .standard
case 1:
mapView.mapType = .mutedStandard
case 2:
mapView.mapType = .satelliteFlyover
default:
break
}
}
@objc func zoomButtonTapped(zoomButt: UIButton){
let b: Int = problemChild
print(b)
for _ in 1...5 {
print("Pinging Your Location...")
if zoomButt.backgroundColor == UIColor.green{
print("this button's background color is green man.")
}
}
}
func mapViewWillStartLocatingUser(_ mapView: MKMapView) {
//adding this here to get used to the idea of protocols
}
}
提前谢谢你,我很抱歉听起来像个傻瓜,但我真的很想理解。变量的范围是由其定义而不是赋值设置的
mapView
是MapViewController
的属性。因此,它可以在MapViewController
中的任何地方访问。这与分配时间无关
视图控制器有点不寻常,因为它们通常是从故事板初始化的,但有些片段在viewDidLoad
之前无法初始化(因为它们引用故事板中的片段)。也就是说,这不是最好的代码。这样写会更好:
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
let mapView = MKMapView()
...
并且应该从loadView
中删除行mapView=MKMapView()
。它的书写方式是有效的,但它并不像它应该的那样清晰或安全。(loadView
在视图控制器的生命周期中只调用一次。这并不总是正确的,但在Swift出现的时间内,这种情况一直存在。)
当我说这不是“应有的安全性”时,我的意思是,如果某个东西在
init
和loadView
之间访问mapView
(这可能由于各种原因而发生),这将崩溃。通过仔细管理,您可以避免这种情况,但避免更安全代码>可以键入时键入。变量的范围由其定义设置,而不是由其赋值设置mapView
是MapViewController
的属性。因此,它可以在MapViewController
中的任何地方访问。这与分配时间无关
视图控制器有点不寻常,因为它们通常是从故事板初始化的,但有些片段在viewDidLoad
之前无法初始化(因为它们引用故事板中的片段)。也就是说,这不是最好的代码。这样写会更好:
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
let mapView = MKMapView()
...
并且应该从loadView
中删除行mapView=MKMapView()
。它的书写方式是有效的,但它并不像它应该的那样清晰或安全。(loadView
在视图控制器的生命周期中只调用一次。这并不总是正确的,但在Swift出现的时间内,这种情况一直存在。)
当我说这不是“应有的安全性”时,我的意思是,如果某个东西在init
和loadView
之间访问mapView
(这可能由于各种原因而发生),这将崩溃。通过仔细管理,您可以避免这种情况,但避免更安全代码>可以的时候键入。在函数之外声明的变量,如mapView
是实例变量。变量的作用域是实例可用的所有代码,因此可以从其他函数引用对象
通过在loadView
内部初始化,对象引用仅在该赋值执行后才有效,但这与变量的可见性不同。在mapView
方式之外声明的变量是实例变量。变量的作用域是实例可用的所有代码,因此可以从其他函数引用对象
通过在loadView
中初始化它,对象引用仅在该赋值执行后有效,但这与变量的可见性不同。您询问:
在函数之外实例化对象,这样我们就可以在编写viewController时引用同一个对象,这不是最好的做法吗
如果你问“我们不喜欢属性而不是局部变量”的问题,答案是“不”。在防御性编程中,我们倾向于使用局部变量,但在实际需要视图控制器级别作用域的情况下除外,在这种情况下,我们使用属性。局部变量没有意外的数据共享/变异。属性,因为它们在所有方法中是共享的,所以它可能会在其他地方被意外更改(当然是适度的)。现在,如果您需要在各种方法中引用对象,例如使用mapView
的情况,则需要一个属性。但是如果我们不需要在其他地方引用它,比如locationManager
,那么如果可以,我们就坚持使用局部变量
如果不是,那么在ViewController顶部推断变量,然后在函数中实例化对象的目的是什么
首先,我们不是在视图控制器的顶部“推断变量”。我们只是“声明属性”,声明无论最终在何处实例化,都可以在整个视图控制器中访问该属性
关于预先声明属性的做法,但只是在稍后实例化对象并在类似viewDidLoad
的函数中设置属性(或者在您的示例中,在loadView
中),这并不是不合理的做法。它使实例化和配置保持一致
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
var mapView: MKMapView!
...
override func loadView() {
mapView = MKMapView()
view = mapView
...
let locationManager = CLLocationManager()
...
}
}
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
@IBOutlet var mapView: MKMapView!
...
override func viewDidLoad() {
super.viewDidLoad()
// perhaps reference the map view created in the storyboard to configure it, e.g.
mapView.isPitchEnabled = true
...
let locationManager = CLLocationManager()
...
}
}