I try to implement in-app purchase functionalities with several permanent items in Swift 3 for my spritekit game. Everything is created on iTunes Connect, the bundle name is set and my 4 items are correctly declared in the iTunes Connect. The problem is about code inside Xcode. I use the tutorial from Raywenderlich.com here:
https://www.raywenderlich.com/122144/in-app-purchase-tutorial
This tutorial is made for just one item, but what about if we need more items ? (4 in my case). I try for 2 days to modify the code to manage more than one single item, without any success. I have modified the structure RageProducts with the following code:
import Foundation
public struct RageProducts {
public static let GirlfriendOfDrummerRage = "com.creaworks.FurryLight_Puzzles.Guitarist"
fileprivate static let productIdentifiers: Set<ProductIdentifier> = [RageProducts.GirlfriendOfDrummerRage]
// Initial declaration for one item
// public static let store = IAPHelper(productIds: RageProducts.productIdentifiers)
}
//New declaration for 4 items
public static let store = IAPHelper(productIds: Set(
[
GreenGrocerPurchase.AdRemoval,
GreenGrocerPurchase.NewShoppingLists_One,
GreenGrocerPurchase.NewShoppingLists_Five,
GreenGrocerPurchase.NewShoppingLists_Ten
].map { $0.productId }
))
func resourceNameForProductIdentifier(_ productIdentifier: String) -> String? {
return productIdentifier.components(separatedBy: ".").last
}
When I test the code, the compiler return no error but I see no item in my purchase list (instead of one when I activate the old one item declaration). What am I missing?
Is there a swift 3 simplest code example to declare several items for in app purchase ? I can't find any on the web. I use spritekit, so, I don't need tableview components or UIView buttons, this is a little bit confusing for just starting with in app purchase functionalities.
Make sure you add additional identifiers, similar to this one:
public static let GirlfriendOfDrummerRage = "com.creaworks.FurryLight_Puzzles.Guitarist"
Then add them to Set<ProductIdentifier>.
Here an example with 2 products:
public struct Products {
public static let One = "com.creaworks.FurryLight_Puzzles.Guitarist"
public static let Two = "com.creaworks.FurryLight_Puzzles.GuitaristTWO"
fileprivate static let productIndentifiers: Set<ProductIdentifier> = [Products.One, Products.Two]
func resourceNameForProductIdentifier(_ productIdentifier: String) -> String? {
return productIdentifier.components(separatedBy: ".").last
}
}
Related
I have a project A in which I have defined a struct, that only exists in project A, as follows
public struct Foo: RawRepresentable {
public typealias RawValue = String
public var rawValue: RawValue
public init?(rawValue: RawValue) {
self.rawValue = rawValue
}
public static let bar = Foo(rawValue: "bar")
}
Now, when I create an extension in project A that redefines the bar property, this will generate an error, which is logical.
extension Foo {
// Invalid redeclaration of 'bar'
static let bar = Foo(rawValue: "foo")
}
My real question comes when I define a new project B, that depends on A. I declared the same extension there, but no compiler error was given. Why is that?
import A
extension Foo {
// No error, but shouldn't it give me one?
static let bar = Foo(rawValue: "foo")
}
Well, there's two ways to look at this. One is that it's a bug, the other is that it isn't. :) The canonical report is probably the one at https://bugs.swift.org/browse/SR-3228 [WARNING: that URL may go bad when Apple moves over to GitHub Issues for its Swift bug reporting]. But read also the discussion of the underlying mechanism from Jordan Rose in the comments to https://bugs.swift.org/browse/SR-8010, where it seems that the real issue is how to maintain Objective-C compatibility.
So yes, Apple knows about this, and they know it would be nice to issue a warning about doing something iffy, but you are in fact allowed to create what amounts to a same-named but different method/property in a different module, so on your head be it if you do so.
New to Swift, I am trying to build an iOS app that allows a user to construct dynamic reports. I have created several model classes meant to represent various types of data to report on, e.g. Widgets and Gadgets, and associated service classes for these models containing the logic needed to retrieve their data. Examples for a model and service here:
class Widget: BaseModel, Equatable, Identifiable {
let id: UUID
let value: Int
let timeStamp: Date
init(rawData: RawData) {
self.value = rawData.quantity
self.timeStamp = rawData.date
self.id = UUID()
}
func toString() -> String {
return "\(self.value) widgets"
}
static func == (lhs: Widget, rhs: Widget) -> Bool {
return lhs.id == rhs.id
}
}
class WidgetService: BaseService {
let queryService: QueryService = QueryService()
func fetchSamplesInDateRange(dates: (startDate: Date, endDate: Date)?) async -> [Widget] {
// get samples and return them
}
}
These are based off of two protocols with associated types, BaseModel and BaseService. What I'm trying to do in this very early proof of concept stage is implement a simple view that will allow a user to select a type of data (corresponding to one of my Models) and run a query for all data for that Model within a date range. But I am completely stuck on how to implement the model selection.
I have a basic view file I've been working with that just has one button that executes a fetch function, populating a state variable results.
func fetchData() async -> Void {
let modelService: some BaseService = // not sure what to do here
let result: [some BaseModel] = await modelService.fetchSamplesInDateRange(dates: nil)
results = result
}
Because BaseModel and BaseService have associated types they can't be used in the way above as type constraints, I know, I put them there to give an idea of what I'm trying to do.
I had thought to put the class names as strings, choosable via options in a Picker, and then use something like NSClassFromString to get the right class for the service, but ultimately this just doesn't seem workable as I have to declare the concrete service class type at some point, this solution just moves around where I run into the Protocol 'BaseModel' can only be used as a generic constraint because it has Self or associated type requirements error.
Any idea what I'm missing here? This sort of thing using base classes, extensions, generics, just doesn't seem like it should be this difficult as other languages handle it fine (though admittedly with less type safety).
Hey guys I'm working on my first ever app and need some help. My workout tracker app has two classes which you can find below. I have two view controllers hooked up to their own swift files.
Heres my first view controller
Basically what it does is takes the data in the text fields and steppers and turns it into a "Workout" object then appends it to the "WorkoutList" class array.
I've got a print statement setup that prints the Array.count. It shows the correct number in the debug but when I switch views it gets reset to zero.
#IBAction func addToWorkoutList(_ sender: UIButton) {
let workout = Workout(name: workoutName.text!, description: workoutDescription.text!, sets: Int(setStepper.text!)!, reps: Int(repStepper.text!)!)
workoutArrayList.append(workout)
print(workoutArrayList.count)
}
The second view inherits the first views class so that is how I access the "WorkoutArrayList"
class OverViewViewController: NewWorkoutViewController, UITableViewDelegate, UITableViewDataSource {
My app basically allows you to add a workout then produces a graph based on the data you provided. This can make it easy to visualize your gains in the gym. I'm doing this as a learning project so any help on what I should do to build this app would also be greatly appreciated.
Workout Object Class
import Foundation
class Workout {
let workoutName : String
let workoutDescription : String
let numberOfSets : Int
let numberOfReps : Int
init(name : String, description : String, sets : Int, reps : Int) {
workoutName = name
workoutDescription = description
numberOfSets = sets
numberOfReps = reps
}
}
WorkoutList Class
import Foundation
class WorkoutList {
let workoutArray : [Workout] = []
}
Inheriting the class is not what you want to do here. An easy fix for you would be to make workoutArray a static variable so any class can access it at any given time.
static var workoutArray : [Workout] = []
Here is why just inheriting the class doesn't work. When the OverViewViewController loads in to the app, it creates a new instance of the class OverViewViewController and since it inherits NewWorkoutViewController, it also creates a new instance of the NewWorkoutViewController class. You have 2 different instances of NewWorkoutViewController, changing a variable in one of those instances won't change it for any other instances of the class. A static variable, however, is what you are looking for. The array can be changed and accessed any time from any class, you don't even need to inherit. It would work whether you made workoutArray static or workoutArrayList static.
If you have any other questions, feel free to leave a comment.
In Core data when I create a data model, I choose to generate the category extension, I understand that this is created in derived data
I want to be able to view this in the XCode code editor but I don't know how I can open it just to view it.
I am using XCode 9 beta 3
The ways I can manage to do this is by typing some thing such as
let m = MenuItem()
let n = m.name
In the code editor and then command clicking on name and then it jumps to the file, or finding the generated extension in Finder and opening from there.
//
// MenuItem+CoreDataProperties.swift
//
//
// Created by Ryan.Heitner on 01/08/2017.
//
// This file was automatically generated and should not be edited.
//
import Foundation
import CoreData
extension MenuItem {
#nonobjc public class func fetchRequest() -> NSFetchRequest<MenuItem> {
return NSFetchRequest<MenuItem>(entityName: "MenuItem")
}
#NSManaged public var available: Bool
#NSManaged public var desc: String?
#NSManaged public var name: String?
#NSManaged public var price: Double
}
The category extension seems buggy to me. Just select "Manual/None", then select an entity or all entities and click on Editor->Create NSManagedObject Subclass, choose your entities and the extensions should be shown under your project root in Xcode.
Unfortunately what you're doing is the only option Xcode provides. It's not good, but you haven't missed anything. I suggest filing a bug with Apple about this. In the meantime, either deal with this as it is, or switch to some other means of generating your properties-- manually maybe, or using mogenerator.
I have some codes in java which organized well, so it helps me manage source code as well as extend in future easily. These codes as follow
public interface IDataModel<T extends IDataModel> {
void copyData(T data);
long getUpdatedTime();
}
public abstract class AbstractDataModel<T extends IDataModel> implements IDataModel<T>{
protected long updatedTime;
public long getUpdatedTime(){
return updatedTime;
}
}
public class concreteDataA extends AbstractDataModel<concreteDataA>{
String property1;
public String getProperty1(){
return property1;
}
#override
public void copyData(concreteDataA data){
property1 = data.getProperty1();
updatedTime = data.getUpdatedTime();
}
}
Now i want to port into iOS swift 3.0. Is it possible to organize code in swift 3.0 as above? Or is there any equivalent way in swift to organize code as above? I'm quite new to swift iOS, so it makes me hard to organize source code in pattern. Thanks you.
You haven't provided much in the way of context, but it seems like you're struggling developing a "protocol-oriented" solution, as Swift folks like to call the pattern. Here are a couple of options that might solve your problem (spoiler – I think the problem is in your design):
Interface: Protocol, Abstract Class: Protocol Extension
Like #sulthan mentioned, you can certainly get to a similar place using protocols with default implementations, like so:
protocol DataModel {
mutating func copy(data: Self)
var updatedTime : Float { get }
}
extension DataModel {
var updatedTime : Float { return 0 }
}
However, you'll run into a problem when you try to implement the ConcreteDataModel since you want to specialize it to account for the property1 value that isn't mentioned in the protocol. Your options are to relax that requirement in ConcreteDataModel (aka don't do that) or use typecasting. Please note, fighting the typing system in Swift is a sure sign that your code is not idiomatic! You should see this difficulty as the language nudging you to reconsider your approach.
Use immutable data types
This is the most straight-forward answer. If what you've described above is actually a concrete example from your app, then you don't really need protocols at all. (In fact, your Java implementation is certainly over-abstracting.) Swift structs are immutable, which means that whenever you change them, you are actually changing a copy.
struct DataModel {
let updatedTime: Float
mutating func update(time: Float) {
self = DataModel(updatedTime: time)
}
}
var data1 = DataModel(updatedTime: 3)
var data2 = data1
data2.update(time: 17)
print(data1.updatedTime) // 3.0
print(data2.updatedTime) // 17.0
Model your behavior apart from your data
This is the generalized solution. From a design perspective, it's clear that you have two distinct concerns. You want something copyable, and you want something that tracks "time." Why not just let your code reflect that?
protocol Copier {
associatedtype Data
func copy(from: Data) -> Data
}
protocol Clock {
var time: Float { get }
}
class AlarmClock: Clock, Copier {
let time: Float
let alarm: Float
init(time: Float, alarm: Float) {
self.time = time
self.alarm = alarm
}
func copy(from: AlarmClock) -> AlarmClock {
return AlarmClock(time: from.time, alarm: from.alarm)
}
}
Of course, you could even go the last step and provide the default implementation for Clock.time if you really needed it.