0

I am making my View Identifiable like this code:

struct RedView: View, Identifiable {
    
    let id: UUID = UUID()
    
    var body: some View {

        Color.red.frame(width: 100, height: 100, alignment: .center)
        
        
    }
}

Now I want make a CustomViewModifier which only work or be applicable on Views which they are Identifiable, for example to make normal ViewModifier, we do not need that our content conform to Identifiable, they must just conform to View, In this question/problem I want make a CustomViewModifier which require it contents conform to View and Identifiable, how can I do this?

here what tried so far, need help to complete:

struct CustomViewModifier<InPutContent: View & Identifiable>: ViewModifier {

    func body(content: InPutContent) -> some View  {

        return content.onAppear() { print(content.id) }

    }

}

use case:

import SwiftUI

struct ContentView: View {

    var body: some View {

        RedView()
            .modifier(CustomViewModifier())  // It must work! because RedView is Identifiable!
        
        Text("Hello")
            .modifier(CustomViewModifier())  // It must NOT work! because Text is not Identifiable!
 
    }
}



UPDATE:


struct CustomViewModifier<InPutContent: View & Identifiable>: ViewModifier {
    
    var inPutContent: () -> InPutContent

    func body(content: Content) -> some View  {

        return body2(content: inPutContent())

    }

    func body2(content: InPutContent) -> some View  {

        return content.onAppear() { print(content.id) }

    }

}

use case:

import SwiftUI

struct ContentView: View {
    var body: some View {
        
        RedView()
            .modifier(CustomViewModifier(inPutContent: { RedView() }))       // compiles
        
        Text("Hello")
            .modifier(CustomViewModifier(inPutContent: { Text("Hello") }))   // does not compile
        
    }
}
ios coder
  • 1
  • 4
  • 31
  • 91
  • See [this](https://stackoverflow.com/questions/56833659/what-is-content-in-swiftui). You don't get to decide what `Content` is. – Sweeper Mar 20 '21 at 07:31
  • @Sweeper: I know that, that is why I want make **CustomViewModifier** which I can see through my Content before they pass into **CustomViewModifier** – ios coder Mar 20 '21 at 07:35
  • @Sweeper: I add some new code to show you what I want – ios coder Mar 20 '21 at 07:38
  • You don't seem to have understood. You are trying to strengthen the precondition here, which you definitely can't do. The protocol is telling you "to conform to me, you must implement a method that accepts some sort of `View`", but you insist on saying "nope, I will only provide a method that takes an _identifiable_ `View`". Do you see why you are unreasonable now? How about _not_ using `ViewModifier` and instead just do a plain old `extension` of `View where Self: Identifiable`? – Sweeper Mar 20 '21 at 07:41
  • I am okey with anything which help me to solve my issue, – ios coder Mar 20 '21 at 07:45
  • @Sweeper: I like to know if you see any way that I could use **content** as **inPutContent**, then I could omit **inPutContent: { RedView() }** from **CustomViewModifier(inPutContent: { RedView() })** – ios coder Mar 20 '21 at 08:15
  • No, `Content` is defined by the `ViewModifier` protocol to be `_ViewModifier_Content>`. You don't get to redefine it. – Sweeper Mar 20 '21 at 08:17
  • yes, you right! I have no access to **content** until it get used **func body(content: Content) -> some View**, from the other side I have access to **inPutContent** because of **var inPutContent: () -> InPutContent**, But It makes so hard for me to know where this **Content** defined at first place? We have to define **Content** every where to make it usable, but here you can use **Content** magically! which make problem to me to solve my issue in better way. – ios coder Mar 20 '21 at 08:26
  • 1
    See the link in my first comment. It should explain where `Content` is declared. – Sweeper Mar 20 '21 at 08:34

1 Answers1

1

One of the requirements of ViewModifier is that you are able to modify any view. Clearly, you cannot do that in this case, so ViewModifier is not suitable.

Try writing an extension on View where Self: Identifiable instead:

extension View where Self: Identifiable {
    func printId() -> some View  {
        return onAppear() { print(id) }
    }
}

usage:

struct ContentView: View {

    var body: some View {

        RedView()
            .printId()  // compiles
        
        Text("Hello")
            .printId()  // does not compile
 
    }
}

Comparison between ViewModifier and extensions

Sweeper
  • 213,210
  • 22
  • 193
  • 313