How to fix Objective C Methods SWIFT - swift

How would I fix this problem?
Here's the code
//
// TTTImageView.swift
// TicTacToe
import UIKit
class TTTImageView: UIImageView {
var player:String?
var activated:Bool! = false
Problem is here and states "Method 'setPlayer' with objective c selector 'setPlayer:'conflicts with setter for 'player'with same objective c selector"
func setPlayer (_player:String){
self.player = _player
if activated == false{
if _player == "x"{
self.image = UIImage(named: "x")
}else{
self.image = UIImage(named: "o")
}
activated = true
}
}
}
I haven't tried anything yet but will greatly appreciate any help.

There error is explained here:
https://stackoverflow.com/a/28500768/3149796
There are lots of great Swift features that you can use instead of what you've got. Try a property observer (didSet) instead of creating a custom setter function. You can also clean up your code and make it safer with an optional binding (if let) and a where clause.
Also your activated property shouldn't be implicitly unwrapped (Bool!), but rather just Bool.
import UIKit
class TTTImageView: UIImageView {
var activated: Bool = false
var player: String? {
didSet {
if let player = self.player where self.activated == false {
if self.player == "x" {
self.image = UIImage(named: "x")
} else {
self.image = UIImage(named: "o")
}
self.activated = true
}
}
}
}

I had the same problem and I was able to fix it by using #nonobjc
More information here:
Swift 2, method 'setOn' with Objective-C selector 'setOn:' conflicts with setter for 'on' with the same Objective-C selector

change setPlayer to Player
I hope this helps

Related

Swift Mapkit remove annotations and release memory

I am using mapView.removeAnnotations(mapView.annotations) to remove annotations but I can see from debug in Xcode that the memory for each annotation is not released and this eventually causes my app to crash. Is there a way to release it? I have looked at ARC and deinit and weak but I can't see how this relates to my code.
import Foundation
import MapKit
class StationMarkerView: MKMarkerAnnotationView {
override var annotation: MKAnnotation? {
willSet {
guard let station = newValue as? Station else {
return
}
canShowCallout = true
let mapsButton = FavouriteButton()
let bool = station.is_favourite
let image = bool! ? "star.fill": "star"
mapsButton.setBackgroundImage(UIImage(systemName: image), for: .normal)
rightCalloutAccessoryView = mapsButton
markerTintColor = station.markerTintColor
glyphImage = station.glyphImage
}
}
}
I have tried using weak for "mapButton" but Xcode gives me a dealocation warning.
Thanks any help appreciated.
I found a quick and dirty solution to my problem. Removing the annotations and then changing the maptype seems to release all memory relating to the mapView.
So to refresh my map I do ...
mapView.removeAnnotations(mapView.annotations)
mapView.mapType = MKMapType.satellite
velibManager.fetchVelib()
mapView.mapType = MKMapType.standard

NSTouchBar integration not calling

I am integrating TouchBar support to my App. I used the how to from Rey Wenderlich and implemented everything as follows:
If self.touchBarArraygot filled the makeTouchBar() Method returns the NSTouchBar object. If I print out some tests the identifiers object is filled and works.
What not work is that the makeItemForIdentifier method not get triggered. So the items do not get created and the TouchBar is still empty.
Strange behavior: If I add print(touchBar) and a Breakpoint before returning the NSTouchBar object it works and the TouchBar get presented as it should (also the makeItemForIdentifier function gets triggered). Even if it disappears after some seconds... also strange.
#available(OSX 10.12.2, *)
extension ViewController: NSTouchBarDelegate {
override func makeTouchBar() -> NSTouchBar? {
if(self.touchBarArray.count != 0) {
let touchBar = NSTouchBar()
touchBar.delegate = self
touchBar.customizationIdentifier = NSTouchBarCustomizationIdentifier("com.TaskControl.ViewController.WorkspaceBar")
var identifiers: [NSTouchBarItemIdentifier] = []
for (workspaceId, _) in self.touchBarArray {
identifiers.append(NSTouchBarItemIdentifier("com.TaskControl.ViewController.WorkspaceBar.\(workspaceId)"))
}
touchBar.defaultItemIdentifiers = identifiers
touchBar.customizationAllowedItemIdentifiers = identifiers
return touchBar
}
return nil
}
func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItemIdentifier) -> NSTouchBarItem? {
if(self.touchBarArray.count != 0) {
for (workspaceId, data) in self.touchBarArray {
if(identifier == NSTouchBarItemIdentifier("com.TaskControl.ViewController.WorkspaceBar.\(workspaceId)")) {
let saveItem = NSCustomTouchBarItem(identifier: identifier)
let button = NSButton(title: data["name"] as! String, target: self, action: #selector(self.touchBarPressed))
button.bezelColor = NSColor(red:0.35, green:0.61, blue:0.35, alpha:1.00)
saveItem.view = button
return saveItem
}
}
}
return nil
}
}
self.view.window?.makeFirstResponder(self) in viewDidLoad() did solve the problem.

Cannot call a function within a didSet. Error message: "expression resolves to unused function"

class HomeViewController: UIViewController
{
// The timer is used to check when the download is complete and will only allow segues when it is
var timer = Timer()
var segueName: String = ""
static var didSelectTabBar = false
static var tabBarSegueName = ""
static var startAnimation: Bool = false
{
didSet
{
if startAnimation == true
{
updateCounting(<#T##HomeViewController#>)
loadAnimation(<#T##HomeViewController#>)
}
}
}
The variable for the didSet is being changed in a separate Swift file and works, I can get to the if statement. But I can't get the functions to work and receive the same error message for both.
updateCounting
func updateCounting(){
if MyVariables.allSoldiersDownloaded
{
HomeViewController.startAnimation = false
loadingImageView.stopAnimating()
loadingImageView.isHidden = true
if HomeViewController.didSelectTabBar == false
{
self.performSegue(withIdentifier: self.segueName, sender: nil)
}
timer.invalidate()
MyVariables().setGlobalSoldier(id: MyVariables.facebookSoldierID)
soldierOfHourButton.setTitle("Soldier of the Hour: \(MyVariables.globalSoldier.christian_names) \(MyVariables.globalSoldier.surname)", for: UIControlState.normal)
soldierOfHourButton.sizeToFit()
}
else {
//print("Not downloaded yet")
}
}
loadAnimation
func loadAnimation() {
//creates and stores all the names for the images used in an array
var imagesNames = ["run1-1.jpg", "run2-1.jpg", "run3-1.jpg", "run4-1.jpg", "run5-1.jpg", "run6-1.jpg", "run7-1.jpg", "run8-1.jpg", "run9-1.jpg", "run10-1.jpg", "run11-1.jpg"]
//create new uiimage array
var images = [UIImage]()
//loop through all the photos in the imagesNames array and add them to the images array
for i in 0..<imagesNames.count{
images.append(UIImage(named: imagesNames[i])!)
}
//tell testview what images to use for the animation
loadingImageView.animationImages = images
//tell testview how long to show a single image for
loadingImageView.animationDuration = 0.9
//start the animation in the image view called test view
loadingImageView.startAnimating()
loadingImageView.isHidden = false
}
Welcome to SO. Please provide as much info as you can (for example the full stack trace), and format your questions properly (see my edits). This way you will get help much much faster.
What is the meaning of <#T##HomeViewController#>?
It should be just updateCounting() and loadAnimation():
Replace
updateCounting(<#T##HomeViewController#>)
loadAnimation(<#T##HomeViewController#>)
with
updateCounting()
loadAnimation()

Swift - how to make inner property optional

My question is in regards to optionals in swift. Let say i have the following defined already:
if let myCell = cell as? AECell {
if !myCell.someView.hidden{
//how do i use optional on someView, perhaps someView will not exists
}
}
as you can see, what if someView is nil , how do i use an optional here to only execute the if statement if someView is not nil ..i tried the question mark:
if !myCell.someView?.hidden but its syntax is not correct
if let myCell = cell as? AECell, let someView = myCell.someView {
// someView is unwrapped now
}
This should do it:
if let myCell = cell as? AECell, let myView = myCell.someView where !myView.hidden {
// This gets executed only if:
// - cell is downcast-able to AECell (-> myCell)
// - myCell.myView != nil (-> unwrapped)
// - myView.hidden == false
}
You could use optional chaining
if let myView = (cell as? AECell).someView {
if !myView.hidden{
// do something
}
}
To answer the question directly, yes you can use optionals this way. The someView property of your cell must be defined as optional.
class MyCell: UICollectionViewCell {
var someView: AECell?
}
Then you can use the following syntax:
myCell.someView?.hidden = true
The behavior you're talking about is very much akin to Objective-C's nil messaging behavior. In Swift,you want to lean more towards confirming the existence of an object before manipulating it.
guard let myView = myCell.someView as? AECell else {
// View is nil, deal with it however you need to.
return
}
myView.hidden = false

UIImageView is NIL

I have a default image in viewItem to make sure that it is working, it shows on the detail view of the splitview.
#IBOutlet weak var ImageView: UIImageView!
var imageCache = [String: UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
self.configureView()
}
func configureView() {
if let detail: AnyObject = self.detailItem {
if let label = self.detailDescriptionLabel {
let dict = detail as [String: String]
label.text = ""
let s = dict["result"]
let vr = NString(string: s!)
let vrd = vr.doubleValue
let value = ceil(vrd*20)
let valueString = String(format: "%.0f", value)
vresult.text = "\(valueString)%"
getPic(dict) // <---- trouble maker
fitem.hidden = false
ritem.hidden = false
}
} else {
navigationController?.popViewControllerAnimated(true)
}
}
func getPic(item: [String: String]) {
var chachedImage = self.imageCache[item["image"]!]
println(item["image"]) // <-- prints out the url
if cachedImage == nil {
var imgUrl = NSURL(string: item["image"]!)
let request: NSURLRequest = NSURLRequest(URL: imgUrl!)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {( reponse: NSURLResponse!, data: NSData!, error; NSError!) -> Void in
if error == nil {
cachedImage = UIImage(data: data)
println("got here no problem") // <-- prints out
self.imageCache[item["image"]!] = cachedImage
println(self.imageCache) // <-- prints reference OK
dispatch_async(dispatch_get_main_queue(), {
self.ImageView.image = cachedImage // <---- offender
})
} else {
println("Error: \(error.localizedDescription)")
}
})
} else {
dispatch_async(dispatch_get_main_queue(), {
self.ImageView.image = cachedImage
})
}
}
ImageView is coming up nil every time.
fatal error: unexpectedly found nil while unwrapping an Optional value
but the default image shows. I've moved this out of the dispatch and even tried setting it straight from the viewDidLoad() always errors. It used to be a UIWebView and worked perfectly except that it would not cache anything. Since loading these images is a lot of work, I thought caching would be good, I've got caching working for thumbnails in the MASTER view.
It may be because of how your instaciating your viewcontroller.
let vc = MyViewController()
Something like this wont work. You're creating the VC without actually giving the storyboard a chance to link the IBOutlets. Instead use
storyboard.instantiateViewControllerWithIdentifier(identifier: String)
You may need to get reference to the storyboard using
let storyboard = UIStoryboard(name: name, bundle: NSBundle.mainBundle())
Hope this helps :)
Changing your variable name shouldn't make any difference except for readibility/maintainability unless there's a namespace conflict (good to understand why/where that might be happening). Also I was wondering - you made the IBOutlet'ed varable weak. When the last remaining strong ref to the object goes away, the weak references to the object are set nil by the runtime/garbage collector automatically. (Look up that section of the Swift documentation if you're not solid about it).
Maybe you should check your classes and controllers by adding deinit { println(,"function name deallocated' }. Between your use of weak and improved behavior seen when you change the variable name, it seems like there might be some weird (buggy) interactions going on in your app itself.
Well silly me. I've been working on this for a few days, I got the great idea to try and change the name, and it worked. I tried changing it back and it broke, apparently you can't use ImageView as a variable!
In my case was because I was using a nib and didn't register it.
Once I did registered it, it worked
My case Was Different I used
awakeFromNib()
instead of
viewDidLoad()
.