Whilst attempting to create a set, I get the error stating "Cannot convert value of type '[Int]' to specified type 'Set'". This occurs even though I write the code exactly as in the DD: https://developer.apple.com/documentation/swift/set
var intSet2 : Set = [2, 3, 5, 7]
// Cannot convert value of type '[Int]' to specified type 'Set'
I have now switched to 'NSSet' (which I found by accidence) and now it appears to work. How come using normal 'Set' does not work? When I go to the DD of NSSet it says: "An object representing a static, unordered, uniquing collection, for use instead of a Set constant in cases that require reference semantics." Is this about reference types? The DD also states that arrays are value types. I'm at a loss as to when to use Set or NSSet (or even NSMutableSet for that manner).
var intSet2 : NSSet = [2, 3, 5, 7]
// Works
Lastly, when I try to convert an array of colors with type [CardColor] to a Set or NSset, I receive error message stating: "Cannot convert value of type '[CardColor]' to specified type 'NSSet'.
let colorCheck = selectedCards.map { $0.color }
var colorCheckSet : NSSet = colorCheck
// Cannot convert value of type '[CardColor]' to specified type 'NSSet'
Thanks for your help in advance.
Set model:
import Foundation
class Set {
// MARK: properties
var deck = [Card]()
var tableCards = [Card]()
var matchedCards = [Card]()
var selectedCards: [Card] {
get {
var cards = [Card]()
for card in tableCards.indices {
if tableCards[card].isSelected == true {
cards.append(tableCards[card])
}
}
return cards
}
}
var unmatchedCards = 12
var score = 0
// MARK: functions
// Selects the card. If this is the third card to be selected, proceeds to check for matches
func selectCard(at index: Int) {
if tableCards[index].isSelected == false {
if selectedCards.count < 3 {
tableCards[index].isSelected = true
if selectedCards.count == 3 {
checkIfCardsMatch()
}
}
}
else if tableCards[index].isSelected == true {
tableCards[index].isSelected = false
}
}
func checkIfCardsMatch() {
let colorCheck = selectedCards.map { $0.color }
var colorCheckSet : NSSet = colorCheck
// Cannot convert value of type '[CardColor]' to specified type 'NSSet'
var intSet2 : Set = [2, 3, 5, 7]
// Cannot convert value of type '[Int]' to specified type 'Set'
// for item in colorCheck {
// colorCheckSet.insert()
// }
// let symbolCheck: Set = selectedCards.map() { $0.symbol }
// let numberCheck: Set = selectedCards.map() { $0.number }
// let shadingCheck: Set = selectedCards.map() { $0.shading }
}
// MARK: functions
func dealThreeMoreCards() {
if unmatchedCards <= 21 {
unmatchedCards += 3
}
print(unmatchedCards)
}
//MARK: initialization
init() {
for cardcolor in CardColor.allCases {
for cardsymbol in CardSymbol.allCases {
for cardnumber in CardNumber.allCases {
for cardshading in CardShading.allCases {
let card = Card(initcolor: cardcolor, initsymbol: cardsymbol, initnumber: cardnumber, initshading: cardshading)
deck.append(card)
}
}
}
}
}
}
Card model:
import Foundation
struct Card {
var identifier: Int = 0
var isSelected = false
var color: CardColor
var symbol: CardSymbol
var number: CardNumber
var shading: CardShading
static var identifierFactory = 0
init(initcolor: CardColor, initsymbol: CardSymbol, initnumber: CardNumber, initshading: CardShading){
color = initcolor
symbol = initsymbol
number = initnumber
shading = initshading
Card.identifierFactory += 1
self.identifier = Card.identifierFactory
}
}
enum CardColor: Int, CaseIterable {
case red = 1
case green = 2
case purple = 3
// static let all = [cardColor.red, cardColor.green, cardColor.purple]
}
enum CardSymbol: Int, CaseIterable {
case ovals = 1
case squiggles = 2
case diamonds = 3
// static let all = [cardSymbol.ovals, cardSymbol.squiggles, cardSymbol.diamonds]
}
enum CardNumber: Int, CaseIterable {
case one = 1
case two = 2
case three = 3
// static let all = [cardNumber.one, cardNumber.two, cardNumber.three]
}
enum CardShading: Int, CaseIterable {
case solid = 1
case open = 2
case striped = 3
// static let all = [cardShading.solid, cardShading.open, cardShading.striped]
}
// Not every Card variable has been included below. Could cause issues later.
extension Card: Hashable {
static func == (lhs: Card, rhs: Card) -> Bool {
return lhs.identifier == rhs.identifier &&
lhs.isSelected == rhs.isSelected &&
lhs.color == rhs.color &&
lhs.symbol == rhs.symbol &&
lhs.number == rhs.number &&
lhs.shading == rhs.shading
}
func hash(into hasher: inout Hasher) {
hasher.combine(identifier)
hasher.combine(isSelected)
hasher.combine(color)
hasher.combine(symbol)
hasher.combine(number)
hasher.combine(shading)
}
}
Related
I have a spring boot based micro-service endpoint which produces protobuf. Here is the .proto definition:
syntax = "proto3";
package TournamentFilterPackage;
import "google/protobuf/any.proto";
option java_package = "com.mycompany.service.tournament.proto";
option java_outer_classname = "TournamentCompleteData";
message TournamentData {
repeated TournamentRecord tournamentRecords = 1;
}
message TournamentRecord {
int64 id = 1;
Date start = 2;
float prize = 3;
string name = 4;
string speed = 5;
string type = 6;
float buyIn = 7;
int32 noOfParticipants = 8;
string status = 9;
}
message Date {
int32 year = 1;
int32 month = 2;
int32 day = 3;
}
message PokerResponseProto {
repeated int32 errorCodes = 1;
google.protobuf.Any responseObject = 2;
}
Here is my rest controller:
#ApiOperation(value="Complete Tournament Data", response = PokerResponseProto.class)
#GetMapping(value="/tournaments/completedata", produces = "application/x-protobuf")
public ResponseEntity<PokerResponseProto> getCompleteTournamentdata() {
if (logger.isInfoEnabled()) {
logger.info("BEGIN::/lobby/api/v1//tournaments/completedata/ " + "GET ::");
}
List<TournamentTypeResponseDto> tournamentTypeResponseDtos = new ArrayList<>();
List<TournamentRecord> tournamentRecords = new ArrayList<>();
ResponseEntity<PokerResponseProto> pokerResponse = null;
try {
tournamentTypeResponseDtos =
tournamentTypeDataService.getCompleteTournamentList();
for(TournamentTypeResponseDto t:tournamentTypeResponseDtos) {
tournamentRecords.add(controllerUtils.buildTournamentRecord(t));
}
TournamentData.Builder tournamentDataBuilder =
TournamentData.newBuilder().addAllTournamentRecords(tournamentRecords);
pokerResponse = new ResponseEntity<>(BKPokerResponseProto.newBuilder()
.setResponseObject(Any.pack(tournamentDataBuilder.build()))
.build(),
HttpStatus.OK);
logger.info("pokerResponse: {}", pokerResponse.toString());
} catch (PokerException pe) {
if (this.logger.isErrorEnabled()) {
this.logger.error(pe.getMessage(), bkpe);
}
List<Integer> errorCodeValue = controllerUtils
.convertErrorCodesToInt(bkpe.getErrorCodes());
pokerResponse = new ResponseEntity<>(PokerResponseProto.newBuilder()
.addAllErrorCodes(errorCodeValue)
.build(), HttpStatus.INTERNAL_SERVER_ERROR);
}
if (logger.isInfoEnabled()) {
logger.info("RETURN::/lobby/api/v1//tournaments/completedata/ " + "GET :: {}",
pokerResponse.toString());
}
return pokerResponse;
}
Here is the code snippet from ControllerUtils class:
public TournamentRecord buildTournamentRecord(TournamentTypeResponseDto dto) {
Instant tournamentStart = dto.getTournamentStartDate();
LocalDate localDate1 = LocalDateTime.ofInstant(tournamentStart,
ZoneOffset.UTC).toLocalDate();
Date.Builder dateBuilder1 = Date.newBuilder();
dateBuilder1.setYear(localDate1.getYear());
dateBuilder1.setMonth(localDate1.getMonthValue());
dateBuilder1.setDay(localDate1.getDayOfMonth());
TournamentCompleteData.Date trnamntStartDate = dateBuilder1.build();
TournamentRecord tr = TournamentRecord.newBuilder()
.setId(dto.getTournamentTypeId())
.setStart(trnamntStartDate)
.setPrize(dto.getFirstPrize())
.setName(dto.getTournamentName())
.setStatus(dto.getStatusName())
.build();
return tr;
}
I have written a test-case which can access this end-point & print the tournaments. But Swift client gets null when it invokes this end point. Already existing protobuf end points work fine with swift client & I have a ProtobufHttpMessageConverter already configured
#Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
And when the swift client invokes the end point, log messages get printed. That means client is invoking the end-point.
Here is the swift client code snippet for LobbyAPI:
import Foundation
class LobbyAPI: Api {
func getTournammentTableList(completion: #escaping ((TournamentFilterPackage_TournamentData?, Error?) -> Void)) {
getData(WithUrl: (APIConstants.lobbyURL) + "tournaments/completedata/", APIKey: APIConstants.apiKey, completion: completion)
}
For TournamentTableListVM
import Cocoa
import RealmSwift
class TournamentTableListVM: NSObject {
private weak var tblListView: LobbyTableListView!
private var tblPreviewVM: TablePreviewVM!
var arrFilterTableList: [LobbyFilterPackage_LobbyTableRecord] = []
var arrTableList: [LobbyFilterPackage_LobbyTableRecord] = []
var timer = Timer()
var didSelectTable: ((_ tableRecord: LobbyFilterPackage_LobbyTableRecord,_ isObserver:Bool) -> Void)!
var getFilterCallBack:(() -> Void)?
var currentSelectedMoneyType: (() -> TabMenuMoneyToggleView.Money) = { .play }{
didSet{
tblPreviewVM.currentSelectedMoneyType = currentSelectedMoneyType
}
}
var didTakeActionFromTablePreview: ((TablePreviewVM.TablePreviewPlayerActionType, Int) -> Void)?
//For sorting
var currentSortKey: String?
var currentSortAscending: Bool?
var aUserData: APPokerProto_PlayerProfileProto!
var observClick = false
func getCompleteTableData() {
LobbyAPI().getTournammentTableList() {[weak self] (aTournammentData, aError) in
guard let self = self else { return }
guard aError == nil, let tableData = aTournammentData, tableData.lobbyTableRecords.count > 0 else {
self.emptyTableAndPreview()
LoginManager.shared.didToggleNotify()
return
}
LoginManager.shared.didToggleNotify()
self.arrFilterTableList = tableData.lobbyTableRecords
self.arrTableList = tableData.lobbyTableRecords
self.tblListView.tblList.reloadData()
self.tblListView.tblList.selectRowIndexes(NSIndexSet.init(index: 0) as IndexSet, byExtendingSelection: true)
self.timeStamp = String(tableData.timeStamp.seconds)
}
}
In this above code "aTournammentData" is coming as nil.
Update Found that in front end swift, it was mapped to wrong generated swift struct. With the help of https://github.com/apple/swift-protobuf plugin TournamentCompleteData.pb.swift file was generated as below
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: TournamentCompleteData.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
struct TournamentFilterPackage_TournamentData {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var tournamentRecords: [TournamentFilterPackage_TournamentRecord] = []
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct TournamentFilterPackage_TournamentRecord {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var id: Int64 = 0
var start: TournamentFilterPackage_Date {
get {return _start ?? TournamentFilterPackage_Date()}
set {_start = newValue}
}
/// Returns true if `start` has been explicitly set.
var hasStart: Bool {return self._start != nil}
/// Clears the value of `start`. Subsequent reads from it will return its default value.
mutating func clearStart() {self._start = nil}
var prize: Float = 0
var name: String = String()
var speed: String = String()
var type: String = String()
var buyIn: Float = 0
var noOfParticipants: Int32 = 0
var status: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _start: TournamentFilterPackage_Date? = nil
}
struct TournamentFilterPackage_Date {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Year of the date. Must be from 1 to 9999, or 0 to specify a date without
/// a year.
var year: Int32 = 0
/// Month of a year. Must be from 1 to 12, or 0 to specify a year without a
/// month and day.
var month: Int32 = 0
/// Day of a month. Must be from 1 to 31 and valid for the year and month, or 0
/// to specify a year by itself or a year and month where the day isn't
/// significant.
var day: Int32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "TournamentFilterPackage"
extension TournamentFilterPackage_TournamentData: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".TournamentData"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "tournamentRecords"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeRepeatedMessageField(value: &self.tournamentRecords) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.tournamentRecords.isEmpty {
try visitor.visitRepeatedMessageField(value: self.tournamentRecords, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: TournamentFilterPackage_TournamentData, rhs: TournamentFilterPackage_TournamentData) -> Bool {
if lhs.tournamentRecords != rhs.tournamentRecords {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension TournamentFilterPackage_TournamentRecord: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".TournamentRecord"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "id"),
2: .same(proto: "start"),
3: .same(proto: "prize"),
4: .same(proto: "name"),
5: .same(proto: "speed"),
6: .same(proto: "type"),
7: .same(proto: "buyIn"),
8: .same(proto: "noOfParticipants"),
9: .same(proto: "status"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularInt64Field(value: &self.id) }()
case 2: try { try decoder.decodeSingularMessageField(value: &self._start) }()
case 3: try { try decoder.decodeSingularFloatField(value: &self.prize) }()
case 4: try { try decoder.decodeSingularStringField(value: &self.name) }()
case 5: try { try decoder.decodeSingularStringField(value: &self.speed) }()
case 6: try { try decoder.decodeSingularStringField(value: &self.type) }()
case 7: try { try decoder.decodeSingularFloatField(value: &self.buyIn) }()
case 8: try { try decoder.decodeSingularInt32Field(value: &self.noOfParticipants) }()
case 9: try { try decoder.decodeSingularStringField(value: &self.status) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
if self.id != 0 {
try visitor.visitSingularInt64Field(value: self.id, fieldNumber: 1)
}
try { if let v = self._start {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
} }()
if self.prize != 0 {
try visitor.visitSingularFloatField(value: self.prize, fieldNumber: 3)
}
if !self.name.isEmpty {
try visitor.visitSingularStringField(value: self.name, fieldNumber: 4)
}
if !self.speed.isEmpty {
try visitor.visitSingularStringField(value: self.speed, fieldNumber: 5)
}
if !self.type.isEmpty {
try visitor.visitSingularStringField(value: self.type, fieldNumber: 6)
}
if self.buyIn != 0 {
try visitor.visitSingularFloatField(value: self.buyIn, fieldNumber: 7)
}
if self.noOfParticipants != 0 {
try visitor.visitSingularInt32Field(value: self.noOfParticipants, fieldNumber: 8)
}
if !self.status.isEmpty {
try visitor.visitSingularStringField(value: self.status, fieldNumber: 9)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: TournamentFilterPackage_TournamentRecord, rhs: TournamentFilterPackage_TournamentRecord) -> Bool {
if lhs.id != rhs.id {return false}
if lhs._start != rhs._start {return false}
if lhs.prize != rhs.prize {return false}
if lhs.name != rhs.name {return false}
if lhs.speed != rhs.speed {return false}
if lhs.type != rhs.type {return false}
if lhs.buyIn != rhs.buyIn {return false}
if lhs.noOfParticipants != rhs.noOfParticipants {return false}
if lhs.status != rhs.status {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension TournamentFilterPackage_Date: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Date"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "year"),
2: .same(proto: "month"),
3: .same(proto: "day"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularInt32Field(value: &self.year) }()
case 2: try { try decoder.decodeSingularInt32Field(value: &self.month) }()
case 3: try { try decoder.decodeSingularInt32Field(value: &self.day) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.year != 0 {
try visitor.visitSingularInt32Field(value: self.year, fieldNumber: 1)
}
if self.month != 0 {
try visitor.visitSingularInt32Field(value: self.month, fieldNumber: 2)
}
if self.day != 0 {
try visitor.visitSingularInt32Field(value: self.day, fieldNumber: 3)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: TournamentFilterPackage_Date, rhs: TournamentFilterPackage_Date) -> Bool {
if lhs.year != rhs.year {return false}
if lhs.month != rhs.month {return false}
if lhs.day != rhs.day {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
Xcode 8.3.3 is giving me this Swift 3 error on this line
values2[index] = nextValue(currentValue)
Cannot convert value of type 'Int' to expected argument type 'Card'
Here's my code:
//
// Card.swift
// match
//
// Created by quantum on 05/09/2017.
// Copyright © 2017 Quantum Productions. All rights reserved.
//
import UIKit
class Card: NSObject {
var quantity = 0
var fill = 0
var shape = 0
var color = 0
override var description : String {
return "Q" + String(quantity) + "/F" + String(fill) + "/S" + String(shape) + "/C" + String(color)
}
override init() {
super.init()
}
static func properties() -> [String] {
return ["quantity", "fill", "shape", "color"]
}
static func isMatch(cards: [Card]) -> Bool {
for property in self.properties() {
var sum = 0
for card in cards {
sum = sum + (card.value(forKey: property) as! Int)
}
if !([3, 6, 9, 7].contains(sum)) {
return false
}
}
return true
}
static func deck(_ values: [Int], _ index: Int, _ max: Int, _ acc: [Card]) -> [Card]{
let currentValue = values[index]
var values2 = values
if currentValue >= max {
if index == 0 {
return acc
}
values2[index] = 0
values2[index-1] = values2[index-1] + 1
return deck(values, index - 1, max, acc)
} else {
var acc2 = acc
let card = Card()
for (index, element) in self.properties().enumerated() {
card.setValue(values[index], forKey: element)
}
acc2.append(Card())
values2[index] = nextValue(Card())
return deck(values2, index, max, acc2)
}
}
func nextValue(_ v: Int) -> Int {
if (v == 0) {
return 1
} else if (v == 1) {
return 2
}
return 4
}
static func deck() -> [Card] {
return deck([1,1,1,1], 4, 3, [Card]())
}
}
this is inside of my Card class.
Strangely, if I try (this is wrong, I'm testing the compiler error)
values2[index] = nextValue(Card())
I get the error Cannot assign the value of type (Int) -> Int to type 'Int'.
Swift thinks my Card is an Int? I'm confused as to what's happening.
I expected to get the call nextvalue with the variable currentvalue, which should be an Int.
It's a bad error message from the compiler.
Your problem is that deck is declared static, but you're trying to call nextValue which is not declared static. This means that nextValue implicitly takes a hidden argument, self, but deck isn't providing it.
If you add static to the func nextValue declaration, it will work like you expect. (You'll get an error on the line referring to self.properties instead, but you'll be closer.)
To make this work properly, you probably want all these functions to be non-static instead. Just think about how this code gets called initially (i.e. how you get your first instance of Card).
A static method cannot call an instance method: the idea makes no sense, as there is no instance. Thus your reference to nextValue is impossible. That is why the line is problematic. How can a static method deck call an instance method nextValue?
Using XCode 8.3.3 which I believe uses Swift 3.1, but not 100% sure (how can you tell?). Here is the complete code. Note that when I paste this into a clean Playground, I get no errors. But within an XCode project, I get the build error on the line "let dice = Dice(withArrayOfDie: arrayOfDie)" in the unit test:
let defaultFaceCount = 6
let defaultDieCount = 6
func randomInt(withMaxValue maxValue: Int) -> Int {
return Int(arc4random_uniform(UInt32(maxValue))) + 1
}
class Die
{
private let m_faceCount: Int // Constant only set in init
private var m_faceValue: Int?
init(numFaces initialFaceCount: Int, withValue initialFaceValue: Int) {
// Make sure number of faces is greater than 0.
m_faceCount = (initialFaceCount > 0) ? initialFaceCount : defaultFaceCount
// Make sure face value is in proper range.
if initialFaceValue == 0 || initialFaceValue > m_faceCount {
m_faceValue = randomInt(withMaxValue: m_faceCount)
}
else {
m_faceValue = abs(initialFaceValue)
}
}
convenience init(numFaces initialFaceCount: Int) {
self.init(numFaces: initialFaceCount,
withValue: randomInt(withMaxValue: initialFaceCount))
}
convenience init() {
self.init(numFaces: defaultFaceCount)
}
var faceValue: Int {
get {
return m_faceValue!
}
}
var faceCount: Int {
get {
return m_faceCount
}
}
func roll() {
// face values are 1 based!
m_faceValue = randomInt(withMaxValue: m_faceCount)
}
}
class Dice {
var m_dice: [Die]
var m_occurrencesOf: [Int]
// Init with a pre-initialized array of Die. Every Die in
// the array must have the same face count.
init(withArrayOfDie: [Die]) {
var faceCount = defaultFaceCount
if withArrayOfDie.isEmpty {
// If there are no dice, add defaults.
m_dice = [Die]()
for _ in 1...defaultDieCount {
m_dice.append(Die(numFaces: defaultFaceCount))
}
}
else {
m_dice = withArrayOfDie
faceCount = m_dice[0].faceCount
}
// Keep trace of # of occurrences of each face value.
m_occurrencesOf = Array(repeating: 0, count: faceCount)
for die in m_dice {
m_occurrencesOf[die.faceValue - 1] += 1
}
}
// Init numDice dice, each with numFaces.
convenience init(numDice count: Int, numFaces faceCount: Int) {
var dice = [Die]()
for _ in 1...count {
dice.append(Die(numFaces: faceCount))
}
self.init(withArrayOfDie: dice)
}
// Init defaultDieCount dice, each with defaultFaceCount faces.
convenience init() {
self.init(numDice: defaultDieCount, numFaces: defaultFaceCount)
}
var count: Int {
return m_dice.count
}
// Retrieve the die at the specified (0 based) index.
func die(atIndex index: Int) -> Die? {
if !m_dice.isEmpty && index >= 0 && index < m_dice.count {
return m_dice[index]
}
return nil
}
subscript(index: Int) -> Die? {
get {
return die(atIndex: index)
}
}
}
// Unit Test
var arrayOfDie = [Die]()
for i in 1...6 {
arrayOfDie.append(Die())
}
let dice = Dice(withArrayOfDie: arrayOfDie)
// XCTAssertEqual(6, dice.count)
I get the build error "Cannot convert value of type [Die] to expected argument type [Die]" on the line "let dice = Dice(withArrayOfDie: arrayOfDie)". Cannot figure out why the argument which is an array of die does not match the expected init argument type.
Thanks!
Get rid of () in var m_dice: [Die]()
class Dice {
var m_dice: [Die]
init(withArrayOfDie dice: [Die]) {
m_dice = dice
}
}
I want to implement a function like this one:
protocol Base {
var value: Int { get set }
}
class ObjectTypeA: Base {
var value: Int = 0
}
class ObjectTypeB: Base {
var value: Int = 1
}
var objects: [Base] = [ObjectTypeA(), ObjectTypeB()]
func updatePropertyForType(type: Base.Type, value: Int) {
objects.filter({ $0 is type }).forEach { // <<< ERROR IS HERE
var object = $0
object.value = value
}
}
updatePropertyForType(ObjectTypeB.self, value: 10)
But there is an error:
'type' is not a type
Please, help me fix it.
See this answer:
protocol Base: AnyObject {
var value: Int { get set }
}
class ObjectTypeA: Base {
var value: Int = 0
}
class ObjectTypeB: Base {
var value: Int = 1
}
var objects: [Base] = [ObjectTypeA(), ObjectTypeB()]
func updatePropertyForType(type: Base.Type, value: Int) {
objects.filter({let item = $0; return type === item.dynamicType }).forEach {
$0.value = value
}
}
call it with:
updatePropertyForType(ObjectTypeA.self, value: 3)
As the other answers have eluded to, you cannot use meta-types with is. However, a nicer solution would be to simply use generics. This will allow Swift to infer the type you pass into the function, allowing you to write it as:
protocol Base : class {
var value: Int { get set }
}
class ObjectTypeA: Base {
var value: Int = 0
}
class ObjectTypeB: Base {
var value: Int = 1
}
var objects: [Base] = [ObjectTypeA(), ObjectTypeB()]
func updateElements<T:Base>(ofType type: T.Type, withValue value: Int) {
objects.filter{ $0 is T }.forEach{ $0.value = value }
}
updateElements(ofType: ObjectTypeB.self, withValue: 10)
You'll also want to make your Base protocol class bound (: class) in order to allow Swift to treat Base typed instances as reference types (allowing you to do $0.value = value).
Your previous code of:
var object = $0
object.value = value
would have worked for reference types, but not for value types – as object here is simply a copy of $0, so any mutations won't be reflected in the array. Therefore you should annotate your protocol to make it clear that your protocol isn't designed to be used with value types.
If you do want to be able to handle value types, you may want to consider using map instead:
func updateElements<T:Base>(ofType type: T.Type, withValue value: Int) {
objects = objects.map {
var object = $0
if object is T {
object.value = value
}
return object
}
}
But this code works just fine.
protocol Base {
var value: Int { get set }
}
class ObjectTypeA: Base {
var value: Int = 0
}
class ObjectTypeB: Base {
var value: Int = 1
}
var objects: [Base] = [ObjectTypeA(), ObjectTypeB()]
func updatePropertyForType(type: Base.Type, value: Int) {
objects.filter({ object in
let result = object.dynamicType == type
return result
}).forEach {
var object = $0
object.value = value
}
}
updatePropertyForType(ObjectTypeB.self, value: 10)
print(objects)
** REWRITE **
OK, it turns out I'm really asking a different question. I understand about hashValue and ==, so that's not relevant.
I would like my wrapper class BUUID to "do the right thing" and act just like NSUUID's act in a Dictionary.
See below, where they don't.
import Foundation
class BUUID: NSObject {
init?(str: String) {
if let uuid = NSUUID(UUIDString: str) {
_realUUID = uuid
}
else {
return nil
}
}
override init() {
_realUUID = NSUUID()
}
private var _realUUID: NSUUID
override var description: String { get { return _realUUID.UUIDString } }
override var hashValue: Int { get { return _realUUID.hashValue } }
var UUIDString: String { get { print("WARNING Use description or .str instead"); return _realUUID.UUIDString } }
var str: String { get { return _realUUID.UUIDString } }
}
func ==(lhs: BUUID, rhs: BUUID) -> Bool { return lhs._realUUID == rhs._realUUID }
let a = BUUID()
let b = BUUID(str: a.str)!
print("a: \(a)\nb: \(b)")
print("a === b: \(a === b)")
print("a == b: \(a == b)")
var d = [a: "Hi"]
print("\(d[a]) \(d[b])")
let nA = NSUUID()
let nB = NSUUID(UUIDString: nA.UUIDString)!
print("na: \(nA)\nnB: \(nB)")
print("nA === nB: \(nA === nB)")
print("nA == nB: \(nA == nB)")
var nD = [nA: "Hi"]
print("\(nD[nA]) \(nD[nB])")
Results. Note that I can look up using NSUUID nB and get back what I put under nA. Not so with my BUUID.
a: 9DE6FE91-D4B5-4A6B-B912-5AAF34DB41C8
b: 9DE6FE91-D4B5-4A6B-B912-5AAF34DB41C8
a === b: false
a == b: true
Optional("Hi") nil
nA: <__NSConcreteUUID 0x7fa193c39500> BB9F9851-93CF-4263-B98A-5015810E4286
nB: <__NSConcreteUUID 0x7fa193c37dd0> BB9F9851-93CF-4263-B98A-5015810E4286
nA === nB: false
nA == nB: true
Optional("Hi") Optional("Hi")
Inheriting from NSObject also assumes isEqual(object: AnyObject?) -> Bool method overloading:
import Foundation
class BUUID: NSObject {
init?(str: String) {
if let uuid = NSUUID(UUIDString: str) {
_realUUID = uuid
}
else {
return nil
}
}
override init() {
_realUUID = NSUUID()
}
private var _realUUID: NSUUID
override func isEqual(object: AnyObject?) -> Bool {
guard let buuid = object as? BUUID else {
return false
}
return buuid._realUUID == _realUUID
}
override var description: String { get { return _realUUID.UUIDString } }
override var hashValue: Int { get { return _realUUID.hashValue } }
var UUIDString: String { get { print("WARNING Use description or .str instead"); return _realUUID.UUIDString } }
var str: String { get { return _realUUID.UUIDString } }
}
func ==(lhs: BUUID, rhs: BUUID) -> Bool { return lhs._realUUID == rhs._realUUID }
let a = BUUID()
let b = BUUID(str: a.str)!
print("a: \(a)\nb: \(b)")
print("a === b: \(a === b)")
print("a == b: \(a == b)")
var d = [a: "Hi"]
print("\(d[a]) \(d[b])")
let nA = NSUUID()
let nB = NSUUID(UUIDString: nA.UUIDString)!
print("na: \(nA)\nnB: \(nB)")
print("nA === nB: \(nA === nB)")
print("nA == nB: \(nA == nB)")
var nD = [nA: "Hi"]
print("\(nD[nA]) \(nD[nB])")
So the answer is to not make BUUID inherit from NSObject, which undercuts the Swiftiness of overriding ==.
So:
extension BUUID: Hashable {}
class BUUID: CustomStringConvertible {
// take away all 'override' keywords, nothing to override
// otherwise same as above
}
Interesting!
This answer is relevant to initially asked question: Why that's possible to get two key-value pairs with identical key's hashes in a dictionary
This example illustrates that keys in Dictionary can have identical hashes, but equality operation should return false for different keys:
func ==(lhs: FooKey, rhs: FooKey) -> Bool {
return unsafeAddressOf(lhs) == unsafeAddressOf(rhs)
}
class FooKey: Hashable, Equatable {
var hashValue: Int {
get {
return 123
}
}
}
var d = Dictionary<FooKey, String>()
let key1 = FooKey()
let key2 = FooKey()
d[key1] = "value1"
d[key2] = "value2"
Output
[FooKey: "value1", FooKey: "value2"]
That's definitely not good to have all keys with the same hash. In this case we are getting that worst case when search element complexity fells down to O(n) (exhaustive search). But it will work.