Initialize Adafruit IO Global Class Inside Setup

Hello! I'm having some issues with the Adafruit IO Arduino library. I don't have much experience with OOP and I think that's my issue. I am using WifiManager to connect to WiFi on an ESP82666 and it is also collected Adafruit IO usernames/keys and storing that in EEPROM. My issue is that I can only initialize my AIO object once I have my keys which I only get in the end of setup, but if I initialize AIO in setup it's not global and I can't run io.run() in my loop anymore. I'm sure this is a simple OOP issue that I just don't understand yet. Thanks for any help!

Entire Code:

#include <EEPROM.h>
#include <WiFiManager.h>
#include "AdafruitIO_WiFi.h"


WiFiManager wm; // global wm instance

//Struct to store Adafruit IO data
struct { 
    char IOUsername[32] = "";
    char IOKey[36] = "";
} IOSettings;

///////////DIMMER SETTINGS//////////
////////////////////////////////////


int AC_LOAD = D2;    // Output to Opto Triac pin
int dimming = 0;  // Dimming level (0-128)  0 = ON, 128 = OFF


float frequency = 60.0; //50 or 60 hertz
int steps = 256; //Stepps between off and completely on


int onVal = 200; //The brightness that the lamp is "on." Decrease value for dimmer lamp

bool waiting = false;
int timer = 0;

int fadeTime = 3600000; //time that the light fades in milliseconds (60 minutes)

int currentVal = 0;
float zeroCrossInt = (((1 / frequency) / 2) * 1000);
float intPerStep = ((1000 * zeroCrossInt) / steps);

bool fadeOffActive = false;
bool slowPulseActive = false;

long lastMillis = 0;



void setup() {

  //setup
  WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP  
  Serial.begin(115200);
  Serial.setDebugOutput(true);  

  //Triac setup
  pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
  attachInterrupt(D1, zero_crosss_int, RISING);  // Choose the zero cross interrupt # from the table above

  
  delay(3000);
  Serial.println("\n Starting");

  
  //start EEPROM 
  EEPROM.begin(68);
  
  //get stored Adafruit IO dataa
  EEPROM.get(0, IOSettings);


  //Adafruit IO data parameter for WifiManager
  WiFiManagerParameter IOUsername("IOUsername", "Adafruit IO Username", IOSettings.IOUsername, 32);
  WiFiManagerParameter IOKey("IOKey", "Adafruit IO Key", IOSettings.IOKey, 36);

  wm.addParameter(&IOUsername);
  wm.addParameter(&IOKey);

  //Set the parameter callback function and include the parameters on the main page.
  wm.setParamsPage(false);
  wm.setSaveParamsCallback(saveParamCallback);

  //Menu setup
  std::vector<const char *> menu = {"wifi","sep","restart","exit"};
  wm.setMenu(menu);
  
  // set dark theme
  wm.setClass("invert");


  //Setup WifiManager AP
  bool res;
  res = wm.autoConnect("LoveLamp Setup","lovelamp"); 

  if(!res) {
    Serial.println("Failed to connect or hit timeout");
     //ESP.restart();
  } 
  else {
    //if you get here you have connected to the WiFi   
    Serial.println("Connected to WiFi!");
 
  }

  //setup Adafruit IO library parameters 
  AdafruitIO_WiFi io(IOSettings.IOUsername, IOSettings.IOKey, "", "");
  AdafruitIO_Feed *lamp = io.feed("lamp");


  //connect to Adafruit IO
  Serial.println("Connecting to Adafruit IO");
  io.connect();


  //Setup message handler
  lamp->onMessage(handleMessage);

  // wait for a connection
  while(io.status() < AIO_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  lamp->get();
  
  // we are connected!
  Serial.println();
  Serial.println(io.statusText());


  
}


void loop() {
  
io.run();

}


//the interrupt function must take no parameters and return nothing
ICACHE_RAM_ATTR void zero_crosss_int()  //function to be fired at the zero crossing to dim the light
{
  
  //Unstable behavior for low brightness levels
  if (dimming <= 10) { return; }
  
  int delayTime = (intPerStep*map(dimming, 255, 0, 0, 255));    // For 60Hz =>65  
  
  delayMicroseconds(delayTime);    // Wait till firing the TRIAC    
  digitalWrite(AC_LOAD, HIGH);   // Fire the TRIAC
  delayMicroseconds(8.33);         // triac On propogation delay 
  digitalWrite(AC_LOAD, LOW);    // No longer trigger the TRIAC (the next zero crossing will swith it off) TRIAC
  
}



String getParam(String name){
  //read parameter from server, for customhmtl input
  String value;
  if(wm.server->hasArg(name)) {
    value = wm.server->arg(name);
  }
  return value;
}

//Save Adafruit IO parameters
void saveParamCallback(){
  
  //Set the struct to the new data
  getParam("IOUsername").toCharArray(IOSettings.IOUsername, 32);
  getParam("IOKey").toCharArray(IOSettings.IOKey, 36);
  
  //Store and commit to EEPROM
  EEPROM.put(0, IOSettings);
  EEPROM.commit();


  
}

void handleMessage(AdafruitIO_Data *data) {

  Serial.print("received <- ");
  Serial.println(data->value());

}


Issue section (Inside setup):

//setup Adafruit IO library parameters 
  AdafruitIO_WiFi io(IOSettings.IOUsername, IOSettings.IOKey, "", "");
  AdafruitIO_Feed *lamp = io.feed("lamp");


  //connect to Adafruit IO
  Serial.println("Connecting to Adafruit IO");
  io.connect();


  //Setup message handler
  lamp->onMessage(handleMessage);

  // wait for a connection
  while(io.status() < AIO_CONNECTED) {
    Serial.print(".");
    delay(500);
  }

  lamp->get();
  
  // we are connected!
  Serial.println();
  Serial.println(io.statusText());

Define a Global pointer to an AdafruitIO_WiFi object. Then create the object dynamically in setup() when you're ready:

AdafruitIO_WiFi *ioPtr;

void setup() {

  ioPtr = new AdafruitIO_WiFi(IOSettings.IOUsername, IOSettings.IOKey, "", "");

}