Excess memory usage swift - swift

I'm building a today extension for iOS and I'm confused why this function keeps on using more and more memory.
See the code below:
func loadActivePlayer() {
kodi.getActivePlayer {
(response) in
let result = JSON(response)
let activePlayer = ActivePlayer()
if let playerid = result["result"][0]["playerid"].int {
activePlayer.playerid = playerid
}
if let type = result["result"][0]["type"].string {
activePlayer.type = type
}
if(activePlayer.isEmpty()) {
self.loadActivePlayer()
}
else {
self.enablePlaybackButtons(true)
self.activePlayer = activePlayer
self.kodi.getItem(activePlayer.playerid) {
(response) in
var result = JSON(response)
var item = Item()
if let id = result["result"]["item"]["id"].int {
item.id = id
}
if let type = result["result"]["item"]["type"].string {
item.type = type
}
if let label = result["result"]["item"]["label"].string {
item.label = label
}
if let title = result["result"]["item"]["title"].string {
item.title = title
}
if let season = result["result"]["item"]["season"].int {
item.season = season
}
if let episode = result["result"]["item"]["episode"].int {
item.episode = episode
}
if let showtitle = result["result"]["item"]["showtitle"].string {
item.showtitle = showtitle
}
dispatch_async(dispatch_get_main_queue()) {
self.itemTitleLabel.text = item.title
self.itemShowTitleLabel.text = item.showtitle
self.itemSeasonEpisodeLabel.text = "S\(item.season)E\(item.episode)"
}
self.loadActivePlayer()
}
}
}
When it goes in the if(activePlayer.isEmpty())
the memory usage increases and increases and increases, quite irritating.
But when it goes into the else, the memory usage stays almost the same, it does not increase significantly.
Can anyone help me understand why this is happening?
Thanx in advance!

Related

CoreData batch insert Entities with Relationship

Is there anyway to insert entities with relationship? I get error "Illegal attempt to establish a relationship 'content' between objects in different contexts"
addUsers(users: [userData])
func addUsers(users: [User]) {
let taskContext = container.viewContext
taskContext.perform {
let batchInsertRequest = self.newBatchInsertRequest(with: users)
if let fetchResult = try? taskContext.execute(batchInsertRequest),
let batchInsertResult = fetchResult as? NSBatchInsertResult,
let success = batchInsertResult.result as? Bool, success {
return
}
}
}
crash happens in below code
private func newBatchInsertRequest(with users: [Users]) -> NSBatchInsertRequest {
var index = 0
let total = message.count
let batchInsertRequest = NSBatchInsertRequest(entity: WaUser.entity(), managedObjectHandler: { managedObject in
guard index < total else { return true }
let user = users[index]
if let waUser = managedObject as? WaUser {
waUser.name = user.name
let waUserInfo = waUserInfo(context: self.container.viewContext)
waUserInfo.pass = "12345"
waUserInfo.key = "asdfgh"
waUser.info = waUserInfo **//crash occurs here**
}
index += 1
return false
})
return batchInsertRequest
}

Filter results, slow performance Swift

Swift question...
I'm making a babyname app and trying to filter the results as chosen by the user. I managed to get it working, but it takes a while for the results to get filtered. I mean like 2-3 seconds.
Here is what I wrote :
func apply(list: [String]) -> [String] {
let allSavedSettings = settings.all
var newList = list
if let short = allSavedSettings["short"] as? Bool {
if !short {
print("filter short")
newList = newList.filter({$0.count > 4})
}
}
if let long = allSavedSettings["long"] as? Bool {
if !long {
print("filter long")
newList = newList.filter({$0.count < 5})
}
}
if let dutch = allSavedSettings["dutch"] as? Bool {
if !dutch {
print("filter dutch")
newList = newList.filter({!dutchboy.contains($0)})
newList = newList.filter({!dutchgirl.contains($0)})
}
}
if let english = allSavedSettings["english"] as? Bool {
if !english {
print("filter english")
newList = newList.filter({!englishboy.contains($0)})
newList = newList.filter({!englishgirl.contains($0)})
}
}
if let arabic = allSavedSettings["arabic"] as? Bool {
if !arabic {
print("filter arabic")
newList = newList.filter({!arabicboy.contains($0)})
newList = newList.filter({!arabicgirl.contains($0)})
}
}
if let hebrew = allSavedSettings["hebrew"] as? Bool {
if !hebrew {
print("filter hebrew")
newList = newList.filter({!hebrewboy.contains($0)})
newList = newList.filter({!hebrewgirl.contains($0)})
}
}
if let latin = allSavedSettings["latin"] as? Bool {
if !latin {
print("filter latin")
newList = newList.filter({!latinboy.contains($0)})
newList = newList.filter({!latingirl.contains($0)})
}
}
if let chinese = allSavedSettings["chinese"] as? Bool {
if !chinese {
print("filter chinese")
newList = newList.filter({!chineseboy.contains($0)})
newList = newList.filter({!chinesegirl.contains($0)})
}
}
if let scandinavian = allSavedSettings["scandinavian"] as? Bool {
if !scandinavian {
print("filter scandinavian")
newList = newList.filter({!scandinavianboy.contains($0)})
newList = newList.filter({!scandinaviangirl.contains($0)})
}
}
if let spanish = allSavedSettings["spanish"] as? Bool {
if !spanish {
print("filter spanish")
newList = newList.filter({!spanishboy.contains($0)})
newList = newList.filter({!spanishgirl.contains($0)})
}
}
return newList
}
So I save the users preferences as a Boolean value in an array called "allSavedSettings" with userdefaults. Whenever a setting is false it will filter the result from the complete list of names.
Is there something else I should use, to speed things up? The list is about 5000 names.
Thanks in advance.
Patrick
I'd use sets wherever possible since hashing is faster than iterating over an array multiple times and it eliminates duplicates. You do not need to convert your main list to a set as that would add additional cycles.
Something like this should speed things up.
var doNotInclude = Set<String>()
if allSavedSettings["english"] == false {
doNotInclude.formUnion(Set(englishBoy + englishGirl))
}
if allSavedSettings["dutch"] == false {
doNotInclude.formUnion(Set(dutchBoy + dutchGirl))
}
if allSavedSettings["arabic"] == false {
doNotInclude.formUnion(Set(arabicBoy + arabicGirl))
}
let result = list.filter { !doNotInclude.contains($0) }

Parse Alamofire result swift

I'm very lost parsing the following response from an AF request – let json = result as! NSDictionary – in Swift:
{
errors = (
);
get = statistics;
parameters = {
country = germany;
};
response = (
{
cases = {
"1M_pop" = 14303;
active = 317167;
critical = 4179;
new = "+15161";
recovered = 863300;
total = 1200006;
};
continent = Europe;
country = Germany;
day = "2020-12-08";
deaths = {
"1M_pop" = 233;
new = "+380";
total = 19539;
};
population = 83900328;
tests = {
"1M_pop" = 347331;
total = 29141172;
};
time = "2020-12-08T09:15:08+00:00";
}
);
results = 1;
}
Any idea how to get the actual case numbers, i.e. for example the number of new cases?
So far I have tried the following (error throwing) approach:
if let responseDict = result as? NSDictionary {
if let data = responseDict.value(forKey: "response") as?
[NSDictionary] {
// Get case numbers
guard let cases = data[0]["cases"] else { return }
guard let casesPerOneMil = cases[0] as! Int else { return }
print(casesPerOneMil)
}
}
Basically don't use NS... collection types in Swift at all, use native types.
And don't use value(forKey, use key subscription.
And you have to conditional downcast Any to the expected concrete type.
There is another mistake: The object for cases is a dictionary, note the {} and you have to get the value for casesPerOneMil with key subscription, too
if let responseDict = result as? [String:Any],
let dataArray = responseDict["response"] as? [[String:Any]],
let firstDataItem = dataArray.first {
// Get case numbers
guard let cases = firstDataItem["cases"] as? [String:Any] else { return }
guard let casesPerOneMil = cases["1M_pop"] as? Int else { return }
print(casesPerOneMil)
}
}

Storing Collective Level Score Values For An Overall "Bank" Value in SpriteKit

I have a game that has 9 different levels which have their own highscore values for coins collected and special coins collected. I want to make a "Bank" that can store those values and add them up to be able to 'purchase' the unlock for some levels. I'm not sure if I implemented my scoring system in a way that won't allow this or if I'm missing something simple. Any insight is greatly appreciated!
import Foundation
struct ScoreManager {
static func getCurrentScore(for levelKey: String) -> [String:Int] {
if let existingData = UserDefaults.standard.dictionary(forKey: levelKey) as? [String:Int] {
return existingData
} else {
return [GameConstants.StringConstants.scoreScoreKey:0, GameConstants.StringConstants.scoreStarsKey:0, GameConstants.StringConstants.scoreCoinsKey:0]
}
}
static func updateScore(for levelKey: String, and score: [String:Int]) {
UserDefaults.standard.set(score, forKey: levelKey)
UserDefaults.standard.synchronize()
}
static func compare(scores: [[String:Int]], in levelKey: String) {
var newHighscore = false
let currentScore = getCurrentScore(for: levelKey)
var maxScore = currentScore[GameConstants.StringConstants.scoreScoreKey]!
var maxStars = currentScore[GameConstants.StringConstants.scoreStarsKey]!
var maxCoins = currentScore[GameConstants.StringConstants.scoreCoinsKey]!
for score in scores {
if score[GameConstants.StringConstants.scoreScoreKey]! > maxScore {
maxScore = score[GameConstants.StringConstants.scoreScoreKey]!
newHighscore = true
}
if score[GameConstants.StringConstants.scoreStarsKey]! > maxStars {
maxStars = score[GameConstants.StringConstants.scoreStarsKey]!
newHighscore = true
}
if score[GameConstants.StringConstants.scoreCoinsKey]! > maxCoins {
maxCoins = score[GameConstants.StringConstants.scoreCoinsKey]!
newHighscore = true
}
}
if newHighscore {
let newScore = [GameConstants.StringConstants.scoreScoreKey: maxScore, GameConstants.StringConstants.scoreStarsKey: maxStars, GameConstants.StringConstants.scoreCoinsKey: maxCoins]
updateScore(for: levelKey, and: newScore)
}
}
And this is called in the GameScene after you finish the level..
func finishGame() {
gameState = .finished
var stars = 0
let percentage = CGFloat(coins)/100.0
if percentage >= 0.8 {
stars = 3
} else if percentage >= 0.4 {
stars = 2
} else if coins >= 1 {
stars = 1
}
let scores = [
GameConstants.StringConstants.scoreScoreKey: coins,
GameConstants.StringConstants.scoreStarsKey: stars,
GameConstants.StringConstants.scoreCoinsKey: superCoins
]
ScoreManager.compare(scores: [scores], in: levelKey)
createAndShowPopup(type: 1, title: GameConstants.StringConstants.completedKey)
if level < 9 {
let nextLevelKey = "Level_\(world)-\(level+1)_Unlocked"
UserDefaults.standard.set(true, forKey: nextLevelKey)
UserDefaults.standard.synchronize()
}
}
Ignore the stars, I used these to show basically how well you did on the level. I'll gladly provide more code snippets if needed too. Thank you all again!

realmOC can't update data

addobject is success. but i want to update data. After realm.beginWriteTransaction() executes, breakpoint can't continue execute backup.quanId = 5, it's like just jump over.
class YQQuanBackup: RLMObject {
dynamic var groupId:Int = 0
dynamic var quanId:Int = 0
dynamic var content:String = ""
}
GCDBlock.async(.Default) {
let results:RLMResults = YQQuanBackup.objectsWhere("groupId == %d", self.groupInfo!.groupId)
let quanBackup = results.firstObject() as? YQQuanBackup
guard let backup = quanBackup else { return }
let realm = RLMRealm.defaultRealm()
realm.beginWriteTransaction()
backup.quanId = 5
backup.content = YQRichTextUtil.richTextToPublishText(self.textView.attributedText, uploadedImageUrls: self.uploadedImageUrls)
do {
try realm.commitWriteTransaction()
} catch {
print(error)
}
}