Search code examples
swiftobjective-cswiftuinotificationcenter

Notification Center - cannot be used on instance of nested type


I am trying to set up my Swift text and labels to work with notification center so what is displayed can be changed using an objective C file. My UpdateConnectionTypeText and UpdateStatusText works but I am getting the following errors for UpdateGreySubText, Text("Uploading memory model to controller"): "Instance member 'publisher5' of type 'ViewController.ContentView' cannot be used on instance of nested type 'ViewController.ContentView.ProgressBar'"

My Objective C code:


{
    UploadViewController* myView = [[UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:@"ID_VIEWV2_VIEW"];
 //   myView.delegate = self;
    [self presentViewController:myView animated:YES completion:^{
        [myView UpdateUploadProgressWithProgressValue:0.7];
        [myView UpdateInitialTextWithInitialTextParameter:@"Initial text here"];
        [myView UpdateAddressTextWithAddressTextParameter:@"Address text here"];
        [myView UpdateOrangeTextWithOrangeTextParameter:@"Orange text here"];
        [myView UpdateGreySubTextWithGreySubTextParameter:@"Grey sub text here"];
        [myView UpdateControllerTypeTextWithControllerTypeTextParameter:@"Controller text here"];
        [myView UpdateConnectionTypeTextWithConnectionTypeTextParameter:@"Connection text here"];
        [myView UpdateStatusTextWithStatusTextParameter:@"Status text here"];
        
    }];
}

My Swift code:


import Foundation
import SwiftUI

@objc public protocol ViewDelegate: NSObjectProtocol {
    @objc func ButtonPushed()
    
}

@objc class ViewController: UIViewController {
   
    @IBOutlet var ProgressBarView: UIView!
    
    // embed SwiftUI into the UIKit storyboard view controller
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let childView = UIHostingController(rootView: ContentView())
        addChild(childView)
        childView.view.frame = ProgressBarView.bounds
        ProgressBarView.addSubview(childView.view)
        childView.didMove(toParent: self)
        
    }
    
    @objc weak var delegate: ViewDelegate?
    
    //creating function for dictionary to store changes and create notification
    //This takes a value between 0 and 1 
    @objc func UpdateUploadProgress(progressValue: Float)
    {
        //First, we need to normalize the value which is between 0 and 0.99 to 0 and 0.8999996
        let normalizedValue = progressValue * 0.8999996
        let valueUpdate:[String: Float] = ["ProgressValue": normalizedValue]
        NotificationCenter.default.post(name:NSNotification.Name("COM.WWW.UpdateText0"), object: nil, userInfo:valueUpdate)
    }
    
    @objc func UpdateText1(Text1Parameter: String)
    {
        let textUpdate:[String: String] = ["Text1Parameter": Text1Parameter]
        NotificationCenter.default.post(name:NSNotification.Name("COM.WWW.UpdateText1"), object: nil, userInfo:textUpdate)
    }
    
    @objc func UpdateText2(AddressTextParameter: String)
    {
        let textUpdate:[String: String] = ["Text2Parameter": Text2Parameter]
        NotificationCenter.default.post(name:NSNotification.Name("COM.WWW.UpdateText2"), object: nil, userInfo:textUpdate)
    }
    
    @objc func UpdateText3(Text3Parameter: String)
    {
        let textUpdate:[String: String] = ["Text3Parameter": Text3Parameter]
        NotificationCenter.default.post(name:NSNotification.Name("COM.WWW.UpdateText3"), object: nil, userInfo:textUpdate)
    }
    
    @objc func UpdateText4(Text4Parameter: String)
    {
        let textUpdate:[String: String] = ["Text4Parameter": Text4Parameter]
        NotificationCenter.default.post(name:NSNotification.Name("COM.WWW.UpdateText4"), object: nil, userInfo:textUpdate)
    }
    
  
    @objc func UpdateText5(Text5Parameter: String)
    {
        let textUpdate:[String: String] = ["TextParameter": Text5Parameter]
        NotificationCenter.default.post(name:NSNotification.Name("COM.WWW.UpdateText5"), object: nil, userInfo:textUpdate)
    }
    
     @objc func UpdateText6(Text6Parameter: String)
     {
         let textUpdate:[String: String] = ["TextParameter": Text6Parameter]
         NotificationCenter.default.post(name:NSNotification.Name("COM.WWW.UpdateText6"), object: nil, userInfo:textUpdate)
     }
    
     @objc func UpdateText7(StatusTextParameter: String)
     {
         let textUpdate:[String: String] = ["Text7Parameter": Text7Parameter]
         NotificationCenter.default.post(name:NSNotification.Name("COM.WWW.UpdateText7"), object: nil, userInfo:textUpdate)
     }
    
    struct ContentView: View {
        //creating vars
        @State var progressValue: Float = 0.3
        //let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
        @State private var degress: Double = -110
        @State var Text1 = ""
        let label = UILabel()
        @State var Text2 = ""
        @State var Text3 = ""
        @State var Text4 = ""
        @State var fourLinesText = "More status text here. dlkfjglkdfjglkdfjglkdfjglk. This text will be 4 lines in length. 1234567891011121314151617181920. Controller responding. This text will be 4 lines in length. 1234567891011121314151617181920. Controller responding. This text will be 4 lines in length. 1234567891011121314151617181920"
        @State var Text5 = ""
        
        //setting up notification center to listen to addresses
        let publisher = NotificationCenter.default.publisher(for: NSNotification.Name("COM.WWW.UpdateText0"))
        let publisher8 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.WWW.UpdateText1"))
        let publisher6 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.CMW.COM.WWW.UpdateText2"))
        let publisher7 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.WWW.UpdateText3"))
        let publisher5 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.WWW.UpdateText4"))
        let publisher2 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.WWW.UpdateText5"))
        let publisher3 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.WWW.UpdateText6"))
        let publisher4 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.WWW.UpdateText7"))
        
        //display
        var body: some View {
            VStack {
                Spacer()
                    .frame(height: 70)
                
                if #available(iOS 16.0, *) {
                    Label("Resetting to upload mode.", systemImage: "icon")
                        .font(.title)
                        .foregroundColor(Color(hex: "000"))
                        .fontWeight(.bold)
                        .onReceive(publisher8) { obj in
                            let statusTextVal = obj.userInfo?["Text0Parameter"] as? String
                            fourLinesText = Text0Val!
                        }

                } else {
                    // Fallback on earlier versions
                    Label("Resetting to upload mode.", systemImage: "icon")
                        .font(.title)
                        .foregroundColor(Color(hex: "000"))
                }
                    
                    
                ZStack{
                    //background rectangle
                    RoundedRectangle(cornerRadius: 25)
                        .fill(Color(hex: "494949"))
                        .frame(width: 300, height: 300)
                    
                    ProgressBar(progress: self.$progressValue)
                        .frame(width: 250.0, height: 250.0)
                        .padding(40.0)
                        .onReceive(publisher) { obj in
                            let progVal = obj.userInfo?["ProgressValue"] as? Float
                            progressValue = progVal!
                            }
                    
                    ProgressBarTriangle(progress: self.$progressValue).frame(width: 280.0, height: 290.0).rotationEffect(.degrees(degress), anchor: .bottom)
                        .offset(x: 0, y: -150)
                }
                
                
                Spacer()
                    .frame(height: 20)
                VStack(alignment :.leading, spacing: 30) {
                    HStack {
                        if #available(iOS 16.0, *) {
                            Label("text:", image: "Icon")
                                .foregroundColor(Color(hex: "000"))
                                .fontWeight(.bold)
                        } else {
                            // Fallback on earlier versions
                            Label("Controller type:", image: "Icon")
                                .foregroundColor(Color(hex: "000"))
                        }
                        Text(Text1)
                        //app crashes when following code active:
                        //onReceive(publisher2) { obj in
                            //let Text1Val = obj.userInfo?["Text1Parameter"] as? String
                            //Text1 = Text1Val!
                        //}
                    }
                    
                    HStack {
                        if #available(iOS 16.0, *) {
                            Label("text:", image: "Icon")
                                .foregroundColor(Color(hex: "000"))
                                .fontWeight(.bold)
                        } else {
                            // Fallback on earlier versions
                            Label("text:", image: "IconSmall")
                                .foregroundColor(Color(hex: "000"))
                        }
                        Text(Text2)
                            .onReceive(publisher3) { obj in
                                let Text2Val = obj.userInfo?["Text2Parameter"] as? String
                                Text2 = connectionTextVal!
                            }
                    }
                    
                    HStack {
                        if #available(iOS 16.0, *) {
                            Label("text:", image: "Icon")
                                .foregroundColor(Color(hex: "000"))
                                .fontWeight(.bold)
                        } else {
                            // Fallback on earlier versions
                            Label("text:", image: "Icon")
                                .foregroundColor(Color(hex: "000"))
                        }
                        
                    }
                    
                    //four lines of status text
                    Text(fourLinesText)
                        .foregroundColor(Color(hex: "000"))
                        .lineLimit(4)
                        .multilineTextAlignment(.leading)
                        .onReceive(publisher4) { obj in
                            let Text3Val = obj.userInfo?["Text3Parameter"] as? String
                            fourLinesText = Text3Val!
                        }
                    
                    Spacer()
                }
                .padding(.leading, 20)
                .padding(.trailing, 20)
            }
        }
        
        public struct ProgressBar: View {
            //creating vars
            @Binding var progress: Float
            @State var addressText = "00000"
            @State var orangeText = "Orange Text"
            
            public func UpdateProgressValue(progressValue: Float)
            {
                progress = progressValue
            }
            
            var body: some View {
                
                VStack (alignment :.center, spacing: 30){
                    HStack {
                        Label("Address:", systemImage: "target")
                            .foregroundColor(Color(hex: "8f8f8f"))
                            .padding(.top, 15)
                        Text(addressText)
                            .foregroundColor(Color(hex: "8f8f8f"))
                            .padding(.top, 15)
                            //.onReceive(publisher6) { obj in
                                //let addressTextVal = obj.userInfo?["AddressTextParameter"] as? String
                                //addressText = addressTextVal!
                            //}
                    }
                    ZStack {
                        
                        Circle()
                            .trim(from: 0.35, to: 0.85)
                            .stroke(style: StrokeStyle(lineWidth: 12.0, lineCap: .round, lineJoin: .round))
                            .opacity(0.3)
                            .foregroundColor(Color.gray)
                            .rotationEffect(.degrees(54.5))
                        
                        Circle()
                            .trim(from: 0.35, to: CGFloat(self.progress))
                            .stroke(style: StrokeStyle(lineWidth: 12.0, lineCap: .round, lineJoin: .round))
                            .fill(AngularGradient(gradient: Gradient(stops: [
                                .init(color: Color.init(hex: "daff00"), location: 0.39000002),
                                .init(color: Color.init(hex: "00ff04"), location: 0.5999999),
                                .init(color: Color.init(hex: "32E1A0"), location: 0.8099997)]), center: .center))
                            .rotationEffect(.degrees(54.5))
                        
                        VStack(alignment :.center, spacing: 10) {
                            
                            Text("824").font(Font.system(size: 44)).bold().foregroundColor(Color.init(hex: "ffffff"))
                            
                            if #available(iOS 16.0, *) {
                                Label(orangeText, systemImage: "clock")
                                    .foregroundColor(Color(hex: "FF6600"))
                                    .fontWeight(.bold)
                                //.onReceive(publisher7) { obj in
                                    //let statusTextVal = obj.userInfo?["Text5Parameter"] as? String
                                    //orangeText = statusTextVal!
                                //}
                            } else {
                                // Fallback on earlier versions
                                Label(orangeText, systemImage: "clock")
                                    .foregroundColor(Color(hex: "FF6600"))
                                //.onReceive(publisher7) { obj in
                                    //let statusTextVal = obj.userInfo?["Text5Parameter"] as? String
                                    //orangeText = statusTextVal!
                                //}
                            }
                            
                            Text("Uploading memory model to controller")
                                .foregroundColor(Color(hex: "8f8f8f"))
                                .multilineTextAlignment(.center)
                                .onReceive(publisher5) { obj in
                                    let GreySubTextVal = obj.userInfo?["Text4Parameter"] as? String
                                    connectionTypeText = GreySubTextVal!
                                }
                            
                        }
                    }
                    
                }
                
            }
            
        }
        
        struct ProgressBarTriangle: View {
            @Binding var progress: Float
            
            
            var body: some View {
                ZStack {
                    Image("triangle").resizable().frame(width: 10, height: 10, alignment: .center)
                }
            }
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
}
    extension Color {
        init(hex: String) {
            let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
            var int: UInt64 = 0
            Scanner(string: hex).scanHexInt64(&int)
            let a, r, g, b: UInt64
            switch hex.count {
            case 3: // RGB (12-bit)
                (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
            case 6: // RGB (24-bit)
                (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
            case 8: // ARGB (32-bit)
                (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
            default:
                (a, r, g, b) = (1, 1, 1, 0)
            }
            
            self.init(
                .sRGB,
                red: Double(r) / 255,
                green: Double(g) / 255,
                blue:  Double(b) / 255,
                opacity: Double(a) / 255
            )
        }
        
    }

Solution

  • Your ProgressBar struct does not have any access to any instance members of ContentView or CMWSTUploadViewV2Controller. Just as ContentView does not have any access to any instance members of CMWSTUploadViewV2Controller.

    CMWSTUploadViewV2Controller.ContentView should only declare the publisherX properties that it needs. Your CMWSTUploadViewV2Controller.ContentView.ProgressBar struct should declare its own publisherX properties as needed.

    In other words, move the declarations for publisher5, publisher6, and publisher7 to be inside the ProgressBar struct instead of the ContentView struct.


    On a separate note, you should avoid hardcoding each of your notification names multiple times. It's too easy to make a typo for one of the names which will lead to a hard-to-find bug in your code. Define a constant for each notification name and use that constant in each place that it is needed.