Why is my app crashing when loading my in app purchases? - xcode

I have this code that loads my in app purchases in the didMoveToView. If I press a button to go to my help screen or another button to leave the scene before the in app purchases load the app crashes. I think Im calling it in the wrong place. Can someone tell me what Im doing wrong? If you need more code or info let me know please. Thanks!
override func didMoveToView(view: SKView) {
if(SKPaymentQueue.canMakePayments()) {
println("IAP is enabled, loading")
var productID:NSSet = NSSet(objects: "unlockLevelTwo", "unlockLevelThree", "unlockEverything")
var request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as Set<NSObject>)
request.delegate = self
request.start()
} else {
println("please enable IAPS")
}

#1
Did you add the StoreKit framework to your project?
#2
Make sure not to release the class containing the corresponding methods at the end.
Hope that helps :)

Related

SwiftUI - How to get access to "WindowScene"

In watching the WWDC 21 videos reference StoreKit 2, there are a few functions that they reference wherein they let a value = WindowScene as follows:
func manageSubscriptions() async {
if let windowScene = self.view.window?.windowScene {
do {
try await AppStore.showManageSubscriptions(in: windowScene)
} catch {
//error
}
}
}
The let line errors out with the message: Type of expression is ambiguous without more context
If I try and provide more context with something like:
if let windowScene = (self.view.window?.windowScene)! as UIWindowScene {
I am told: Value of type 'MyStruct' has no member 'view'
What am I missing, must be something simple, to gain access to this needed UI element?
Thank you
Added:
I'd like to add that I am using a SwiftUI app that was created using a SceneDelegate and AppDelegate, not a simple struct: App, type of structure. So I am guessing I need to access something in the SceneDelegate to get the right object..
Just to provide an answer for anyone interested, with all credit to #aheze for finding it and #Matteo Pacini for the solution, to get this specific method to work when using a SwiftUI app that has an AppDelegate/SceneDelegate structure, this will work:
#MainActor
func manageSubscriptions() async {
if let windowScene = UIApplication.shared.connectedScenes.first {
do {
try await AppStore.showManageSubscriptions(in: windowScene as! UIWindowScene)
} catch {
//error
}
}
}
You can conversely use the view modifier manageSubscriptionsSheet(isPresented:) instead. This is Apple's recommended approach when using SwiftUI and will mitigate the need for getting a reference to the window scene.
Source:
If you’re using SwiftUI, call the manageSubscriptionsSheet(isPresented:)view modifier.

How to write unit test cases (XCTest) in UIWebView / WebKit - Swift

I want to write unit test cases (XCTest) in UIWebView/ Webkit- Swift
Please post any helpful link, example, or tutorial.
Thank you.
Shriram
A good way is to create fake navigation actions to call manually the delegate.
In this question you have a good example to write test cases of this way. unit-testing-wknavigationdelegate-functions
Example to test loading in navigation:
// setup
let fakeNavigation = WKNavigation()
delegateObject.refresh() // Set loading to true and init the web view
XCTAssertTrue(delegateObject.loading)
delegateObject.webView(webView, didFinish: fakeNavigation)
XCTAssertFalse(delegateObject.loading)
Example to test the policy:
class FakeNavigationAction: WKNavigationAction {
let testRequest: URLRequest
override var request: URLRequest {
return testRequest
}
init(testRequest: URLRequest) {
self.testRequest = testRequest
super.init()
}
}
// setup
var receivedPolicy: WKNavigationActionPolicy?
let fakeAction = FakeNavigationAction(testRequest: ...)
// act
delegateObject.webView(webView, decidePolicyFor: fakeAction, decisionHandler: {
receivedPolicy = $0
})
XCTAssertEqual(receivedPolicy, theExpectedValue)

Swift 4.2.1 requesting JSON with Xcode 10.1

My code:
let cgpurl = URL(string: "https://api.coingecko.com/api/v3/ping")!
let task = URLSession.shared.dataTask(with: cgpurl) { (Data, URLResponse, Error) in
if let data = Data, let string = String(data: data, encoding: .utf8) {
let CGPing = string } ; resume() }
The problem is with the 2nd use of "cgpurl". I've tried changing case to no effect. The error I'm getting is, "Cannot use instance member 'cgpurl' within property initializer; property initializers run before 'self' is available". Ok... but I can't even replace cgpurl with the actual link? Then I get the error message "Ambiguous reference to member 'dataTask(with:completionHandler:)'" I realize this release of swift was supposed to be "small" & just to "fix errors" but I've not been able to find any current documentation on this release. I'm using swift 4.2.1 with Xcode 10.1
This code was taken directly from a teaching manual for Swift 4.2
No, it wasn't. The code you have was never right, in Swift 4.2 or any other version of Swift. You have blindly copied and pasted perhaps, without looking at the overall context.
The problem is that the code, as you have it, is sitting "loose" at the top of your view controller or other class declaration, perhaps something along these lines:
class MyViewController : UIViewController {
let cgpurl = // ...
let task = // ...
}
That's wrong. The most basic rule of Swift programming is that executable code can exist only in a function. For example:
class MyViewController : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let cgpurl = // ...
let task = // ...
}
}
That may not solve all your issues, but at least you'll get past the most basic mistake you're making and the "Cannot use instance member" compile error will go away.

NSCache() is not working properly

I think I am tired of NSCache(). Could not understand what's the problem behind this. Trying to save an array of [AnyObject] to NSCahce(), which I have done using this following line of code.
NSCache().setObject(data, forKey: "News")
And tried to get it back using this way.
if let news = NSCache()("News") as? [AnyObject]
{
}
else
{
// I am always here :)
}
So I was thinking what's the problem with this. After searching a bit in Google I could see that setting totalCostLimit and countLimit will help you solve this problem. So I have set it like this.
NSCache().totalCostLimit = 50000
NSCache().countLimit = 50000
After setting this also, it was not working. So I thought of running this code in main thread, which I have done like this.
dispatch_async(dispatch_get_main_queue()) {
NSCache().setObject(data, forKey: "News")
}
Still it returned nil. Now last but not the least I have created one global instance of NSCache() and called all these operations using that instance. Well, doing like that also didn't give the expected result. It always gave me nil.
What's happening here? I know that NSCache() can store AnyObject values. I am saving lot of images in the same project without any problem, when I am trying to save this it returns nil.
Well this AnyObject contains some custom classes. Is that can be a problem? If yes, how will I save it locally without using CoreData or NSUserdefaults.
How I created an instance globally and accessed these. Created one instance of NSCache in the AppDelegate.swift file but outside of AppDelegate class
let mainCache = NSCache()
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(aNotification: NSNotification)
{
mainCache.totalCostLimit = 50000
mainCache.countLimit = 50000
}
}
Later I have used it like this.
mainCache.setObject(data, forKey: "News")
And getting the data back like this.
if let news = mainCache.objectForKey("News") as? [AnyObject]
{
}
else
{
// Always here :)
}
When you write NSCache() you are creating a new NSCache instance. You're doing this on just about every line.
What you need to do is create one instance, let myCache = NSCache(), and then reuse it: myCache.setObject(data, forKey: "News").

Swift - CLLocationManager not asking for user permission

I am with Xcode beta 2 and trying to get user location with OS X app, however it is not even asks user permission. here is what I did until now.
...
import CoreLocation
class AppDelegate: NSObject, NSApplicationDelegate, CLLocationManagerDelegate {
var locManager : CLLocationManager = CLLocationManager()
func applicationDidFinishLaunching(aNotification: NSNotification?) {
locManager.delegate = self
locManager.desiredAccuracy = kCLLocationAccuracyBest
locManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
//doSomething.
}
}
nothing happens. I looked other questions and try all suggested solutions from answers but did not work. Tried with Objective-C, all fine. Am I missing something here?
Location Service enabled on preferences of the computer. Also "NSLocationUsageDescription" is in info.plist. NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription for 10.10 and later, I am working on 10.9.
Information Property List Key Reference
There were no problem code wise, just noticed it is App Sandbox entitlement problem. Once I have checked Location under App Data it worked right away.

Resources