override func layoutAttributesForElements(in rect: CGRect) -> [AnyObject]? {
var layoutAttributes = [UICollectionViewLayoutAttributes]()
// Loop through the cache and look for items in the rect
for attributes in cache {
if attributes.frame.intersects(rect ) {
layoutAttributes.append(attributes)
}
}
return layoutAttributes }
Here I'm getting the error.
Method does not override any method from it's superclass.
How can I resolve the issue.
Any one can you please help me.
Thanks in Advance.
If you are really trying to override that method in its right place, Try removing the method name and type override func layoutAttributes and select the correct override from auto complete. These kind of problems sometimes occur because of Swift's syntax changes in different versions of swift
Try removing the override should work.
Related
I just can´t find out how to get access to custom layout attributes in the apply() method of a custom cell.
I have to implement a custom layout attribute to my CollectionViewLayoutAtrributes, so I subclassed them. This works well so far:
class TunedLayoutAttributes: UICollectionViewLayoutAttributes {
var customLayoutAttributeValue: CGFloat = 1000
override func copy(with zone: NSZone?) -> Any {
let copy = super.copy(with: zone) as! TunedLayoutAttributes
customLayoutAttributeValue = customLayoutAttributeValue
return copy
}
override func isEqual(_ object: Any?) -> Bool {
if let attributes = object as? TunedLayoutAttributes {
if attributes. customLayoutAttributeValue == customLayoutAttributeValue {
return super.isEqual (object)
}
}
return false
}
}
The value has to dynamically change based on user scroll interaction.
Now I need my custom cells to update their appearance after an invalidateLayout call from the custom UICollectionViewLayout class. To my knowledge this usually can also be done by overriding the cells classes apply(_ layoutAttributes: UICollectionViewLayoutAttributes) method.
Usually like so:
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
let newFrame = // calculations here. CGRect(....)
layoutAttributes.frame = newFrame
}
Now the missing chemistry:
Unlike in the apply() example above my new customLayoutAttributeValue is (of course?) not part of the layoutAttributes: in the method.
So I tried to downcast the layoutAttributes to my custom class like so:
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
let tunedLayoutAttributes = layoutAttributes as! TunedLayoutAttributes
tunedLayoutAttributes.customLayoutAttributeValue = // calculation here.
}
So how do I get access to tunedLayoutAttributes in the apply() method?
Any help is appreciated. Thanks for reading!
You kind of gave the solution to yourself here. UICollectionViewLayoutAttributes does (of course) not know about customLayoutAttributeValue, so you have to cast to the appropriate class (TunedLayoutAttributes, in your case).
Now in order for apply(_:) to actually give you TunedLayoutAttributes and not just plain UICollectionViewLayoutAttributes, you need to tell your UICollectionViewLayout subclass to use your custom class (TunedLayoutAttributes) when vending layout attributes for items in the layout.
You do that by overriding class var layoutAttributesClass in you layout subclass.
Note that if you override layout attributes vending methods (layoutAttributesForElements(in:) and friends) in your layout subclass, you'd need to return TunedLayoutAttributes there for the whole thing to work.
Also note that UIKit frequently copies attributes under the hood when performing collection view layout passes, so make sure your copy and isEqual methods are working as expected. (e.g., the attributes objects passed to apply(_:) are not (necessarily) the objects your layout vended, but rather copies.
Edit
As discussed in the comments, you should replace the forcecast as! with an if let as? cast to prevent crashes when apply(_:) actually gets passed plain UICollectionViewLayoutAttributes.
I created a question a few days ago and was provided with protocol on how to solve an issue of passing data back and forth . I have also looked at some tutorials and have created a protocol but it is not working or even hitting the breakpoint from what I can see it should be working. I have created a protocol for my AVPlayer so that on tap it could get a new video but like i said it's not even hitting the breakpoint this is my code...
protocol CustomAVPLayerProtocol: class {
func reloadTabled(at index: Int)
}
class CustomAVPLayerC: AVPlayerViewController {
var delagate: CustomAVPLayerProtocol?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.delagate?.reloadTabled(at: 1)
for touch in touches {
self.delagate?.reloadTabled(at: 1)
print("Tapped")
// When I tap the AVPlayer this print statement shows
// So I know it is coming here
}
}
}
Now This is my second class/controller
class BookViewC: UIViewController, CustomAVPLayerProtocol {
override func viewDidLoad() {
super.viewDidLoad()
PlayVideo(250, "url")
}
func reloadTabled(at index: Int) {
print("This protocol method does not execute or hit breakpoint")
self.PlayVideo(250, "url")
}
func PlayVideo(MediaHeight: Float, MediaURL: String) {
let movieURL = URL(string: MediaURL)
videoCapHeight.constant = CGFloat(MediaHeight)
streamsModel.playerView = AVPlayer(url: movieURL!)
streamsModel.MyAVPlayer.player = streamsModel.playerView
streamsModel.MyAVPlayer.videoGravity = AVLayerVideoGravity.resizeAspectFill.rawValue
streamsModel.MyAVPlayer.showsPlaybackControls = false
streamsModel.MyAVPlayer.view.frame = VideoView.bounds
VideoView.addSubview(streamsModel.MyAVPlayer.view)
self.addChildViewController(streamsModel.MyAVPlayer)
streamsModel.playerView?.isMuted = false
streamsModel.MyAVPlayer.player?.play()
}
}
As I stated before it is not even hitting the breakpoint on BookViewC.reloadTabled as suggestions would be great
As per your code these are some minor mistakes which you can correct to make it work.
1. `weak var delagate: CustomAVPLayerProtocol?`
*Make a weak delegate to save it from retaining a strong reference cycle and memory leaks.*
2. Code Snippet:
func PlayVideo {
let customPlayer = CustomAVPLayerC()
customPlayer.delegate = self
}
in Your Second ViewController, You need to assign your delegate to an object / view controller to make ie respond to
NOTE: In case you require, you can make a super class that conforms the your protocol class, so that your every view controller conforms it automatically, you just need to assign an delegate to class on which you want to use it.
You have the foundation set up correctly but remember that classes are (mostly) just blueprints for instances. These classes are useless until you create instances of them because it’s the instances that will do the work.
Therefore, simply pass one instance as the delegate of the other, which you can do here because you've correctly set up the protocol.
protocol CustomAVPLayerProtocol: AnyObject {
func reloadTabled(at index: Int)
}
class CustomAVPLayerC: AVPlayerViewController {
weak var delagate: CustomAVPLayerProtocol?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.delagate?.reloadTabled(at: 1)
for touch in touches {
self.delagate?.reloadTabled(at: 1)
print("Tapped")
}
}
}
class BookViewC: UIViewController, CustomAVPLayerProtocol {
override func viewDidLoad() {
super.viewDidLoad()
PlayVideo(250, "url")
}
func reloadTabled(at index: Int) {
PlayVideo(250, "url")
}
func PlayVideo(_ MediaHeight: Float, _ MediaURL: String) {
//
}
}
let book = BookViewC()
let layer = CustomAVPLayerC()
layer.delagate = book
Where you do this instantiation/delegation is up to you. Also, I know that a lot of people here use class to define protocols that only conform to classes, but Swift's documentation instructs us to use AnyObject.
Protocols are the most common means used by unrelated objects to communicate with each other. As per the above code, the communication did not seem to happen.
Your protocol declaration part seems alright. The problem exists in the secondViewController. I can see that you have not set the delegate to the object that's been created. Ideally, it has to be something like this:
Class BookViewC: UIViewController, CustomAVPLayerProtocol {
override func viewDidLoad() {
super.viewDidLoad()
PlayVideo(250, "url")
}
You need to the set the delegate here:
func PlayVideo {
let customPlayer = CustomAVPLayerC()
customPlayer.delegate = self //This makes the selector to respond
}
I'm in the process of translating my app to Swift 3. I stumbled upon an issue with using a clean way of setting datasource and delegate for a UICollectionView inside a UITableViewCell, described here.
The code is as follows:
func setCollectionViewDataSourceDelegate<D: protocol<UICollectionViewDataSource, UICollectionViewDelegate>>
(_ dataSourceDelegate: D, forRow row: Int) {
collectionView.delegate = dataSourceDelegate
collectionView.dataSource = dataSourceDelegate
collectionView.tag = row
collectionView.reloadData()}
And it throws a warning, stating:
'protocol<...>' composition syntax is deprecated; join the protocols using '&'
When I accept the suggested solution, it changes the D: protocol<UICollectionViewDataSource, UICollectionViewDelegate> into a D: (UICollectionViewDatasource & UICollectionViewDelegate) call, and instead throws an error:
Expected a type name or protocol composition restricting 'D'
I'd be much obliged if someone with a better understanding of Swift 3 generics than myself could suggest a solution.
No need to use protocol<> because the compiler already knows that. Just join the protocols like this: D: UITableViewDelegate & UITableViewDataSource
setCollectionViewDataSourceDelegate for swift3
extension PollTableViewCell {
func setCollectionViewDataSourceDelegate<D: UICollectionViewDataSource & UICollectionViewDelegate>(_ dataSourceDelegate: D, forRow row: Int) {
theCollectionView.delegate = dataSourceDelegate
theCollectionView.dataSource = dataSourceDelegate
theCollectionView.tag = row
theCollectionView.setContentOffset(theCollectionView.contentOffset, animated:false) // Stops collection view if it was scrolling.
theCollectionView.reloadData()
}
var collectionViewOffset: CGFloat {
set {
theCollectionView.contentOffset.x = newValue
}
get {
return theCollectionView.contentOffset.x
}
}
}
I've tried looking at other StackOverflow inquires about this, I can't seem to find the solution to this. I'm not sure if this is due to me looking at threads which are non-Swift 2.0.
I will need NSNotification to pass any kind of value to my Main View Controller. But I keep getting:
Optional(foobar)
Here's a function on View Controller B:
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let notificationName = "CoreLocationNSN"
let notification = NSNotification(name: notificationName, object: self, userInfo: ["doge":"foobar"])
NSNotificationCenter.defaultCenter().postNotification(notification)
}
Here's my main View Controller's initialization function:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
NSNotificationCenter.defaultCenter().addObserver(self, selector: "testNSNWithObject:", name: CoreLocationNSN, object: nil)
}
func testNSNWithObject(notification: NSNotification) {
print("Printing...")
print(String(notification.userInfo!["doge"]))
print(String(notification.userInfo?["doge"]))
print(notification.userInfo!["doge"])
print(notification.userInfo?["doge"])
}
But, here's my output:
Printing...
Optional(foobar)
Optional(foobar)
Optional(foobar)
Optional(foobar)
You just need to unwrap the String
func testNSNWithObject(notification: NSNotification) {
if let dodge = notification.userInfo?["dodge"] as? String {
print(dodge)
}
}
I suggest you to avoid the force unwrap operator ! since it's dangerous and there are several safer solutions available in Swift.
I've solved it, looks like it can be unwrapped by adding ! at the end, for some reason I thought my compiler was yelling at me for doing so:
func testNSNWithObject(notification: NSNotification) {
print("Printing...")
print(String(notification.userInfo!["doge"]))
print(String(notification.userInfo?["doge"]))
print(notification.userInfo!["doge"]!) // <<-- THIS ONE WORKED!
print(notification.userInfo?["doge"]!)
}
Just going to keep this here since this issue has been troublesome for me in the past and the syntax seems very strange.
Does anyone know what else I could have done instead that would've removed the "Optional()" from the string?
I'm new to Swift, I'm trying to create a new Cocoa Application based on the following code:
Drag and Drop in Swift - Issues with Registering for Dragged Types?
I'm doing this:
create Swift Cocoa Application
add a Custom View
add a Swift Class subclass of NSView named DropView
set the Custom View class to DropView
paste the referenced code in DropView
Then I'm getting a few errors, and I'm not really understanding why and how to solve it. Can someone help me?
As the first error says, you need to add the override to your init method:
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
}
Also there are some changes in the draggingEntered and the draggingUpdated methods. You don't need the ! for your NSDraggingInfo anymore:
override func draggingEntered(sender: NSDraggingInfo) -> NSDragOperation {
return NSDragOperation.Copy
}
override func draggingUpdated(sender: NSDraggingInfo) -> NSDragOperation {
return NSDragOperation.Copy
}
To check the correct implementation of a method you want to override, just start typing the method-name in your file and Xcode will create you the method with header etc:
To fix your last error, you need to implement the required init the NSView needs:
required init?(coder: NSCoder) {
super.init(coder: coder)
}
To help you for further errors like these: Often Xcode itself helps you to solve the problems. Especially if you see the round error-circle on the left side of your editor. Just click on it and check what Xcode recommends: