Unknown error in Swift Playground caused by long literals - swift

Within my Swift Playgrounds source directory I placed the following code.
public func startPlayground() {
let list = [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]]
print(list.count) // 282
}
The nested array consists of 282 elements of the form [0,0,0]. The playground itself then just calls startPlayground() within the Contents.swift
On macOS, the playground executes correctly and outputs 282. On Swift Playgrounds 2.2 for iPad, executing this playground results in the message: "Unknown error while executing the playground".
How can I avoid this?

This seems to be a memory related issue on Swift Playgrounds, taken into account the already known issues:
Limited number of views in Swift Playgrounds
Memory Limit of Swift Playgrounds
Such long literals are seemingly too much for the iPad version of Swift Playgrounds. However, adding the elements at runtime works fine:
var list = [[0,0,0]]
for _ in 1...282 {
list.append([0,0,0])
}

Related

Immutable value never used in for in loop

I'm learning Swift and have started a Playground in Xcode 9.2. I've got the following code and whilst it is running as expected, it's giving me an warning message. What does it mean? I tried searching elsewhere but I can't find out why it's returning a warning.
for myCounter in 1...3 {
print("My counter")
}
The warning:
Immutable value 'myCounter' was never used; consider replacing with '_' or removing it
I tried doing what it said, and it seemed to work and not return any warnings, but why would that make a difference?
for _ in 1...3 {
print("My counter")
}
What's the difference here and why does it cause this?
The warning is telling that you are not using myCounter for anything, when you don't care about something in Swift you use _ to tell the compiler that your intention is to not use that value.
The warnings would also go away if you started using the value:
for myCounter in 1...3 {
print("My counter: \(myCounter)")
}
Swift has a smart compiler which optimizes. You are assigning 1, 2, and 3 into variable storage, to no purpose; you never use that variable for anything. So that is a waste of time and storage space. Therefore the compiler warns you to try to get you to improve the program. You did. It stopped warning.

Get Around the "Initialization of immutable value 'variableName' was never used" Warning in Swift 3 Switch Statements

So I have some code that looks like this:
fileprivate func enumSwitchTime(_ optionalString: String?) {
if let nextEnumToSwitchOn = funcToGetEnum()
switch nextEnumToSwitchOn {
case .enumStateOne(let associatedEnumValue):
if let optionalString = optionalString {
//do stuff with both associatedEnumValue and optionalString
}
case .enumStateTwo...
.
.
.
}
}
However since Swift 3 (I'm using Xcode 8.1) I am getting the "Initialization of immutable value 'associatedEnumValue' was never used..." warning on the that first case.
I am still getting my toes wet in Swift, but so far I see no way around this. I can't do an underscore parameter in the case statement and then declare the associated enum value later, after the let optionalString = optionalString, or at least I haven't found any way of doing that.
It is just a warning, but I don't like warnings in my code. Any way around this?
Well, as it turns out this was an Xcode error/issue.
After cleaning my project and restarting Xcode multiple times, and the warning persisting, I posted the question here thinking I was missing something.
After Martin R said if the variable is used in any code path the warning shouldn't be there, I futzed around with the code, undid those changes, cleaned the project, restarted Xcode and FINALLY the warning went away.

NSUndoManager casting NSUndoManagerProxy crash in Swift code

In our application we're using the following code:
let lInvocationTarget = lUndoManager.prepare(withInvocationTarget: self)
let _ = (lInvocationTarget as! MyObjectType).myMethod(_: self.opacity, undoManager: lUndoManager)
This compiles without warnings and runs fine under macOS 10.12 Sierra. However it crashes at runtime on 10.9 - 10.11 (Mavericks till El Capitan).
The crash report notices:
Could not cast value of type 'NSUndoManagerProxy' (0x7fff76d6d9e8) to 'MyObjectType' (0x108b82218).
Then I rewrote the code to:
if let lInvocationTarget = lUndoManager.prepare(withInvocationTarget: self) as? MyObjectType {
let _ = lInvocationTarget.setOpacity(_: self.opacity, undoManager: lUndoManager)
}
Then it doesn't crash, but then Undo is not working at all.
This last way of writing comes directly out of Apples documentation, so apparently behaviour changed in Swift 3 or 10.12 SDK. I'm using Xcode 8.2 with Swift 3 and SDK 10.12
The registerUndo(withTarget, selector:, object:) is not suitable because I have a lot of other undoable methods with more arguments. Really don't want to wrap those in a dictionary orso. And even when selectors are pretty type safe nowadays, I still don't like them.
There is also the block based API (registerUndo(withTarget: handler:) ), but that is unfortunately only for 10.11+.
Anyone encountered the same problem? And more important: anyone come up with a way out?
I am so much astonished that I hear your first code works on macOS 10.12. The method prepare(withInvocationTarget:) has been a this-hardly-works-in-Swift thing. Not only the returned proxy object is not the instance of the original class, but neither the object is not a descendent of NSObject (at lease in some former OS Xs).
Anyway, this is one thing worth trying:
let lInvocationTarget = lUndoManager.prepare(withInvocationTarget: self)
_ = (lInvocationTarget as AnyObject).myMethod(self.opacity, undoManager: lUndoManager)
I found registerUndoWithTarget:handler: is a better API now.

Is there way for Swift code to detect if it's being run in a playground or not?

To be able to test GameKit features, I'd like to be able to detect if the code is being run in a Playground, so that it can just skip the network calls. Is there a way to do this?
edit:
Forget about GameKit--that just muddies the issue. There are many different scenarios where this would be useful. It's really just a simple question about whether a specific function call exists or not: is there a method that returns true if the code is running in a Playground?
I don't know of a documented way to do it, but there are some undocumented things you can do.
Here's a technique that works in both Xcode 7 with Swift 2.2 and Xcode 8 with Swift 3.0, in both macOS and iOS playgrounds: check for a bundle whose identifier starts with "com.apple.dt".
// Swift 2.2
if NSBundle.allBundles().contains({ ($0.bundleIdentifier ?? "").hasPrefix("com.apple.dt.") }) {
print("in playground")
} else {
print("not in playground")
}
// Swift 3.0
if Bundle.allBundles.contains(where: { ($0.bundleIdentifier ?? "").hasPrefix("com.apple.dt.") }) {
print("in playground")
} else {
print("not in playground")
}
Note that com.apple.dt. is not a prefix reserved specifically for a playground-related bundle; the dt part standards for something like “developer tool”. So there might be circumstances where you get a false positive: there's a bundle that matches but you're not in a playground. I'm not aware of any such circumstances, but there might be some. I did test an IBDesignable view in a macOS xib under Xcode 7, and it didn't have any com.apple.dt. bundles loaded.

exc_bad_access using WKInterfaceSlider

I can't use WKInterfaceSlider without having exc_bad_access error.
I'm using this code:
#IBAction func sliderChanged(value:AnyObject) {
println(value)
}
Sometimes it works for the first click on +/-
Update:
WKInterfaceSlider works using Objective-C.
See XCode 6.2 Beta release notes: "Known Issues - XCode Interface Builder"
"After creating IB Actions in Swift for WKInterfaceSwitch or WKInterfaceSlider objects,
storyboards fail to compile with an error such as "Argument to 'IBAction' method cannot have
non-object type." (19003052"
Solution: remove "#IBAction" annotation (which implies #objc). Should still work ok.