Calling Swift-Class initWith.. in Objective-C - objective-c

My Swift-Class defines an initWith.. method by the following code
convenience init(controlType: ApplePencilControlType) {
self.init(frame: CGRect())
type = controlType
self.frame = self.controlFrame
if type == .zoom {
zoomSlider = UISlider(frame: CGRect(x: 10, y: 10, width: 100, height: 20))
if let slider = zoomSlider {
self.addSubview(slider)
}
}
else if type == .toLeft || type == .toRight {
imageView = UIImageView(frame: CGRect(x: 5, y: 5, width: 20, height: 20))
if let imgView = imageView {
if let img = type.image {
imgView.image = img
}
self.addSubview(imgView)
}
}
}
Trying to call this method by the following Objective-C Code makes Xcode show up an error.
- (void)presentOrHidePencilControls {
self.apToLeft = [[ApplePencilControl alloc] initWithControlType:ApplePencilControlTypeToLeft];
}
The error is No visible #interface for 'ApplePencilControl' declares the selector 'initWithControlType:'
What have I to do, so i can call this initializer from Objective-C? The "Project/Modul-Swift.h" is already imported.

I had to insert #objc and : Int to my enum definition in the same class.

Related

React Native native UI component width and height

I'm creating a native UI component on iOS and I want its size to expand according to the content size.
It seems like I must set a fixed width and height in order for the view to be rendered. Any idea how to solve it?
// JS
import React from 'react';
import { View, requireNativeComponent } from 'react-native';
class StyledText extends React.Component {
render() {
return (
<View style={this.props.style}>
// without the height and width the compnent won't show up
<StyledLabelReactBridge styledText={'some text'} style={{height: 100, width: 100, backgroundColor: 'red'}}/>
</View>
);
}
}
StyledText.propTypes = {
styledText: React.PropTypes.string,
style: View.propTypes.style
};
const StyledLabelReactBridge = requireNativeComponent('StyledLabelReactBridge', StyledText);
module.exports = StyledText;
// objective-C
#implementation StyledLabelReactBridgeManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
return [[NewStyledLabel alloc] init];
}
RCT_CUSTOM_VIEW_PROPERTY(styledText, NSString, NewStyledLabel)
{
if (![json isKindOfClass:[NSString class]])
return;
[view setStyledText:[NewStyledText textFromXHTML:json]];
}
#end
You need to override reactSetFrame in xcode to receive content size change.
#import "React/UIView+React.h"
#implementation YourView {
- (void)reactSetFrame:(CGRect)frame {
[super reactSetFrame: frame];
/* everytime content size changes, you will get its frame here. */
}
}
first you should create a subclass of RCTShadowView like
#import <React/RCTShadowView.h>
#interface RNGuessLikeContainerShadowView : RCTShadowView
#end
#implementation RNGuessLikeContainerShadowView
- (void)setLocalData:(NSObject *)localData {
if ([localData isKindOfClass:[NSNumber class]]) {
[self setIntrinsicContentSize:CGSizeMake(UIScreen.mainScreen.bounds.size.width, ((NSNumber *)localData).floatValue)];
}
}
#end
then create subclass of RCTViewManager and return shadowview and view of you custom class instance
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerUtils.h>
#interface RNGuessLikeModule: RCTViewManager <RNGuessLikeContainerViewHeightUpdater>
#end
#implementation RNGuessLikeModule
RCT_EXPORT_MODULE(RNGuessLikeModule)
RCT_EXPORT_VIEW_PROPERTY(objects, NSString);
- (UIView *)view {
RNGuessLikeContainerView *_view = [RNGuessLikeContainerView new];
_view.delegate = self;
return _view;
}
- (RCTShadowView *)shadowView {
return [RNGuessLikeContainerShadowView new];
}
- (void)didUpdateWithHeight:(CGFloat)height view:(RNGuessLikeContainerView *)view {
RCTExecuteOnUIManagerQueue(^{
RCTShadowView *shadowView = [self.bridge.uiManager shadowViewForReactTag:view.reactTag];
[shadowView setLocalData:#(height)];
[self.bridge.uiManager setNeedsLayout];
});
}
#end
and in mine code i set custom native ui view delegate to RNGuessLikeModule which is subclass of RCTViewManager,
and you can caculate size in you custom view when data from rn module passed
#objc
public protocol RNGuessLikeContainerViewHeightUpdater {
func didUpdate(height: CGFloat, view: RNGuessLikeContainerView)
}
public final class RNGuessLikeContainerView: UIView, GuessLikeItemsComponentContainer {
#objc
public var objects: String? {
didSet {
if let _objects = objects,
let _data = _objects.data(using: .utf8, allowLossyConversion: true) {
reload(objects: _data)
}
}
}
#objc
public weak var delegate: RNGuessLikeContainerViewHeightUpdater?
public var controller: UIViewController {
return reactViewController()
}
public var guessLikeSceneType: GuessLikeSceneType = .邀好友赚现金红包
public var guessLikeTitle: String?
public var guessLikeItems: [GuessLikeItemsSectionSubItem] = []
public var routerInfo: String?
#objc
public private(set) var guessLikeHeight: CGFloat = 0
lazy var backend = GuessLikeItemsComponentContainerBackend(parent: self)
public lazy var guessLikeContainer: UICollectionView = {
let _container = createGuessLikeContainer()
_container.dataSource = backend
_container.delegate = backend
addSubview(_container)
return _container
}()
override public func layoutSubviews() {
super.layoutSubviews()
guessLikeContainer.frame = bounds
}
public func reload(objects: Data) {
precondition(pthread_main_np() != 0, "RNGuessLikeContainerView reload method should be called on main thread")
do {
let _items = try JSONDecoder().decode([ItemListModel].self, from: objects)
guessLikeItems = GuessLikeItemsSectionItem(list: _items).items
guessLikeContainer.reloadData()
updateHeight()
} catch {
debugPrint(error)
}
}
public func append(objects: Data) {
precondition(pthread_main_np() != 0, "RNGuessLikeContainerView append method should be called on main thread")
if let _list = try? JSONDecoder().decode([ItemListModel].self, from: objects) {
let _items = GuessLikeItemsSectionItem(list: _list).items
guessLikeItems.append(contentsOf: _items)
guessLikeContainer.reloadData()
updateHeight()
}
}
func updateHeight() {
if guessLikeItems.isEmpty {
guessLikeHeight = 0
} else {
var leftHeight: CGFloat = 0
var rightHeight: CGFloat = 0
for (index, item) in guessLikeItems.enumerated() {
if index % 2 == 0 {
leftHeight += item.height + 10.0
} else {
rightHeight += item.height + 10.0
}
}
let sectionHeaderHeight: CGFloat = 50.0
guessLikeHeight = max(leftHeight, rightHeight) + sectionHeaderHeight
}
if let _delegate = delegate {
_delegate.didUpdate(height: guessLikeHeight, view: self)
}
}
public override var intrinsicContentSize: CGSize {
return CGSize(width: UIScreen.main.bounds.width, height: guessLikeHeight)
}
}
then find shadowview binded to your custom ui view and update intrinsicContentSize
finaly call [self.bridge.uiManager setNeedsLayout]
may help you
#implementation SNBFundCardViewManager
RCT_EXPORT_MODULE(FundCard)
- (UIView *)view
{
return [[SNBFundHomeFundCardCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#""];
}
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
RCT_CUSTOM_VIEW_PROPERTY(data, NSDictionary, SNBFundHomeFundCardCell)
{
view.rnData = json;
// 自己撑起高度
CGFloat height = [view.vm getCellHeight];
[self.bridge.uiManager setIntrinsicContentSize:CGSizeMake(UIViewNoIntrinsicMetric, height) forView:view];
}
Well, couldn't find 'auto' like behavior, how ever, setting the component to:
{{ width: '100%', height: '100%}}
Makes it expand (and shrink) according to the parent, which is good enough for my use case. It's a shame that setting 'flex: 1' doesn't have the same effect.

Buttons not clickable when inside a StackView inside a StackView

I have a UIView Subclass which presents three buttons arranged with two above one. I use a StackView to arrange the top two buttons, and the bottom arranged view is just a single button. The problem is that the button added as an arrangedSubview to the root StackView receives clicks, while the buttons inside of the StackView in the StackView do not.
(note: dependencies should not be affecting anything. DynamicButton is just a cocoapod UIButton subclass. InsetView is my own UIView subclass that embeds the buttons in a view with constraints. And pinTo is just a UIView extension that adds pinning constraints to the view. These things shouldn't be the bug given that the bottom button receives clicks and is under the same conditions as the top two buttons.)
class PathContentView: UIView {
let previousButton: DynamicButton = {
let r = DynamicButton(style: .caretLeft)
r.lineWidth = 3
r.strokeColor = .white
r.highlightStokeColor = .gray
return r
}()
let nextButton: DynamicButton = {
let r = DynamicButton(style: .caretRight)
r.lineWidth = 3
r.strokeColor = .white
r.highlightStokeColor = .gray
return r
}()
let deleteButton: DynamicButton = {
let r = DynamicButton(style: .close)
r.lineWidth = 3
r.strokeColor = .white
r.highlightStokeColor = .gray
return r
}()
init() {
super.init(frame: .zero)
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
private func setup() {
// button components
let deleteButtonHolder = InsetView(width: 25, height: 25, view: deleteButton)
let previousButtonHolder = InsetView(width: 25, height: 25, view: previousButton)
let nextButtonHolder = InsetView(width: 25, height: 25, view: nextButton)
let rootStackView = UIStackView()
let topSectionStackView = UIStackView()
topSectionStackView.distribution = .fillEqually
topSectionStackView.alignment = .center
topSectionStackView.spacing = 20
topSectionStackView.axis = .horizontal
rootStackView.axis = .vertical
rootStackView.distribution = .fillEqually
rootStackView.alignment = .fill
rootStackView.isLayoutMarginsRelativeArrangement = true
rootStackView.layoutMargins = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
addSubview(rootStackView)
topSectionStackView.addArrangedSubview(previousButtonHolder)
topSectionStackView.addArrangedSubview(nextButtonHolder)
rootStackView.addArrangedSubview(deleteButtonHolder)
rootStackView.addArrangedSubview(topSectionStackView)
rootStackView.pinTo(superView: self)
rootStackView.isUserInteractionEnabled = true
topSectionStackView.isUserInteractionEnabled = true
}
required init?(coder aDecoder: NSCoder) {
fatalError()
}
func tapped() {
print("tapped")
}
}

func collectionViewContentSize in Swift3

I have update my Project to Swift3 in Xcode 8 and it comes this error but I have no idea what I can make there. I have already search in google but nothing founded.
Have anyone an Idea what I can make ?
Here the Error:
Method 'collectionViewContentSize()' with Objective-C selector 'collectionViewContentSize' conflicts with getter for 'collectionViewContentSize' from superclass 'UICollectionViewLayout' with the same Objective-C selector
public func collectionViewContentSize() -> CGSize {
let numberOfSections = collectionView?.numberOfSections
if numberOfSections == 0 {
return CGSize.zero
}
var contentSize = collectionView?.bounds.size
contentSize?.height = CGFloat(columnHeights[0])
return contentSize!
}
I had something similar but I was overriding collectionViewContentSize()
override func collectionViewContentSize() -> CGSize {
let collection = collectionView!
let width = collection.bounds.size.width
let height = max(posYColumn1, posYColumn2)
return CGSize(width: width, height: height)
}
I Downloaded XCode 8 beta 4 today and have had to change it to:
override var collectionViewContentSize: CGSize {
let collection = collectionView!
let width = collection.bounds.size.width
let height = max(posYColumn1, posYColumn2)
return CGSize(width: width, height: height)
}

Using sprite sheets in xcode

I'm trying to animate my game using a sprite sheet. How would I go about cutting out each sprite from the sprite sheet and using the sprite in xcode? I'm currently using obj -c. I read somewhere that i need to use a frame work, cocoa2d, in order to do this?
In sprite kit you can cut part of a texture out using SKTexture(rect: inTexture:) initializer. This is a helper class which manages an evenly spaced sprite sheet and can cut out a texture at a given row and column. It is used like So
let sheet=SpriteSheet(texture: SKTexture(imageNamed: "spritesheet"), rows: 1, columns: 11, spacing: 1, margin: 1)
let sprite=SKSpriteNode(texture: sheet.textureForColumn(0, row: 0))
Here is the full code
//
// SpriteSheet.swift
//
import SpriteKit
class SpriteSheet {
let texture: SKTexture
let rows: Int
let columns: Int
var margin: CGFloat=0
var spacing: CGFloat=0
var frameSize: CGSize {
return CGSize(width: (self.texture.size().width-(self.margin*2+self.spacing*CGFloat(self.columns-1)))/CGFloat(self.columns),
height: (self.texture.size().height-(self.margin*2+self.spacing*CGFloat(self.rows-1)))/CGFloat(self.rows))
}
init(texture: SKTexture, rows: Int, columns: Int, spacing: CGFloat, margin: CGFloat) {
self.texture=texture
self.rows=rows
self.columns=columns
self.spacing=spacing
self.margin=margin
}
convenience init(texture: SKTexture, rows: Int, columns: Int) {
self.init(texture: texture, rows: rows, columns: columns, spacing: 0, margin: 0)
}
func textureForColumn(column: Int, row: Int)->SKTexture? {
if !(0...self.rows ~= row && 0...self.columns ~= column) {
//location is out of bounds
return nil
}
var textureRect=CGRect(x: self.margin+CGFloat(column)*(self.frameSize.width+self.spacing)-self.spacing,
y: self.margin+CGFloat(row)*(self.frameSize.height+self.spacing)-self.spacing,
width: self.frameSize.width,
height: self.frameSize.height)
textureRect=CGRect(x: textureRect.origin.x/self.texture.size().width, y: textureRect.origin.y/self.texture.size().height,
width: textureRect.size.width/self.texture.size().width, height: textureRect.size.height/self.texture.size().height)
return SKTexture(rect: textureRect, inTexture: self.texture)
}
}
The margin property is the gap between the edge of the image and the sprites. The spacing is the gap between each sprite. The fameSize is the size each sprite will be. This image explains it:
Since the original question was tagged as Objective-C, here's a rough version of this SpriteSheet class in that language. Hope this is helpful:
#import "SpriteSheet.h"
#interface SpriteSheet ()
#property (nonatomic, strong) SKTexture *texture;
#property (nonatomic) NSInteger rows;
#property (nonatomic) NSInteger cols;
#property (nonatomic) CGFloat margin;
#property (nonatomic) CGFloat spacing;
#property (nonatomic, getter=frameSize) CGSize frameSize;
#end
#implementation SpriteSheet
- (instancetype)initWithTextureName:(NSString *)name rows:(NSInteger)rows cols:(NSInteger)cols margin:(CGFloat)margin spacing:(CGFloat)spacing {
SKTexture *texture = [SKTexture textureWithImageNamed:name];
return [self initWithTexture:texture rows:rows cols:cols margin:margin spacing:spacing];
}
- (instancetype)initWithTexture:(SKTexture *)texture rows:(NSInteger)rows cols:(NSInteger)cols {
return [self initWithTexture:texture rows:rows cols:cols margin:0 spacing:0];
}
- (instancetype)initWithTexture:(SKTexture *)texture rows:(NSInteger)rows cols:(NSInteger)cols margin:(CGFloat)margin spacing:(CGFloat)spacing {
if (self == [super init]) {
_texture = texture;
_rows = rows;
_cols = cols;
_margin = margin;
_spacing = spacing;
_frameSize = [self frameSize];
}
return self;
}
- (CGSize)frameSize {
CGSize newSize = CGSizeMake((self.texture.size.width - (self.margin * 2.0 + self.spacing * ((CGFloat)self.cols - 1.0))) / ((CGFloat)self.cols),
(self.texture.size.height - ((self.margin * 2.0) + (self.spacing * ((CGFloat)self.rows - 1.0))) / ((CGFloat)self.rows)));
return newSize;
}
- (SKTexture *)textureForColumn:(NSInteger)column andRow:(NSInteger)row {
if (column >= (self.cols) || row >= (self.rows)) {
NSLog(#"Asking for row or col greater than spritesheet");
return nil;
}
CGRect textureRect = CGRectMake(self.margin + (column * self.frameSize.width + self.spacing) - self.spacing,
self.margin + (row * self.frameSize.width + self.spacing) - self.spacing, // note using width here
self.frameSize.width,
self.frameSize.height);
textureRect = CGRectMake(textureRect.origin.x / self.texture.size.width, textureRect.origin.y / self.texture.size.height, textureRect.size.width / self.texture.size.width, textureRect.size.height/self.texture.size.height);
return [SKTexture textureWithRect:textureRect inTexture:self.texture];
}
I am adding this into a separate answer, because it contains two important things, that I found:
First :
var textureRect=CGRect(x: self.margin+CGFloat(column)*(self.frameSize.width+self.spacing)-self.spacing,
y: self.margin+CGFloat(row)*(self.frameSize.width+self.spacing)-self.spacing,
width: self.frameSize.width,
height: self.frameSize.height)
This code in Swift and its Objective-C counterpart both have a bug. The self.frameSize.width is used for both row and column calculations. The height needs to be used for column.
Second :
The coordinate system for SKTexture places its (0,0) origin at the bottom left corner of the image, this has to be considered when making your sprites or the code needs to be altered.
For example You can get all the frames of the sprite from top left corner to bottom right corner of the sprite like this:
var anim = [SKTexture]()
for row in (0..<self.rows).reversed() {
for column in 0..<self.columns {
if let frame = textureForColumn(column: column, row: row) {
anim.append(frame)
}
}
}
PS. I don't have the much experience with SpriteKit, so if there are any mistakes in my answer, please correct me.
I did a fix for getting sprites from top to bottom, left to right.
Also added a totalFrames so if you don't have a sprite with all frames, you can set the total frames so the array only contains the sprites, no blank sprites.
//
// SpriteSheet.swift
//
import SpriteKit
class SpriteSheet {
let texture: SKTexture
let rows: Int
let columns: Int
var margin: CGFloat=0
var spacing: CGFloat=0
var frameSize: CGSize {
return CGSize(width: (self.texture.size().width-(self.margin*2+self.spacing*CGFloat(self.columns-1)))/CGFloat(self.columns),
height: (self.texture.size().height-(self.margin*2+self.spacing*CGFloat(self.rows-1)))/CGFloat(self.rows))
}
init(texture: SKTexture, rows: Int, columns: Int, spacing: CGFloat, margin: CGFloat) {
self.texture=texture
self.rows=rows
self.columns=columns
self.spacing=spacing
self.margin=margin
}
convenience init(texture: SKTexture, rows: Int, columns: Int) {
self.init(texture: texture, rows: rows, columns: columns, spacing: 0, margin: 0)
}
func textureForColumn(column: Int, row: Int)->SKTexture? {
if !(0...self.rows ~= row && 0...self.columns ~= column) {
return nil
}
var textureRect = CGRect(x: self.margin + CGFloat(column) * (self.frameSize.width+self.spacing)-self.spacing, y: self.margin + CGFloat(self.rows - row - 1) * (self.frameSize.height+self.spacing)-self.spacing,
width: self.frameSize.width,
height: self.frameSize.height)
textureRect = CGRect(x: textureRect.origin.x/self.texture.size().width, y: textureRect.origin.y/self.texture.size().height,
width: textureRect.size.width/self.texture.size().width, height: textureRect.size.height/self.texture.size().height)
return SKTexture(rect: textureRect, in: self.texture)
}
}
To call, just add the animation like this:
fileprivate let framesOpening: [SKTexture] = {
let totalFrames = 28
let rows = 6
let columns = 5
let sheet = SpriteSheet(texture: SKTexture(imageNamed: "GETREADY"), rows: rows, columns: columns, spacing: 0, margin: 0)
var frames = [SKTexture]()
var count = 0
for row in (0..<rows) {
for column in (0..<columns){
if count < totalFrames {
if let texture = sheet.textureForColumn(column: column, row: row) {
frames.append(texture)
}
}
count+=1
}
}
return frames
}()
and call it
let sprite1 = SKSpriteNode(texture: framesOpening.first)
let openingAnimation: SKAction = SKAction.animate(with: framesOpening, timePerFrame: 0.2, resize: false, restore: true)
sprite1.position = CGPoint(x: frame.midX, y: frame.midY)
sprite1.zPosition = 2000
self.addChild(sprite1)
sprite1.run(SKAction.repeatForever(openingAnimation))

UIButton help in Swift

Im trying to program a UIButton that performs that prints a message to the console. I can see the button and touch it but as soon as I touch it my app stops running and the console shows the following error:
Game[2743:63724] -[Game.GameScene buttonAction:]: unrecognized selector sent to instance 0x7a11ad00
2014-09-15 17:51:06.106 Game[2743:63724] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[GameGameScene buttonAction:]: unrecognized selector sent to instance 0x7a11ad00'
this is my code:
let imageButton = UIImage(named: "playbutton2") as UIImage
let buttonPlay = UIButton.buttonWithType(UIButtonType.Custom) as UIButton
buttonPlay.frame = CGRectMake(screenSize.width / 2 , screenSize.height / 2, 100, 100)
buttonPlay.setImage(imageButton, forState: .Normal)
buttonPlay.addTarget(self, action: Selector("buttonAction:"), forControlEvents: UIControlEvents.TouchUpInside)
buttonPlay.tag = 22
self.view.addSubview(buttonPlay)
and
func buttonAction(sender:UIButton!) {
println("Button tapped")
}
------- COMPLETE CODE ---------
import SpriteKit
class GameScene: SKScene {
var skyColor = SKColor()
var bird = SKSpriteNode()
var moving = SKNode()
var titleLabelNode = SKLabelNode()
var title = NSString()
let imageButton = UIImage(named: "playbutton2") as UIImage
let screenSize: CGRect = UIScreen.mainScreen().bounds
override func didMoveToView(view: SKView) {
/* Setup your scene here */
self.addChild(moving)
skyColor = SKColor(red: 113.0/255.0, green: 197.0/255.0, blue: 207.0/255.0, alpha: 1.0)
self.backgroundColor = skyColor
var birdTexture1 = SKTexture(imageNamed: "Bird1")
birdTexture1.filteringMode = SKTextureFilteringMode.Nearest
var birdTexture2 = SKTexture(imageNamed: "Bird2")
birdTexture2.filteringMode = SKTextureFilteringMode.Nearest
var animation = SKAction.animateWithTextures([birdTexture1, birdTexture2], timePerFrame: 0.2)
var flap = SKAction.repeatActionForever(animation)
bird = SKSpriteNode(texture: birdTexture1)
bird.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame) + 150)
bird.runAction(flap)
bird.physicsBody = SKPhysicsBody(circleOfRadius: bird.size.height/2.0)
bird.physicsBody.dynamic = false
self.addChild(bird)
var groundTexture = SKTexture(imageNamed: "Ground")
groundTexture.filteringMode = SKTextureFilteringMode.Nearest
var moveGroundSprite = SKAction.moveByX(-groundTexture.size().width, y: 0, duration: NSTimeInterval(0.01 * groundTexture.size().width))
var resetGroundSprite = SKAction.moveByX(groundTexture.size().width, y: 0, duration: 0)
var moveGroundSpritesForever = SKAction.repeatActionForever(SKAction.sequence([moveGroundSprite, resetGroundSprite]))
for var i:CGFloat = 0; i<2 + self.frame.size.width / (groundTexture.size().width); ++i {
var sprite = SKSpriteNode(texture: groundTexture)
sprite.position = CGPointMake(i * sprite.size.width, sprite.size.height / 2)
sprite.runAction(moveGroundSpritesForever)
moving.addChild(sprite)
}
title = "Swing Bird"
titleLabelNode.fontName = "Helvetica-Bold"
titleLabelNode.fontSize = 80
//titleLabelNode.fontColor = SKColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.)
titleLabelNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) + 50)
titleLabelNode.text = "\(title)"
addChild(titleLabelNode)
let buttonPlay = UIButton.buttonWithType(UIButtonType.Custom) as UIButton
buttonPlay.frame = CGRectMake(screenSize.width / 2 , screenSize.height / 2, 100, 100)
buttonPlay.setImage(imageButton, forState: .Normal)
buttonPlay.addTarget(self, action: Selector("buttonAction:"), forControlEvents: UIControlEvents.TouchUpInside)
buttonPlay.tag = 22
self.view.addSubview(buttonPlay)
func buttonAction(sender:UIButton!) {
println("Button tapped")
}
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
Your function buttonAction is defined at the wrong level. It is currently a function inside didMoveToView instead of a function of the class GameScene.
You can fix it like this:
class GameScene: SKScene {
...
// Move the function here!
func buttonAction(sender:UIButton!) {
println("Button tapped")
}
override func didMoveToView(view: SKView) {
...