skip to Main Content

I am using Xcode 14.2 with both a SwiftUI file as well as an Objective-C file. It uses NotificationCenter to change my text and labels that I have within my SwiftUI. Part of my text (fourLinesText) is being cut off when it runs on an iPhone 8 but am unable to see it because the preview will not display anything and gives an error stating:

‘@objc’ can only be applied to an extension of a class

I have tried changing the class to @Objc extension class but am given the error: Expected type name in extension declaration

How can I restore the preview so I can see my app run in it?

enter image description here

enter image description here

enter image description here

Swift code:

import Foundation
import SwiftUI

@objc public protocol CMWUploadViewV2Delegate: NSObjectProtocol {
    @objc func uploadOKButtonPushed()
    @objc func uploadAbortButtonPushed()
    @objc func uploadErrorLogButtonPushed()
    @objc func uploadRetryButtonPushed()
}

@objc class CMWSTUploadViewV2Controller: 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: CMWUploadViewV2Delegate?
    
    //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.CMW.UpdateUploadProgress"), object: nil, userInfo:valueUpdate)
    }
    
    @objc func UpdateInitialText(InitialTextParameter: String)
    {
        let textUpdate:[String: String] = ["InitialTextParameter": InitialTextParameter]
        NotificationCenter.default.post(name:NSNotification.Name("COM.CMW.UpdateInitialText"), object: nil, userInfo:textUpdate)
    }
    
    @objc func UpdateAddressText(AddressTextParameter: String)
    {
        let textUpdate:[String: String] = ["AddressTextParameter": AddressTextParameter]
        NotificationCenter.default.post(name:NSNotification.Name("COM.CMW.UpdateAddressText"), object: nil, userInfo:textUpdate)
    }
    
    @objc func UpdateOrangeText(OrangeTextParameter: String)
    {
        let textUpdate:[String: String] = ["OrangeTextParameter": OrangeTextParameter]
        NotificationCenter.default.post(name:NSNotification.Name("COM.CMW.UpdateOrangeText"), object: nil, userInfo:textUpdate)
    }
    
    @objc func UpdateGreySubText(GreySubTextParameter: String)
    {
        let textUpdate:[String: String] = ["GreySubTextParameter": GreySubTextParameter]
        NotificationCenter.default.post(name:NSNotification.Name("COM.CMW.UpdateGreySubText"), object: nil, userInfo:textUpdate)
    }
    
  
    @objc func UpdateControllerTypeText(ControllerTypeTextParameter: String)
    {
        let textUpdate:[String: String] = ["ControllerTypeTextParameter": ControllerTypeTextParameter]
        NotificationCenter.default.post(name:NSNotification.Name("COM.CMW.UpdateControllerTypeText"), object: nil, userInfo:textUpdate)
    }
    
     @objc func UpdateConnectionTypeText(ConnectionTypeTextParameter: String)
     {
         let textUpdate:[String: String] = ["ConnectionTypeTextParameter": ConnectionTypeTextParameter]
         NotificationCenter.default.post(name:NSNotification.Name("COM.CMW.UpdateConnectionTypeText"), object: nil, userInfo:textUpdate)
     }
    
     @objc func UpdateStatusText(StatusTextParameter: String)
     {
         let textUpdate:[String: String] = ["StatusTextParameter": StatusTextParameter]
         NotificationCenter.default.post(name:NSNotification.Name("COM.CMW.UpdateStatusText"), 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 GreySubText = ""
        let label = UILabel()
        @State var buttonText1 = ""
        @State var buttonText2 = ""
        @State var controllerTypeText = ""
        @State var connectionTypeText = "CAN"
        @State var statusText = "Status text here"
        @State var fourLinesText = "More status text here. Controller responding. 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 initialText = "Resetting to upload mode."
        
        //setting up notification center to listen to addresses
        let publisher = NotificationCenter.default.publisher(for: NSNotification.Name("COM.CMW.UpdateUploadProgress"))
        let publisher8 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.CMW.UpdateInitialText"))
        //let publisher6 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.CMW.UpdateAddressText"))
        //let publisher7 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.CMW.UpdateOrangeText"))
        //let publisher5 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.CMW.UpdateGreySubText"))
        let publisher2 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.CMW.UpdateControllerTypeText"))
        let publisher3 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.CMW.UpdateConnectionTypeText"))
        let publisher4 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.CMW.UpdateStatusText"))
        
        //display
        var body: some View {
            VStack {
                Spacer()
                    .frame(height: 70)
                
                if #available(iOS 16.0, *) {
                    Label(initialText, systemImage: "clock")
                        .font(.title)
                        .foregroundColor(Color(hex: "000"))
                        .fontWeight(.bold)
                        .onReceive(publisher8) { obj in
                            let initialTextVal = obj.userInfo?["InitialTextParameter"] as? String
                            initialText = initialTextVal!
                        }

                } else {
                    // Fallback on earlier versions
                    Label(initialText, systemImage: "clock")
                        .font(.title)
                        .foregroundColor(Color(hex: "000"))
                        .onReceive(publisher8) { obj in
                            let initialTextVal = obj.userInfo?["InitialTextParameter"] as? String
                            initialText = initialTextVal!
                        }
                }
                    
                    
                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)
                }
                
                //***Controller, Connection, and Status labels/text
                Spacer()
                    .frame(height: 20)
                VStack(alignment :.leading, spacing: 30) {
                    HStack {
                        if #available(iOS 16.0, *) {
                            Label("Controller type:", image: "ControllerIcon")
                                .foregroundColor(Color(hex: "000"))
                                .fontWeight(.bold)
                        } else {
                            // Fallback on earlier versions
                            Label("Controller type:", image: "ControllerIcon")
                                .foregroundColor(Color(hex: "000"))
                        }
                        Text(controllerTypeText)
                        //app crashes when following code active:
                        //onReceive(publisher2) { obj in
                            //let controllerTextVal = //obj.userInfo?["ControllerTypeTextParameter"] as? String
                            //controllerTypeText = controllerTextVal!
                        //}
                    }
                    
                    HStack {
                        if #available(iOS 16.0, *) {
                            Label("Connection type:", image: "CANIconSmall")
                                .foregroundColor(Color(hex: "000"))
                                .fontWeight(.bold)
                        } else {
                            // Fallback on earlier versions
                            Label("Connection type:", image: "CANIconSmall")
                                .foregroundColor(Color(hex: "000"))
                        }
                        Text(connectionTypeText)
                            .onReceive(publisher3) { obj in
                                let connectionTextVal = obj.userInfo?["ConnectionTypeTextParameter"] as? String
                                connectionTypeText = connectionTextVal!
                            }
                    }
                    
                    HStack {
                        if #available(iOS 16.0, *) {
                            Label("Status:", image: "StatusIcon")
                                .foregroundColor(Color(hex: "000"))
                                .fontWeight(.bold)
                        } else {
                            // Fallback on earlier versions
                            Label("Status:", image: "StatusIcon")
                                .foregroundColor(Color(hex: "000"))
                        }
                        
                    }
                    
                    //four lines of status text
                    Text(fourLinesText)
                        .foregroundColor(Color(hex: "000"))
                        .lineLimit(4)
                        .multilineTextAlignment(.leading)
                        .onReceive(publisher4) { obj in
                            let statusTextVal = obj.userInfo?["StatusTextParameter"] as? String
                            fourLinesText = statusTextVal!
                        }
                    
                    Spacer()
                }
                .padding(.leading, 20)
                .padding(.trailing, 20)
            }
        }
        
        public struct ProgressBar: View {
            //creating vars
            @Binding var progress: Float
            @State var addressText = "0x1c000"
            @State var orangeText = "Orange Text"
            @State var GreySubText = ""
            
            let publisher7 = NotificationCenter.default.publisher(for:
                NSNotification.Name("COM.CMW.UpdateOrangeText"))
            let publisher6 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.CMW.UpdateAddressText"))
            let publisher5 = NotificationCenter.default.publisher(for: NSNotification.Name("COM.CMW.UpdateGreySubText"))
            
            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?["OrangeTextParameter"] 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?["OrangeTextParameter"] as? String
                                    orangeText = statusTextVal!
                                }
                            }
                            
                            Text(GreySubText)
                                .foregroundColor(Color(hex: "8f8f8f"))
                                .multilineTextAlignment(.center)
                                .onReceive(publisher5) { obj in
                                    let GreySubTextVal = obj.userInfo?["GreySubTextParameter"] as? String
                                    GreySubText = 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
            )
        }
        
    }

Objective C code:

-(void)summerTestUploadViewController
{
    CMWSTUploadViewV2Controller* myView = [[UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:@"ID_CMW_UPLOADVIEWV2_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. 4 lines of text will be allowed in this area.  4 lines of text will be allowed in this area.  4 lines of text will be allowed in this area.  4 lines of text will be allowed in this area.  4 lines of text will be allowed in this area."];
        
    }];
}

2

Answers


  1. Chosen as BEST ANSWER

    When I remove the attribute @objc for the class CMWSTUploadViewV2Controller it allows me to view it in the preview pane to see how my constraints behave.


  2. To address your issue with the SwiftUI preview not displaying and the error message about ‘@objc’ in Xcode 14.2, and to view your layout on an iPhone 8 for adjustments, here’s a summary of what you can do:

    1. Fixing the ‘@objc’ Error: The error message "’@objc’ can only be applied to an extension of a class" suggests there’s a mismatch in how ‘@objc’ attributes are used in your code. Make sure they are only applied to members of an Objective-C compatible class or an extension of such a class.

    2. Previewing on an iPhone 8:

      • Using an iPhone 8 Simulator: Instead of relying on SwiftUI previews, run your app on an iPhone 8 simulator to see how it looks and behaves on that specific device. This can be done directly from Xcode by choosing an iPhone 8 from the list of simulators.
      • Adjusting Layout for Smaller Screens: If text is being cut off on an iPhone 8, it indicates that your layout might not be responsive to smaller screen sizes. Utilize SwiftUI’s adaptive layout features, like GeometryReader, flexible frames, or ScrollView, to make your UI elements adjust dynamically to different screen sizes.
      • Debugging in Simulator: Use Xcode’s debugging tools while running your app in the simulator to inspect the UI and determine what’s causing the text to be cut off. You can use breakpoints and view the UI hierarchy to get a better understanding of the layout issues.
    3. General Tips:

      • Optimize for Multiple Devices: Design your SwiftUI views to be flexible and responsive to different screen sizes and orientations. This ensures a consistent user experience across all devices.
      • Test Regularly: Regularly test your app on various devices and simulators to catch and fix layout issues early in the development process.

    By fixing the ‘@objc’ usage in your code and using the iPhone 8 simulator to test and adjust your layout, you should be able to address the text cutoff issue effectively. Remember to regularly test on different devices to ensure compatibility and a good user experience.

    Let me know if it worked for you. 🙂

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search