1

I have a View Controller and two classes. Both ClassOne and ClassTwo have a reference to the view controller like so:

var viewController: ViewController?

Both the view controller and ClassTwo have a ClassOne variable that I've assigned like so, in order to retrieve other variables and call functions.

let class_one = ClassOne()

In ClassOne, I am trying to call a function in ClassTwo that uses class_one to call functions in ClassOne. For example, in ClassTwo:

func changeString() {
    self.class_one.string = "yada yada"
}

Here are different ways I have tried to call changeString() in ClassOne:

// Method one:
ClassTwo().changeString()

// Method two:
let class_two = ClassTwo()
self.class_two.changeString()

// Method three:
var class_two: ClassTwo?
self.class_two!.changeString()

When I run the app using method one, the app crashes and says the viewController and classOne references in ClassTwo are nil.

When I run the app using method two, it crashes and Xcode gives me the following memory warning, citing back and forth errors between the changeString() function call in ClassOne and my self.class_one.string variable call in ClassTwo.

Xcode memory warning - could not load any Objective-C class information

This isn't my actual code, but this is the problem I am facing. I'm a beginner with Swift, and I don't really understand what the difference is in all three of those ClassTwo function calls from ClassOne.

Can someone please explain what I'm doing wrong?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
wasimsandhu
  • 4,296
  • 9
  • 27
  • 40
  • How, where and when do you initialize the string variable in ClassOne? – Antonin Charvat Apr 17 '16 at 18:24
  • It is initialized in the class (not a global variable) like so: `var string: String!` – wasimsandhu Apr 17 '16 at 18:26
  • I guess that is the problem. By creating the class_one you create an instance of class, which haven't initialized its variables yet. – Antonin Charvat Apr 17 '16 at 18:35
  • I am currently learning iOS development and it looks like this is solved through Delegates. Check out this question about view controllers and passing data between them.. it's the sensible/idiomatic way to have classes talk to the view controller. http://stackoverflow.com/questions/24222640/passing-data-between-view-controllers-in-swift – sova Apr 17 '16 at 21:24
  • I'm not trying to pass data between the view controller and my two classes, I'm trying to pass data between the two classes... would this approach still work? – wasimsandhu Apr 17 '16 at 22:59
  • @wasimsandhu Take a look at this example http://stackoverflow.com/questions/34938682/swift-delegate-protocol-structure ..the accepted answer there shows how a delegate is organized: protocol in the swift file but outside / before the class definition, delegate inside where code gets updated/shifts/changes, and another class that "conforms to the protocol" in its signature line, and also a spot where the delegate's protocol functions are implemented. I believe this approach is very sensible and would make sense for your example as well. – sova Apr 18 '16 at 02:41

2 Answers2

0

Honestly it's impossible to determine the cause for the crashes from the information you've given. You'd have to post you're actual code, in greater detail than you have here.

The reason this is an answer though is because your scenario smacks of bad design. It sounds like you'd benefit from compartmentalising your code.

Example

If you have a class that is responsible for tracking user location you can instantiate it in your view controller like so:

let locationTracker = LocationTracker()

Then lets say that you need to parse the location values into a string you may have another class that is responsible for this:

let locationParser = LocationParser()

There is NO REASON here for locationParser and locationTracker to have a reference to each other OR the view controller e.g.

let location = locationTracker.currentLocation()
let locationAsString = locationParser.parseLocation(location)

Global functions

I hesitate to add this because it can lead to un-maintainable and disorganised code but in swift you can define a function outside of a class. Functions in a class are normally known as methods. When they're outside a class they're known as functions.

So you can have a swift file called Functions.swift and simply define:

func globalFunc() {

    print("Hello, World!")
}

This function cam be called from anywhere in your code.

Code Design

The way you structure and design your code is very important if you want to create a maintainable and essentially high quality pieces of software.

You'd benefit from reading up about different architectures and tools to help you organise your projects. Like:

MVC

MVVM

Reactive X

Dependency Injection

MVC is the Apple way, but you benefit from knowledge of other approaches. Also note that the dependency injection article gives Objective-C code examples. I know you're learning Swift but if you can it would be good to have a working knowledge of Objective-C. Apple's frameworks are still all written in Objective-C.

Rob Sanders
  • 5,197
  • 3
  • 31
  • 58
  • If I make ClassTwo a global function instead of a method in a class, `self.class_one.string` returns the error: `use of unresolved identifier: "self"` – wasimsandhu Apr 19 '16 at 01:25
  • I'm afraid I'm going to need more. You're giving barely any information. How is `ClassTwo` being used in `self.class_one.string`? If you really want help you'll need to post your code. – Rob Sanders Apr 19 '16 at 08:52
0

It looks like you are using the delegate model, in which case I think you have the optionals going in the wrong direction. You probably want ClassOne to definitely have a ViewController which it can manipulate as desired. Delegates always control some object, so ClassOne should have var viewController: ViewController. Not every ViewController needs a delegate -- at least, it makes sense to have a ViewController with no delegate (even if the result is a lousy view controller), while a delegate with no ViewController to manage is nonsense -- so your ViewController should have var class_one: ClassOne? = nil. You don't assign class_one in initialization because you need the view controller to exist before ClassOne may come into existence. Thus you set class_one after the view controller is initialized.

I think this may fix your problems by solving some of the internal dependencies. Also, it is not too lengthy a change.

BallpointBen
  • 9,406
  • 1
  • 32
  • 62