原文:How To Make a Breakout Game with SpriteKit and Swift: Part 2
作者:Michael Briscoe
译者:kmyhy

更新说明:本教程由 Michael Briscoe升级为 Xcode 8 和 Swift 3。原文作者是 Barbara Reichart。

欢迎回到本教程!

在第一部分,你创建了一个会动的木板和小球到游戏中。

在第二部分,你将添加一些砖块和其它游戏逻辑到游戏中。

这部分内容从第一部分教程继续。如果你没有完成第一部分,可以从这里下载示例项目并继续。

竹砖

你已经让小球四处乱蹦并能够制造碰撞,接下来添加一些竹砖用来击碎。毕竟这是一个逃逸游戏嘛!

回到 GameScene.swift,在 didMove(to:) 方法中添加砖块:

// 1
let numberOfBlocks = 8
let blockWidth = SKSpriteNode(imageNamed: "block").size.width
let totalBlocksWidth = blockWidth * CGFloat(numberOfBlocks)
// 2
let xOffset = (frame.width - totalBlocksWidth) / 2
// 3
for i in 0..<numberOfBlocks {
  let block = SKSpriteNode(imageNamed: "block.png")
  block.position = CGPoint(x: xOffset + CGFloat(CGFloat(i) + 0.5) * blockWidth,y: frame.height * 0.8)

  block.physicsBody = SKPhysicsBody(rectangleOf: block.frame.size)
  block.physicsBody!.allowsRotation = false
  block.physicsBody!.friction = 0.0
  block.physicsBody!.affectedByGravity = false
  block.physicsBody!.isDynamic = false
  block.name = BlockCategoryName
  block.physicsBody!.categoryBitMask = BlockCategory
  block.zPosition = 2
  addChild(block)
}

这段代码创建了 8 块砖,并放在屏幕中央。

  1. 一些常量,比如砖块的数目以及它们的宽。
  2. 计算 x 偏移。这是第一块砖和屏幕左边沿的距离。用屏幕宽度减去8块砖的总宽度再除以 2。
  3. 创建砖块,设置每块砖的物理属性,并根据 blockWidth 和 xOffset 设置每块砖的位置。

Build & run,看看效果。

砖块准备好了。但为了监听球和砖之间的碰撞,你必须修改小球的 contactTestBitMask。仍然在 GameScene.swift 中,在 didMove(to:) 方法中添加一个新的 category:

ball.physicsBody!.contactTestBitMask = BottomCategory | BlockCategory

这句在 BottomCategory 和 BlockCategory 中间使用了一个 OR 位运算符。这会导致这两个 category 的对应位被设为 1 而其它位设为 0。现在,球和地板、砖发生碰撞都会通知委托对象。

断开竹砖

你已经能够检测到球和砖块之间的碰撞了,接下来为 GameScene.swift 添加一个助手方法,从场景中删除砖块:

func breakBlock(node: SKNode) {
  let particles = SKEmitterNode(fileNamed: "brokenPlatform")!
  particles.position = node.position
  particles.zPosition = 3
  addChild(particles)
  particles.run(SKAction.sequence([SKAction.wait(forDuration: 1.0),SKAction.removeFromParent()]))
  node.removeFromParent()
}

这个方法有一个 SKNode 参数。首先,它会用 brokenPlatform.sks 创建一个 SKEmitterNode 实例,将它的位置设置为该节点所在的位置。emitter 节点的 zPosition 是 3,这样粒子会显示在其它砖块的上层。当粒子发射器被添加到场景之后,node(竹砖)被移除。

注意:发射器节点是一种特殊的节点,用于显示用场景编辑器创建的粒子效果。要查看它是什么样子,请打开 brokenPlatform.sks,这是我为本教程专门创建的粒子系统。更多关于粒子系统的内容,请阅读我们的 2D iOS & tvOS 游戏教程一书,它对这部分内容有详细介绍。

接下来的事情就是处理委托通知。在 didBegin(_:) 方法最后添加:

if firstBody.categoryBitMask == BallCategory && secondBody.categoryBitMask == BlockCategory {
  breakBlock(node: secondBody.node!)
  //Todo: check if the game has been won
}

这段代码检查球和砖是否发生碰撞。如果发生,将 node 传递给 breakBlock(node:)方法,这样竹砖就会从屏幕上移除并显示粒子效果!

Build & run。当小球击中竹砖,竹砖会四分五裂。

添加玩法

现在所有游戏元素都就绪了,是时候让玩家体验输赢的感觉了。

理解状态机

大部分游戏逻辑都是受游戏状态控制的。例如,如果游戏处于“主菜单”状态,玩家将无法移动,如果游戏处于 play 状态,玩家才可以动。

大量简单的游戏通过在 update 循环中用布尔值来管理游戏状态。通过状态机,当游戏变得复杂时你可以更好地组织代码。

一个状态机通过单个的当前状态和一系列状态间转换规则来管理一组状态。当游戏状态发生改变,状态机会执行上一状态的退出方法和下一状态的进入方法。这些方法用于控制每个状态下的玩法。当状态成功改变,状态机会执行当前状态的 update 循环。

苹果从 iOS 9 开始引入 GameplayKit 框架,它内置了状态机支持,让我们的工作变得更加容易。GameplayKit 不是本教程讨论的范围,但现在,你将用到其中的两个类:GKStateMachine 和 GKState 类。

添加状态

这个游戏有 3 个状态:

  • WaitingForTap:游戏已经加载,等待玩家去玩。
  • Playing: 游戏正在玩的过程中。
  • GameOver: 游戏已经结束,要么赢要么输。

为了节省时间,这 3 个状态已经被添加到项目中(你可以查看 Game States 文件组)。要创建状态机,首先添加必要的 import 语句到 GameScene.swift 中:

import GameplayKit

然后,在 isFingerOnPaddle = false 声明变量:

lazy var gameState: GKStateMachine = GKStateMachine(states: [
  WaitingForTap(scene: self),Playing(scene: self),GameOver(scene: self)])

通过定义这个变量,你为游戏创建了一个状态机。注意,创建 GKStateMachine 时使用了一个 GKState 的数组。

等待点击状态:WaitingForTap

WaitingForTap 状态是游戏刚加载等待开始的状态。玩家会看到一个 Tap to Play 的提示,游戏等待触摸事件一发生就会进入 play 状态。

在 didMove(to:) 方法中添加代码:

let gameMessage = SKSpriteNode(imageNamed: "TapToPlay")
gameMessage.name = GameMessageName
gameMessage.position = CGPoint(x: frame.midX,y: frame.midY)
gameMessage.zPosition = 4
gameMessage.setScale(0.0)
addChild(gameMessage)

gameState.enter(WaitingForTap.self)

这里创建了一个 sprite 用来显示 Tap to Play 文字,后面则会用来显示 Game Over。然后告诉状态机进入 WaitingForTap 状态。

同时在 didMove(to:) 方法中删除这句:

ball.physicsBody!.applyImpulse(CGVector(dx: 2.0,dy: -2.0)) // REMOVE

你会将这句完后挪一些地方以便进入 play 状态。

打开 Game States 文件夹下的 WaitingForTap.swift 文件。将 didEnter(from:) 和 willExit(to:) 方法修改为:

override func didEnter(from prevIoUsstate: GKState?) {
  let scale = SKAction.scale(to: 1.0,duration: 0.25)
  scene.childNode(withName: GameMessageName)!.run(scale)
}

override func willExit(to nextState: GKState) {
  if nextState is Playing {
    let scale = SKAction.scale(to: 0,duration: 0.4)
    scene.childNode(withName: GameMessageName)!.run(scale)
  }
}

当游戏进入 WaitingForTap state 状态, didEnter(from:) 方法被调用。这个方法简单将 Tap to Play 放大显示,告诉玩家可以开始了。

当游戏退出 WaitingForTap 状态,进入 play 状态时,willExit(to:) 方法被调用,Tap to Play 会被缩小到 0。

Build & run,点击屏幕开始玩游戏!

好了,但当你点击屏幕,什么也不发生。那是下一个游戏状态的事情!

“游戏中”状态

Playging 状态会开始游戏,并管理小球的速度。

首先,回到 GameScene.swift,实现助手方法:

func randomFloat(from: CGFloat,to: CGFloat) -> CGFloat {
  let rand: CGFloat = CGFloat(Float(arc4random()) / 0xFFFFFFFF)
  return (rand) * (to - from) + from
}

这个助手方法返回一个位于两个参数之间的随机数。你会用它来让小球一开始的方向产生一些随机性。

现在,打开 Game States 文件夹下的 Playing.swift 文件,新增一个助手方法:

func randomDirection() -> CGFloat {
  let speedFactor: CGFloat = 3.0
  if scene.randomFloat(from: 0.0,to: 100.0) >= 50 {
    return -speedFactor
  } else {
    return speedFactor
  }
}

这些代码就像“猜硬币”一样,返回一个正数或者负数。这个方法为小球的初始方向变得随机。

然后在 didEnter(from:) 方法中添加代码:

if prevIoUsstate is WaitingForTap {
  let ball = scene.childNode(withName: BallCategoryName) as! SKSpriteNode
  ball.physicsBody!.applyImpulse(CGVector(dx: randomDirection(),dy: randomDirection()))
}

当游戏进入 Playing 状态,获取小球 sprite,调用它的 applyImpulse(_:) 方法,让它开始移动。

然后在 update(deltaTime:) 方法中添加代码:

let ball = scene.childNode(withName: BallCategoryName) as! SKSpriteNode
let maxSpeed: CGFloat = 400.0

let xSpeed = sqrt(ball.physicsBody!.veLocity.dx * ball.physicsBody!.veLocity.dx)
let ySpeed = sqrt(ball.physicsBody!.veLocity.dy * ball.physicsBody!.veLocity.dy)

let speed = sqrt(ball.physicsBody!.veLocity.dx * ball.physicsBody!.veLocity.dx + ball.physicsBody!.veLocity.dy * ball.physicsBody!.veLocity.dy)

if xSpeed <= 10.0 {
  ball.physicsBody!.applyImpulse(CGVector(dx: randomDirection(),dy: 0.0))
}
if ySpeed <= 10.0 {
  ball.physicsBody!.applyImpulse(CGVector(dx: 0.0,dy: randomDirection()))
}

if speed > maxSpeed {
  ball.physicsBody!.lineardamping = 0.4
} else {
  ball.physicsBody!.lineardamping = 0.0
}

update(deltaTime:) 方法会在每一帧的 Playing 状态时调用。获得小球对象,判断它的速度,即移动速度。如果 x 或 y 速度低于某个阈值,小球会卡在直上直下或直左直右移动的状态,如果这样,我们需要施加另外一个力,让它重新回到成一定角度的运动。

同时,在小球移动的过程中速度回增加。如果速度太快,你需要增加线型阻尼,以便球慢下来。

现在 Playing 状态准备就绪,是时候开始游戏了!

回到 GameScene.swift 将 touchesBegan(_:with:) 方法替换为:

override func touchesBegan(_ touches: Set<UITouch>,with event: UIEvent?) {
  switch gameState.currentState {
  case is WaitingForTap:
    gameState.enter(Playing.self)
    isFingerOnPaddle = true

  case is Playing:
    let touch = touches.first
    let touchLocation = touch!.location(in: self)

    if let body = physicsWorld.body(at: touchLocation) {
      if body.node!.name == PaddleCategoryName {
        isFingerOnPaddle = true
      }
    }

  default:
    break
  }
}

检查游戏的当前状态,并根据当前状态做相应的改变。然后,需要修改 update(_:) 方法为:

override func update(_ currentTime: TimeInterval) { gameState.update(deltaTime: currentTime) }

update(_:) 方法在每帧刷新时调用。在这里你调用了 Playing 状态的 update(deltaTime:) 方法来控制球的速度。

Build & run,点击屏幕,状态机开始生效了!

游戏结束状态

GameOver 状态在竹砖被摧毁,或者小球掉到屏幕底部后发生。

打开 Game States 文件夹下的 GameOver.swift 文件, 在 didEnter(from:) 方法添加:

if prevIoUsstate is Playing {
  let ball = scene.childNode(withName: BallCategoryName) as! SKSpriteNode
  ball.physicsBody!.lineardamping = 1.0
  scene.physicsWorld.gravity = CGVector(dx: 0.0,dy: -9.8)
}

当游戏进入 GameOver 状态,设置了小球的线性阻尼和重力加速度,调至小球掉到地板上并逐渐变慢。

这就是游戏结束状态。接下来实现判定输赢的代码!

有赢就有输

状态机也准备好了,游戏接近完成。现在你需要判断游戏的输赢。

打开 GameScene.swift,添加一个助手方法:

func isGameWon() -> Bool {
  var numberOfBricks = 0
  self.enumerateChildNodes(withName: BlockCategoryName) {
    node,stop in
    numberOfBricks = numberOfBricks + 1
  }
  return numberOfBricks == 0
}

这个方法通过遍历场景中的所有子节点检查场景中还剩下几块砖。对于每个子节点,判断名字是否叫做 BlockCategoryName。如果一块砖都没有了,判定玩家胜,返回返回 true。

在 gametState 属性声明下增加一个属性:

var gameWon : Bool = false {
  didSet {
    let gameOver = childNode(withName: GameMessageName) as! SKSpriteNode
    let textureName = gameWon ? "YouWon" : "GameOver"
    let texture = SKTexture(imageNamed: textureName)
    let actionSequence = SKAction.sequence([SKAction.setTexture(texture),SKAction.scale(to: 1.0,duration: 0.25)]) gameOver.run(actionSequence) } }

这里,你定义了一个 gameWon 变量,并定义了它的 didSet 属性观察器。这允许你观察属性值的改变,并作出处理。这里,你将 GameMessage 节点的贴图修改为 YouWon 或 GameOver,并显示到屏幕上。

注意:属性观察器有一个参数,你可以用来读取新值(在 willSet 中)和旧值(在 didSet 中),这样当变化发生时可以对二者进行比较。这 2 个参数默认叫做 newValue 和 oldValue,如果你没有提供替代的名字的话。如果你想进一步了解这方面的内容,请阅读Swift 编程语言:声明。

然后,修改 didBegin(_:) 方法。

首先,在 didBegin(_:) 方法一开始添加:

if gameState.currentState is Playing {
// 这里是原来的代码...
} // if 语句结束

这会防止游戏在未处于 Playing 状态时进行碰撞检测。

将这一句:

print("Hit bottom. First contact has been made.")

替换为:

gameState.enter(GameOver.self)
gameWon = false

当球碰到屏幕底部,游戏结束。

将 // Todo: 一句替换为:

if isGameWon() {
  gameState.enter(GameOver.self)
  gameWon = true
}

当所有的砖块被击碎后游戏胜利!

最后,在 touchesBegan(_:with:) 的 default 分支之前添加:

case is GameOver:
  let newScene = GameScene(fileNamed:"GameScene")
  newScene!.scaleMode = .aspectFit
  let reveal = SKTransition.flipHorizontal(withDuration: 0.5)
  self.view?.presentScene(newScene!,transition: reveal)

你的游戏终于完成了!Build & run!

终止触摸

现在游戏已经完成了,让我们给更上一层楼,为它添加一些新功能!你将在球发生碰撞以及砖块被击碎时增加一些音效。游戏结束时也会添加一小段音乐。最后,为小球添加一个专门的粒子发射器,当它反弹时,给它一段尾迹。

添加音效

为了节省时间,项目中已经添加了几个声音文件。首先,打开 GameScene.swift,添加如下常量,就在 gameWon 变量下边:

let blipSound = SKAction.playSoundFileNamed(“pongblip”,waitForCompletion: false)
let blipPaddleSound = SKAction.playSoundFileNamed(“paddleBlip”,waitForCompletion: false)
let bambooBreakSound = SKAction.playSoundFileNamed(“BambooBreak”,waitForCompletion: false)
let gameWonSound = SKAction.playSoundFileNamed(“game-won”,waitForCompletion: false)
let gameOverSound = SKAction.playSoundFileNamed(“game-over”,waitForCompletion: false)

上面定义了一堆的 SKAction 常量,每个加载不同的声音文件。因为在使用这些动作之前定义,它们会预加载进内存,防止在第一次播放时游戏出现卡顿。

然后,在 didMove(to:) 方法中,将设置小球的 contactTestBitMask 一句改成:

    ball.physicsBody!.contactTestBitMask = BottomCategory | BlockCategory | BorderCategory | PaddleCategory

没有任何新东西,你在小球的 contactTestBitMask 中添加了 BorderCategory 和 PaddleCategory 以便检测小球和屏幕边框、木板的碰撞。

修改 didBegin(_:) 方法,让它根据 firstBody 和 secondBody 播放对应的音效:

```swift // 1
if firstBody.categoryBitMask == BallCategory && secondBody.categoryBitMask == BorderCategory {
  run(blipSound)
}
 // 2
if firstBody.categoryBitMask == BallCategory && secondBody.categoryBitMask == PaddleCategory {
  run(blipPaddleSound)
}




<div class="se-preview-section-delimiter"></div>
  1. 当小球从屏幕边框弹开时播放 blipSound。
  2. 当碰到木板是播放 blipPaddleSound。

当然,当球击碎砖块时,你需要播放破碎音,在 breakBlock(node:) 方法顶部添加:

run(bambooBreakSound)

最后,在 gameWon 变量的 didSet 观察器中插入这句:

run(gameWon ? gameWonSound : gameOverSound)

还有一个地方要改。

我们需要为小球添加一个粒子系统,当它反弹时会留下一段火焰一样的尾迹!

在 didMove(to:) 方法中添加代码:

// 1
let trailNode = SKNode()
trailNode.zPosition = 1
addChild(trailNode)
// 2
let trail = SKEmitterNode(fileNamed: "BallTrail")!
// 3
trail.targetNode = trailNode
// 4
ball.addChild(trail)
  1. 新建一个 SKNode,用于作为粒子系统的 targetNode 属性。
  2. 从 BallTrail.sks 文件创建一个 SKEmitterNode。
  3. 将它的 targetNode 设置为 trailNode。这会将粒子固定,这样它们会留下一个痕迹,而不是跟随小球运动。
  4. 通过 addChild 方式将 SKEmitterNode 绑定到小球上。

这这样了——你已经完成了!Build & run,你的游戏再增强后是这个样子:

结束

你可以从这里下载最终完成后的项目。

这是一个简单的逃逸游戏的例子。一旦完成了它,你还可以增加更多的内容。你可以添加积分,或者给砖块一个生命值,添加各种类别的砖块,小球必须击中砖块几次才能摧毁它们。你可以添加一些会赠与奖励的砖块或者能够提升等级的砖块!

如果你想学习更多 Sprite Kit 的课程,你可以阅读我们的 2D iOS& tvOS 游戏教程。

这本书会教你所有关于制作 iOS & tvOS 游戏的知识——包括物理引擎、瓦片地图、粒子系统、以及如何通过一些美化和特效让你的游戏获得“加分”。

希望你喜欢本教程,如果有任何问题和评论,请在下面留言!

如何用 Sprite Kit 和 Swift 制作一个逃逸游戏-第二部分的更多相关文章

  1. ios – 当我的主线程阻塞时,如何获得断点/日志/增加的可见性?

    在对UI响应的永无止境的追求中,我想更多地了解主线程执行阻止操作的情况.我正在寻找某种“调试模式”或额外的代码,或钩子,或任何东西,从而我可以设置一个断点/日志/将被击中的东西,并允许我检查如果我的主要线程“自愿”用于I/O的块(或任何原因,真的),除了在循环结束时空闲.在过去,我已经使用循环观察器观察了跑步循环的时钟周期,这对于查看问题很有价值,但是在你可以检查的时候,为了做一个好主意,为时已晚

  2. 如何用 Sprite Kit 和 Swift 制作一个逃逸游戏-第二部分

    毕竟这是一个逃逸游戏嘛!emitter节点的zPosition是3,这样粒子会显示在其它砖块的上层。这些方法用于控制每个状态下的玩法。当状态成功改变,状态机会执行当前状态的update循环。注意,创建GKStateMachine时使用了一个GKState的数组。打开GameStates文件夹下的WaitingForTap.swift文件。回到GameScene.swift将touchesBegan方法替换为:检查游戏的当前状态,并根据当前状态做相应的改变。游戏结束状态GameOver状态在竹砖被摧毁,或者

  3. javascript与有限状态机详解

    有限状态机(Finite-state machine)是一个非常有用的模型,可以模拟世界上大部分事物,下面是使用示例

  4. 任何人都可以推荐一个.Net开源替代Windows Workflow?

    .Net堆栈中的WindowsWorkflow有哪些替代方案?

  5. 正则表达式 – 正则表达式的简单示例转换为状态机?

    我使用了很多正则表达式,我想确保我再也不会使用“不适当的”。它不显示如何进行贪婪/非正常匹配,回溯,匹配一行和状态机的其他更深奥的功能,容易被RE语法处理。执行单线RE可以做的实际有限状态机器代码通常是非常长而复杂的。你可以做的最好的事情是获取一些特定简单语言的lex/yacc代码的副本,并查看它生成的代码。它不漂亮,但它可能会给你一个更好的想法,如何工作。

  6. 正则表达式转DFA

    为了给出这种规则的形式化表示,我们引入了一种范式。BNF范式经常被用于理论研究,但是更加实用的是正则表达式。而且,直接使用正则表达式进行匹配配的话,不仅工作量大,而且速度缓慢。

  7. 一个正则表达式引擎的设计和实施1-如何通过NFA识别字符串

    更多更详实内容,请参看:如何进入google,算法面试技能全面提升指南上一节,我们通过汤普森构造,实现了一个叫做非确定性有限状态自动机的数据结构:这个状态机对应的正则表达式是:D*.D|D.D*。我们看看,当给定一个字符串:”1.2”,如何通过上面的状态机来判定,给定的字符串是否符合指定的正则表达式。但由于还有字符要输入,所以状态机需要继续运行。

  8. 自己动手写一个轻巧,高效的正则表达式引擎

    然而,在ThompsonNFA的实现中,没有这种非主流的的正则表达式。这两人税后从事Unix开发,引入了正则表达式。最简单的正则表达式是一个文字字母。现在为止描述的语法只是传统Unixegrep正则表达式语法的子集。新的的正则表达式设施,像Perl当中,已经添加了许多新的运算符和专业序列。正则表达式当中一项常用而有用的扩展是后向引用。正则表达式的NFA由子串的局部NFA构造而成,每个操作符的构造方式是不同的。

  9. 微信公共平台与正则表达式

    其实很无脑,基本上就是看一张html,写几个正则表达式就好了。所以需要识别这个正则表达式就需要状态机,状态机用的很广泛,可以对某些复杂逻辑的程序进行简化,网络协议中TCP就需要专门的状态机进行描述,不然大家都会晕了。

  10. 正则表达式DFA构造方法

    BNF范式经常被用于理论研究,但是更加实用的是正则表达式。正则表达式还有各种各样的其他规则来简化我们的书写,不过由于本文并不是“精通正则表达式”,因此我们只保留若干比较本质的操作来进行词法分析原理的描述。而且,直接使用正则表达式进行匹配配的话,不仅工作量大,而且速度缓慢。

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部