I want to use this iteration function to check a array, and store the result with new array, and then check the new array again and again...however I don't know how to clear the the old useless arrays so that the memory can be released.
func checkEnvironment(environment: [MGLPolygon], seed: MGLPolygon) -> [MGLPolygon]?{
var newEnv: [MGLPolygon]?
var alien: MGLPolygon?
var check = false
for i in 0..<environment.count{
if detectIntersect(poly1: seed, poly2: environment[i]) && check == false{
check = true
alien = seed
newEnv?.append(alien!)
}else{
newEnv?.append(environment[i])
}
}
if check == false{
// error occurs on here
environment.removeAll()
return newEnv!
}else{
checkEnvironment(environment: newEnv!, seed: alien!)
}
return nil
}
in the code
environment.removeAll()
gets a error that says environment is a let static so I can't change it. My question is how do I release the memory form those array?
Any help would be appreciate.
In swift3, function parameter are immutable so in order to change the value you need to add a var and assign into it like below.
func checkEnvironment(environment: inout [MGLPolygon], seed: MGLPolygon) -> [MGLPolygon]?{
if check == false{
environment.removeAll()
return newEnv!
}
}
Related
I am experiencing a bit of trouble, while working on my app in SwiftUI.
I want to append relevant data, summarized in an object, to an array and return this.
While returning the array, I could see by debugging, that it is empty. Debugging in the for loop showed me, that location objects are created and appended, but are not being "saved" in the array. The "mapItems" array on the other hand has lots of members.
What am I missing?
Here is the method I came up with:
func searchForLocation(searchTerm: String) -> Array<Location>{
var locations = [Location]
let searchReqeust = MKLocalSearch.Request()
searchRequest.region = region //region is a published variable and is determined before
searchRequest.naturalLanguageQuery = searchTerm
let search = MKLocalSearch(request: searchRequest)
search.start{response, error in
//error handling
.
.
.
//empty response.mapItems handling
.
.
.
for item in response!mapItems{
let location = createLocationFromItem(item: item)
locations.append(location)
}
}
return locations
}
My locations class if following:
class Location: Identifiable{
var id= UUID()
var coordinates: CLLocationCoordinate2d
//And its proper init method
}
Your searchForLocation has an asynchronous function inside (search.start{...}),
and your code returns before it has finished getting the results.
To "wait" for the results use a completion/closure handler,
something like this:
func searchForLocation(searchTerm: String, completion: #escaping ([Location]) -> ()) {
var locations = [Location]() // <-- here
// ....
search.start{response, error in // <-- here asynchronous function
//... todo deal with errors, eg return completion([])
for item in response!mapItems {
let location = createLocationFromItem(item: item)
locations.append(location)
}
completion(locations) // <- here return when finished
}
}
and call the function like this:
searchForLocation(searchTerm: "Tokyo") { results in
print("\(results)") // <-- here results available, not before
}
I suggest you read-up on how to create and use asynchronous functions, these are important concepts to master to code effectively in Swift.
I have a simple AudioKit app in the works.
I initialize an AKOsicillatorBANK at runtime and allow you to press a button to access a new viewCONTROLLER which has SLIDERS that when changed change the values of the oscillatorBANK properties [releaseDURATION, attackDURATION, decayDURATION, sustainLEVEL].
At the end of the slider's PANGESTURE [state == ended], I call a function that sets the oscillatorBANKS properties to their new values, which are stored in class variables.
I do not know why, but the changes only take effect some time (a few minutes) after the function is called. Does anyone know why this is?
ALSO PLEASE DO NOT COMMENT ON MY CAPITALIZATION STYLE. I PREFER THIS AS IT ALLOWS ME TO EMPHASIZE WHAT I BELIEVE TO BE IS IMPORTANT, WHICH CAN THEN HELP YOU SEE MY TRAIN OF THOUGHTS BETTER.
HERE IS THE CODE. Please note that I ONLY included the code for DECAY within the panGESTURE, because attack, release, and sustain code is all the same design:
// MAIN VIEW CONTROLLER CLASS, GLOBAL SCOPE, INITIALIZED WITH VIEW DID LOAD //
let bank = AKOscillatorBank()
var bankATTACK: Double = 0
var bankDECAY: Double = 0
var bankSUSTAIN: Double = 1
var bankRELEASE: Double = 0
func updateBANKWAVE() {
self.bank.rampDuration = 1
self.bank.attackDuration = self.bankATTACK
self.bank.decayDuration = self.bankDECAY
self.bank.sustainLevel = self.bankSUSTAIN
self.bank.releaseDuration = self.bankRELEASE
print("NEW BANK RAMP [\(self.bank.rampDuration)]")
print("NEW BANK ATTACK [\(self.bank.attackDuration)]")
print("NEW BANK DEC [\(self.bank.decayDuration)]")
print("NEW BANK SUS [\(self.bank.sustainLevel)]")
print("NEW BANK REL [\(self.bank.releaseDuration)]")
}
func prepareforSEGUE() {
if let sliderCONTROLLER = segue.destination as? SLIDERVIEWCONTROLLER {
sliderCONTROLLER.mainCONTROLLER = self
}
}
// SLIDER VIEW CONTROLLER CLASS //
if panGESTURE.state == changed {
// ... update a UILabel to reflect the value to be set ...
decayTEXT = String(format: "%.3f", (self.decayTRANSLATION.truncatingRemainder(dividingBy: 100.0)))
// ... update the MAIN controller variables ...
self.mainCONTROLLER.bankDECAY = Double(self.decayTRANSLATION.truncatingRemainder(dividingBy: 100.0))
// ... protect against values above 10 or below 0 ...
if decayTRANSLATION > 10 { decayVALUE.text = "10.000" ; decayTRANSLATION = 10.01 ; self.mainCONTROLLER.bankDECAY = 10 }
if decayTRANSLATION < 0 { decayVALUE.text = "0.000" ; decayTRANSLATION = -0.01 ; self.mainCONTROLLER.bankDECAY = 0 }
}
if panGESTURE.state == ended {
self.mainCONTROLLER.updateBANKWAVE()
}
By changing the oscillatorBANK.rampDURATION property to 0 instead of 1, I get instantaneous results. However, even though the release is being set to 1, the note can still be heard after 4 or 5 seconds... so...
I tried to edit a list in-place but wasn't able to get it working. Now trying to edit individual elements and add them to a second list. However the second list remains null and does not get updated. Any help would be appreciated.
var localFiles: MutableList<String> = File(localPath).list().toMutableList()
var localFileDates: MutableList<String>? = null
val iterateLocal = localFileDates?.listIterator()
for (item in localFiles) {
var date = item.takeLast(10).take(6)
if (date.matches("[0-9]+".toRegex()) and (date.length == 6) and (date != null) and (date != "null")) {
iterateLocal?.add(item.takeLast(10).take(6))
}
}
println(networkFiles) // prints correct outpu
println(localFileDates) // prints null
You need init localFileDates variable:
var localFileDates = MutableList()
var localFiles: MutableList<String> = File(localPath).list().toMutableList()
var localFileDates = MutableList<String>()
val iterateLocal = localFileDates?.listIterator()
for (item in localFiles) {
var date = item.takeLast(10).take(6)
if (date.matches("[0-9]+".toRegex()) and (date.length == 6) and (date != null) and (date != "null")) {
iterateLocal?.add(item.takeLast(10).take(6))
}
}
println(networkFiles) // prints correct outpu
println(localFileDates) // prints correct
It is better to use map{..} function to create a copy of the list with updated values.
val localFiles = File(localPath).list()?.toMutableList() ?: listOf()
val localFileDates = localFiles.mapNotNull { item ->
val date = item.takeLast(10).take(6)
if (date.matches("[0-9]{6}".toRegex()) {
date
} else {
null
}
}
println(localFiles)
println(localFileDates)
I use the mapNotNull{..} function calls the block for every element of the list and builds the new list only from non-null values.
You do not need var in your code, explicit type names can be omitted too.
The condition can be simplified - no need for the null check, the regular expression filters our the data == "null" case, the length check can be included into the regex too. The date variable can be re-used too.
A more idiomatic (and readable) way:
val localFileDates = File(localPath).list().map { it.takeLast(10).take(6) }.filter {
it.matches("[0-9]+".toRegex()) && (it.length == 6) && (it != "null")
}
Also I suggest you create a named function for takeLast(10).take(6) and the condition to make it clear what is the intent of these lines of code.
I'm pretty new to Swift and I learn by using the "App Development with Swift"-Book.
Could you please check the code below - it doesn't work and I can't figure out why.
import UIKit
func isBelow13(number: Int) -> Bool {
let isBelow: Bool = false
if number < 13 {
let isBelow = true
} else {
let isBelow = false
}
return isBelow
}
isBelow13(number: 11) // returns false, should return true
isBelow13(number: 14) // returns false
Cheerio!
You're defining isBelow as false first, then inside your if statements you're defining a new constant called isBelow. This new constant has the same name as the above one, but is actually totally different. When you're outside of your if statements that one you created inside the if statements doesn't exist anymore and it just returns the one you first created. You're not actually changing the first isBelow that you set initially at all.
What you're actually trying to do can be accomplished like this:
func isBelow13(number: Int) -> Bool {
var isBelow: Bool = false
if number < 13 {
isBelow = true
} else {
isBelow = false
}
return isBelow
}
isBelow13(number: 11) // returns true
isBelow13(number: 14) // returns false
This way you are creating a variable that can be re-assigned "var" instead of "let" and then you are changing the value of that variable based on the if statement condition. Then you're returning that changed value. Make sense?
A more concise version of the same above code would look like this: (From #MartinR in the comments)
func isBelow13(number: Int) -> Bool {
return number < 13
}
The expression number < 13 returns a boolean value so you can just return the result of that expression from your function.
Following the update to Swift 3, it appears both getUUIDBytes and getBytes are not available on the UUID object.
let uuid = UIDevice.current.identifierForVendor
let mutableUUIDData = NSMutableData(length:16)
uuid.getBytes(UnsafeMutablePointer(mutableUUIDData!.mutableBytes))
// ^^^ compiler error, value of type UUID? has no member getBytes
I get this error even when getBytes is listed as a method on UUID in the documentation: https://developer.apple.com/reference/foundation/nsuuid/1411420-getbytes
One right way:
let uuid = UIDevice.current.identifierForVendor!
var rawUuid = uuid.uuid
withUnsafePointer(to: &rawUuid) {rawUuidPtr in //<- `rawUuidPtr` is of type `UnsafePointer<uuid_t>`.
rawUuidPtr.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<uuid_t>.size) {bytes in
//Use `bytes` only in this closure. (Do NEVER export `bytes` out of the closure.)
print(bytes[0],bytes[1])
//...
}
}
Another right way:
withUnsafePointer(to: &rawUuid) {rawUuidPtr in //<- `rawUuidPtr` is of type `UnsafePointer<uuid_t>`.
let bytes = UnsafeRawPointer(rawUuidPtr).assumingMemoryBound(to: UInt8.self)
//Use `bytes` only in this closure. (Do NEVER export `bytes` out of the closure.)
print(bytes[0],bytes[1])
//...
}
As already commented by Rob, exporting the pointer passed to the closure argument of withUnsafeBytes is completely NOT guaranteed. A slight change of the context (32-bit/64-bit, x86/ARM, Debug/Release, adding seemingly unrelated code...) would make your app a crasher.
And one more important thing is that UTF-8 Data of the uuidString and the byte sequence of NSUUID.getBytes are completely different:
let nsUuid = uuid as NSUUID //<-Using the same `UUID`
let mutableUUIDData = NSMutableData(length:16)!
nsUuid.getBytes(mutableUUIDData.mutableBytes.assumingMemoryBound(to: UInt8.self))
print(mutableUUIDData) //-><1682ed24 09224178 a279b44b 5a4944f4>
let uuidData = uuid.uuidString.data(using: .utf8)!
print(uuidData as NSData) //-><31363832 45443234 2d303932 322d3431 37382d41 3237392d 42343442 35413439 34344634>
You are thinking too complicated:
func getUUID ( ) -> Data {
let uuid = NSUUID()
var bytes = [UInt8](repeating: 0, count: 16)
uuid.getBytes(&bytes)
return Data(bytes: bytes)
}
Why does that work?
Consider you have:
func printInt(atAddress p: UnsafeMutablePointer<Int>) {
print(p.pointee)
}
then you can in fact do this:
var value: Int = 23
printInt(atAddress: &value)
// Prints "23"
but you can also do this:
var numbers = [5, 10, 15, 20]
printInt(atAddress: &numbers)
// Prints "5"
It's a form of "implicit bridging". To quote from Swiftdoc.org:
A mutable pointer to the elements of an array is implicitly created
when you pass the array using inout syntax.
This implicit bridging only guarantees valid pointers until the current function returns. Such pointers must never "escape" the current function context, but using them as an inout argument is always safe, as inout arguments were always only guarantee to be valid until the called function returns and the called function must return prior to the current one, so this cannot go wrong.
And for those that don't know, casting UUID to NSUUID (... as NSUUID) and the other way round (... as UUID) is guaranteed to always succeed. But if you insist on using UUID, the easiest way is:
private
func getUUID ( ) -> Data {
var uuid = UUID().uuid
return withUnsafePointer(to: &uuid) {
return Data(bytes: $0, count: MemoryLayout.size(ofValue: uuid))
}
}