I'm developing automated tests using KIF and Swift
I wrote some tests but they don't depend on each other
How to reset app and execute this in beforeEach() method?
class PassengerCountTests: KIFTestCase {
enum Element: String {
case passengerCount = "passengerCount_label"
case plusButton = "plus_button"
case minusButton = "minus_button"
}
func getElement(element: Element) -> UIView {
return tester().waitForView(withAccessibilityLabel: element.rawValue)
}
func tap(element: Element) {
tester().tapView(withAccessibilityLabel: element.rawValue)
}
func testMinPassengerNumber() {
let passengerCount = getElement(element: Element.passengerCount)
let minusButton = getElement(element: Element.minusButton)
XCTAssertEqual(passengerCount.accessibilityValue, "1")
XCTAssertEqual(minusButton.isProbablyTappable, false)
}
func testMaxPassengerNumber() {
for _ in 1...4 {
tap(element: Element.plusButton)
}
let passengerCount = getElement(element: Element.passengerCount)
let plusButton = getElement(element: Element.plusButton)
XCTAssertEqual(passengerCount.accessibilityValue, "5")
XCTAssertEqual(plusButton.isProbablyTappable, false)
}
}
Related
i am using reward admob ad in my project with latest sdk. how can i get proper callback that the user has closed the ad in between. I know there is a delegate method of fullscreencontent delegate which will be called but in that delegate method i am calling some code block which i perform when i complete watching the ad and it justs work fine but what if i closed the ad in between then the same delegate is being called. so how do i decide that the user has watched the ad or closed in between.
my code snippet:
enum RewardAdType {
case avatar, freeChips, scratchCard, chips250
}
typealias AD_COMPLETION_BLOCK = (_ success: Bool) -> ()
class RewardAdManager : NSObject
{
//MARK: - PROPERTIES
var rewardBasedVideoAd : GADRewardedAd? = nil
var rewardValue = ""
var type: RewardAdType? = nil
}
//MARK: - HELPERS
extension RewardAdManager
{
func loadRewardedAd(vc: UIViewController, userId: String, type: RewardAdType, imageName: String? = nil, chipsCoin: String? = nil, completion: #escaping AD_COMPLETION_BLOCK)
{
self.type = type
let adUnit = self.type == .avatar ? Constants.REWARD_AD_AVATAR_LIVE_ID : Constants.REWARD_AD_WINCHIPS_LIVE_ID
let request = GADRequest()
GADRewardedAd.load(withAdUnitID: adUnit, request: request) { [weak self] ad, error in
guard let self = self, error == nil else {
Helpers.hidehud()
self?.type = nil
self?.rewardBasedVideoAd = nil
return
}
let serverSideVerificationOptions = GADServerSideVerificationOptions()
serverSideVerificationOptions.userIdentifier = userId
if type == .scratchCard {
self.rewardValue = self.generateRandomRewardValue()
serverSideVerificationOptions.customRewardString = self.rewardValue
} else if type == .avatar {
serverSideVerificationOptions.customRewardString = imageName
} else if type == .freeChips {
serverSideVerificationOptions.customRewardString = chipsCoin
} else if type == .chips250 {
serverSideVerificationOptions.customRewardString = "250"
}
self.rewardBasedVideoAd = ad
self.rewardBasedVideoAd?.serverSideVerificationOptions = serverSideVerificationOptions
self.rewardBasedVideoAd?.fullScreenContentDelegate = self
self.showRewardedAd(viewController: vc, type: type, completion: completion)
}
}
func showRewardedAd(viewController: UIViewController, type: RewardAdType? = nil, completion: #escaping AD_COMPLETION_BLOCK)
{
Helpers.hidehud()
if let ad = self.rewardBasedVideoAd {
self.type = type
DispatchQueueHelper.delay {
ad.present(fromRootViewController: viewController) {}
}
completion(true)
} else {
self.type = nil
self.checkForSavedLanguage(viewController: viewController)
}
}
func checkForSavedLanguage(viewController: UIViewController)
{
let lang = LanguageCode(rawValue: Defaults[.LangCode]) ?? .english
viewController.showToast(msg: Constants.NO_ADS_MESSAGE.localizeString(string: lang))
}
func generateRandomRewardValue() -> String
{
var val = 0
let random = Double.random(in: 0.1...1.0)
if random < 0.20 {
val = 150
} else if random < 0.50 {
val = 200
} else if random < 0.70 {
val = 250
} else {
val = 350
}
return val.toString()
}
}
//MARK: - GADFullScreenContentDelegate
extension RewardAdManager : GADFullScreenContentDelegate {
func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error)
{
self.type = nil
Helpers.hidehud()
let lang = LanguageCode(rawValue: Defaults[.LangCode]) ?? .english
let userInfo = ["msg":Constants.NO_ADS_MESSAGE.localizeString(string: lang)]
NotificationCaller.shared.showLeaveMsg(userInfo: userInfo)
}
func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd)
{
guard let type = self.type else { return }
self.rewardBasedVideoAd = nil
let userInfo: [String:RewardAdType] = ["type":type]
NotificationCaller.shared.showRewardTypePopup(userInfo: userInfo)
}
}
I have this function
class func addCVals(_ criteres: [[AnyHashable: Any]], _ type: String) {
DispatchQueue.global(qos: .background).async {
autoreleasepool {
if criteres.count > 0 {
if let realm = DBTools.getRealm() {
do {
try realm.transaction {
let oldValues = CriteresVal.objects(in: realm, where: "type = '\(type)'")
if oldValues.count > 0 {
realm.deleteObjects(oldValues)
}
for critere in criteres {
let cval = CriteresVal(critere, type)
if let c = cval {
realm.addOrUpdate(c)
}
}
}
} catch {
DebugTools.record(error: error)
}
realm.invalidate()
}
}
}
}
}
The request that get oldValues occasionally cause an error
Realm accessed from incorrect thread
I don't understand why as I get a new Realm before with this lines:
if let realm = DBTools.getRealm()
My function getRealm:
class func getRealm() -> RLMRealm? {
if !AppPreference.lastAccount.elementsEqual("") {
let config = RLMRealmConfiguration.default()
do {
return try RLMRealm(configuration: config)
} catch {
DebugTools.record(error: error)
DispatchQueue.main.async {
Notifier.showNotification("", NSLocalizedString("UNKNOWN_ERROR_DB", comment: ""), .warning)
}
}
}
return nil
}
CriteresVal is an RLMObject that is composed of this:
#objcMembers
public class CriteresVal: RLMObject {
dynamic var cvalId: String?
dynamic var type: String?
dynamic var text: String?
dynamic var compositeKey: String?
override public class func primaryKey() -> String {
return "compositeKey"
}
private func updatePrimaryKey() {
self.compositeKey = "\(self.cvalId ?? "")/\(self.type ?? "")"
}
required init(_ cvalue: [AnyHashable: Any]?, _ type: String) {
super.init()
if let values = cvalue {
if let cvalId = values["id"] as? String {
self.cvalId = cvalId
} else if let cvalId = values["id"] as? Int {
self.cvalId = "\(cvalId)"
}
self.type = type
if let text = values["text"] as? String {
self.text = text
}
}
updatePrimaryKey()
}
func generateDico() -> [String: Any] {
var dicoSortie = [String: Any]()
if let realm = self.realm {
realm.refresh()
}
if let value = cvalId {
dicoSortie["id"] = value
}
if let value = type {
dicoSortie["type"] = value
}
if let value = text {
dicoSortie["text"] = value
}
return dicoSortie
}
}
compositeKey is the primary key which included cvalId and type
Thanks for help.
Is there a simple way to do this for a UITabBarController after the user has modified the original ordering? I got the following code to work but it feels a bit clunky.
class TabBarViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.restoreItemOrder()
}
override func tabBar(_ tabBar: UITabBar, didEndCustomizing items: [UITabBarItem], changed: Bool) {
if changed {
self.cacheItemOrder(items: items)
}
}
}
The extensions to cache/restore the order after editing.
extension UITabBarController {
private static let cacheKey = "tabBarIndex"
public func cacheItemOrder(items: [UITabBarItem]) {
var index = [String: Int]()
var i = 0
for item in items {
if let title = item.title {
index[title] = i
}
i += 1
}
UserDefaults.standard.set(index, forKey: UITabBarController.cacheKey)
}
public func restoreItemOrder() {
if let dict = UserDefaults.standard.dictionary(forKey: UITabBarController.cacheKey) as? [String: Int] {
if let vcs = self.viewControllers {
self.viewControllers = vcs.sorted() {
var idx0 = 99
var idx1 = 99
if let t0 = $0.tabBarItem.title, let idx = dict[t0] {
idx0 = idx
}
if let t1 = $1.tabBarItem.title, let idx = dict[t1] {
idx1 = idx
}
return idx0 < idx1
}
}
}
}
}
Thanks in advance.
You can express everything more succinctly with functional idioms:
extension UITabBarController {
private static let cacheKey = "tabBarIndex"
public func cacheItemOrder(items: [UITabBarItem]) {
UserDefaults.standard.set(
[String: Int](uniqueKeysWithValues: items.enumerated().map { ($1.title ?? "", $0)}),
forKey: UITabBarController.cacheKey
)
}
public func restoreItemOrder() {
guard let order = UserDefaults.standard.dictionary(forKey: UITabBarController.cacheKey) as? [String: Int] else {
return
}
viewControllers?.sort { left, right in
guard let leftIndex = left.title.flatMap({order[$0]}),
let rightIndex = right.title.flatMap({order[$0]}) else {
return false
}
return leftIndex < rightIndex
}
}
}
I just realized that my old app is not working anymore because unsafeAddressOf is abandoned in Swift 3. I have been searching in Apple documentations and online tutorials but still cant figure out how to change my code to be compliant with Swift 3. Here is my code:
import UIKit
import ImageIO
extension UIImage {
public class func gifWithData(data: NSData) -> UIImage? {
guard let source = CGImageSourceCreateWithData(data, nil) else {
print("SwiftGif: Source for the image does not exist")
return nil
}
return UIImage.animatedImageWithSource(source: source)
}
public class func gifWithName(name: String) -> UIImage? {
guard let bundleURL = Bundle.main.url(forResource: name, withExtension: "gif") else {
print("SwiftGif: This image named \"\(name)\" does not exist")
return nil
}
guard let imageData = NSData(contentsOfURL: bundleURL) else {
print("SwiftGif: Cannot turn image named \"\(name)\" into NSData")
return nil
}
return gifWithData(imageData)
}
class func delayForImageAtIndex(index: Int, source: CGImageSource!) -> Double {
var delay = 0.1
// Get dictionaries
let cfProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil)
let gifProperties: CFDictionary = unsafeBitCast(CFDictionaryGetValue(cfProperties, unsafeAddressOf(kCGImagePropertyGIFDictionary)), to: CFDictionary.self)
// Get delay time
var delayObject: AnyObject = unsafeBitCast(
CFDictionaryGetValue(gifProperties,
unsafeAddressOf(kCGImagePropertyGIFUnclampedDelayTime)),
to: AnyObject.self)
if delayObject.doubleValue == 0 {
delayObject = unsafeBitCast(CFDictionaryGetValue(gifProperties,
unsafeAddressOf(kCGImagePropertyGIFDelayTime)), to: AnyObject.self)
}
delay = delayObject as! Double
if delay < 0.1 {
delay = 0.1 // Make sure they're not too fast
}
return delay
}
class func gcdForPair( a: Int?, var _ b: Int?) -> Int {
// Check if one of them is nil
var a = a
if b == nil || a == nil {
if b != nil {
return b!
} else if a != nil {
return a!
} else {
return 0
}
}
// Swap for modulo
if a < b {
let c = a
a = b
b = c
}
// Get greatest common divisor
var rest: Int
while true {
rest = a! % b!
if rest == 0 {
return b! // Found it
} else {
a = b
b = rest
}
}
}
class func gcdForArray(array: Array<Int>) -> Int {
if array.isEmpty {
return 1
}
var gcd = array[0]
for val in array {
gcd = UIImage.gcdForPair(val, gcd)
}
return gcd
}
class func animatedImageWithSource(source: CGImageSource) -> UIImage? {
let count = CGImageSourceGetCount(source)
var images = [CGImage]()
var delays = [Int]()
// Fill arrays
for i in 0..<count {
// Add image
if let image = CGImageSourceCreateImageAtIndex(source, i, nil) {
images.append(image)
}
// At it's delay in cs
let delaySeconds = UIImage.delayForImageAtIndex(index: Int(i),
source: source)
delays.append(Int(delaySeconds * 1000.0)) // Seconds to ms
}
// Calculate full duration
let duration: Int = {
var sum = 0
for val: Int in delays {
sum += val
}
return sum
}()
// Get frames
let gcd = gcdForArray(array: delays)
var frames = [UIImage]()
var frame: UIImage
var frameCount: Int
for i in 0..<count {
frame = UIImage(CGImage: images[Int(i)])
frameCount = Int(delays[Int(i)] / gcd)
for _ in 0..<frameCount {
frames.append(frame)
}
}
// Heyhey
let animation = UIImage.animatedImage(with: frames,
duration: Double(duration) / 1000.0)
return animation
}
}
Does anyone have an idea how I can fix this code?
I have one project that write with swift 1 but now I run with Xcode 7.2 (swift 2)
but I don't know why I got many errors.
I can fix one problem in my previous question but I have big problem and I so tired.
this is my code :
public func generate() -> AnyGenerator <(String, JSON)> {
switch self.type {
case .Array:
let array_ = object as! [AnyObject]
var generate_ = array_.generate()
var index_: Int = 0
return AnyGenerator<(String, JSON)> {
if let element_: AnyObject = generate_.next() {
return ("\(index_++)", JSON(element_))
} else {
return nil
}
}
case .Dictionary:
let dictionary_ = object as! [String : AnyObject]
var generate_ = dictionary_.generate()
return AnyGenerator<(String, JSON)> {
if let (key_, value_) = generate_.next() {
return (key_, JSON(value_))
} else {
return nil
}
}
default:
return AnyGenerator<(String, JSON)> {
return nil
}
}
}
please guide me about these errors!!!
In Swift 2, the global function
public func anyGenerator<Element>(body: () -> Element?) -> AnyGenerator<Element>
is used to create a (type-erased) generator from a given
closure:
public func generate() -> AnyGenerator <(String, JSON)> {
// ...
return anyGenerator {
if let element_: AnyObject = generate_.next() {
return ("\(index_++)", JSON(element_))
} else {
return nil
}
}
}