4.Swift初探-2048小游戏中的问题

         最近工作不是很忙,就继续学习swift,想着干学习语法提高太慢,就试着用swift写了一个2048小游戏,中间遇见的一些问题在这里记录一下:

1、自定义类

      首先自定义类就花费了很大的力气,主要是因为swift自定义类时严格控制了初始化,我想自定义一个继承自UIView的类,首先必须写这个函数:

required init?(coder aDecoder: NSCoder)
    {
        fatalError("init(coder:) has not been implemented")
    }
require关键字表明如果子类需要添加异于父类的初始化方法时,必须先要实现父类中使用required修饰符修饰过的初始化方法,并且也要使用required修饰符而不是override如果子类中不需要添加任何初始化方法,我们则可以忽略父类的required初始化方法:

        在Objective-C中,init方法是非常不安全的:没有人能保证init只被调用一次,也没有人保证在初始化方法调用以后,实例的各个变量都完成初始化,甚至如果在初始化里使用属性进行设置的话,还可能会造成各种问题。虽然Apple也明确说明了不应该在init中使用属性来访问,但这并不是编译器强制的,因此还是会有很多开发者犯这样的错误。

        所以Swift有了超级严格的初始化方法。一方面,Swift强化了designated初始化方法的地位。Swift中不加修饰的init方法都需要在方法中保证所有非Optional的实例变量被赋值初始化,而在子类中也强制 (显式或隐式地)调用super版本的designated初始化,所以无论如何走何种路径,被初始化的对象总是可以完成完整的初始化的。以下是我的初始化方法:

init()
    {
        self.number = 2
        self.frameNumber = 16
        for lineNumber in 0...3
        {
            for columnNumber in 0...3
            {
                let cubX = CGFloat(columnNumber)*(cubWidth+space)+space
                let cubY = CGFloat(lineNumber)*(cubWidth+space)+space
                let cubFrame:CGRect = CGRectMake(cubX, cubY, cubWidth, cubWidth)
                self.frameArray.append(cubFrame)
            }
        }
        super.init(frame:CGRectMake(0, 0, cubWidth, cubWidth))
        self.label.text = "2"
        self.label.font = UIFont.init(name:label.font.fontName, size: 70)
        self.label.textAlignment = NSTextAlignment.Center
        self.label.backgroundColor = UIColor.whiteColor()
        self.addSubview(self.label)
    }
    convenience init(number:Int)
    {
        self.init()
        self.number = number
        self.label.text = "\(number)"
    }
           与designated初始化方法对应的是在init前加上convenience关键字的初始化方法。这类方法是Swift初始化方法中的“二等公民”,只作为补充和提供使用上的方便。所有的convenience初始化方法都必须调用同一个类中的designated初始化完成设置,另外convenience的初始化方法是不能被子类重写或从子类中以super的方式被调用的。

       只要在子类中实现重写了父类convenience方法所需要的init方法的话,我们在子类中就也可以使用父类的convenience初始化方法了。

因此进行一下总结,可以看到初始化方法永远遵循以下两个原则:

  1. 初始化路径必须保证对象完全初始化,这可以通过调用本类型的designated初始化方法来得到保证;
  2. 子类的designated初始化方法必须调用父类的designated方法,以保证父类也完成初始化。

对于某些我们希望子类中一定实现的designated初始化方法,我们可以通过添加required关键字进行限制,强制子类对这个方法重写实现。这样的一个最大的好处是可以保证依赖于某个designated初始化方法的convenience一直可以被使用。

2.属性成员的set和get方法

         在OC中,我们可以重写 set和get方法去满足我们的需求,在swift中,这方面分得更加细致。首先把属性进行了分类,分为了存储属性和计算属性。对于存储属性,只需要单纯的 存储数据,所以不需要重写get和set方法。而对于计算属性,就是需要通过计算来设置值的,需要重写,具体形式如下:

var perimeter: Double {
        get {
            return 3.0 * sideLength
        }
        set {
            sideLength = newValue / 3.0
        }
    }

当我们需要在外部给属性成员赋值后进行一些操作的话,我们可以 使用willSet和didSet,在代码中我的使用如下:

var number:Int
    {
        didSet
        {
            label.text = "\(self.number)"
        }
    }

3.强制类型转换和数组排序

在swift中强制类型转换通过类似这种形式:Int(要转化的变量),但如果你要将父类对象强转为子类对象的话,需要使用as,具体如下:

for cub in self.gameBackGround.subviews
{
      if (cub is CYLCubView)
          {
              subViewArray.append(cub as! CYLCubView)
          }
}

如果是从子类转化而来的父类对象,则一定可以转化回去,使用as! ,如果不确定,则使用as

在swift中使用.sort进行排序,这里用到了闭包,还有一点不太理解,看一下别人的说法,讲得很清晰:

直接贴代码,不过多解释

//这是我们的model class imageFile { var fileName = String() var fileID = Int() }
//使用 var images : [imageFile] = [] images.sort({ $0.fileID > $1.fileID })

下面是闭包的进阶使用

// 一般的代码形式 images.sort({ (image1: imageFile, image2: imageFile) -> Bool in return image1.fileID > image2.fileID }) // 省略(->)的形式 images.sort({ image1, image2 in return image1.fileID > image2.fileID }) // 带返回值的简单闭包形式 images.sort({ image1, image2 in image1.fileID > image2.fileID }) // 隐含参数的形式 images.sort({ $0.fileID > $1.fileID }) // 以下结果都是相同,只是书写形式不同 images = images.sorted({ (image1: imageFile, image2: imageFile) -> Bool in return image1.fileID > image2.fileID }) images = images.sorted({ image1, image2 in return image1.fileID > image2.fileID }) images = images.sorted({ image1, image2 in image1.fileID > image2.fileID }) images = images.sorted({ $0.fileID > $1.fileID })
//swift标准库 sort(&images, { (image1: imageFile, image2: imageFile) -> Bool in return image1.fileID > image2.fileID }) sort(&images, { image1, image2 in return image1.fileID > image2.fileID }) sort(&images, { image1, image2 in image1.fileID > image2.fileID }) sort(&images, { $0.fileID > $1.fileID }) //使用方法 images = sorted(images, { (image1: imageFile, image2: imageFile) -> Bool in return image1.fileID > image2.fileID }) images = sorted(images, { image1, image2 in return image1.fileID > image2.fileID }) images = sorted(images, { image1, image2 in image1.fileID > image2.fileID }) images = sorted(images, { $0.fileID > $1.fileID })
在项目中我的用法:

array1.sortInPlace({$0.frameNumber < $1.frameNumber})
根据数组中对象的frameNumber属性从小到大进行排序

4.宏定义和懒加载

在swift没有#define,宏定义变成了这样:可以用let来声明常量取代,或者用全局函数来取代
懒加载变成了这样:
lazy var maskView:UIView? =
    {
        let maskView = UIView.init(frame: CGRectMake(0, 0, screenWidth, screenHeight))
        maskView.backgroundColor = UIColor.blackColor()
        maskView.alpha = 0.9
        return maskView
    }()
 
以上便是我做这个小游戏中遇到了一些很基础的问题。整个游戏的代码在GitHub上,有兴趣的可以下载下来,欢迎指正。点击打开链接





你可能感兴趣的:(游戏,2048,xcode,swift)