Imagine I have a Core Data object, Product. Each Product has a quantity, price, and total attribute. Total is there for efficiency when retrieving items from the table. (I understand that there may be an efficient way to get the computed value using fetched properties, but this is only an example, and that answer is not what I am looking for.)
+------+----------+-------+-------+
| Name | Quantity | Price | Total |
+------+----------+-------+-------+
| Foo | 1 | 20 | 20 |
| Bar | 0 | 30 | 0 |
| Baz | 3 | 5 | 15 |
+------+----------+-------+-------+
Assume that the price of a product never changes. However, the quantity does change. Whenever the quantity changes, I would like to be notified so that I can recompute the total. I would like to avoid using KVO if possible because I have a custom NSManagedObject class, product, and I would like to override one of its methods in order to update the price and not have to worry about registering/unregistering for notifications on its own attributes.
This method should only be called when the price is changed, not every time any of the attributes on the object has changed.
I would also like this method to be triggered right when the value is changed (e.g. not right before the context is saved), so that I can access the new total attribute before the context is saved.
Which method should I override and can it be done in a category on my Product class?
Note: this question is similar but is mainly concerned with running more than one thread, which may require more complicated answers. I am looking for something simple, on a single thread.
You should override the setter method for the quantity attribute of your entity:
- (void)setQuantity:(NSNumber *)quantity
{
[self willChangeValueForKey:#"quantity"];
[self setPrimitiveValue:quantity forKey:#"quantity"];
[self didChangeValueForKey:#"quantity"];
NSNumber *price = ... // compute new price
self.price = price;
}
You can add that code to a category of the Product class if you don't want to change
the Xcode generated files.
Related
This post is more a discussion about a current problem I face with an app I'm building. I'd love to hear different people's opinions on how they'd implement this :) I'm using redux for the example but this question really extends to all front-end state management.
I'm building an app that is a paginated newsfeed-type list that loads the results 10 posts at a time. When I reach the bottom of that list then it will fetch another 10 posts and append to the list.
I'm managing my state as a hash of posts and a list of paginated ids. Every time I reach the end of the list I fetch the next set of results from my offset and push the new ids to the end of the list and this all works great.
{
posts: {
a: {
content: 'some content'
points: 100
},
b: {
content: 'some other content'
points: 98
},
c: { ... },
d: { ... },
e: { ... },
.
.
.
},
popularPosts: [
'a',
'b',
'd',
'e'
.
.
.
],
newPosts: [...]
}
The problem is that I have functionality to pull down to refresh at the top of the list and fetch the latest top posts (like the way you can in the Twitter or 9gag apps).
The issue is that ordering by points is dynamic. So for example, at the time of the first request my posts ordered by points above is [a, b, d, e]. Now, what happens if people up-vote post 'b' a few points and now the order on the server is [b, a, d, e] when I refresh the next time. I could naively find a common sequence between the new order of the ids from the server and the existing order in the state and append the diff to the top of the list, but this a very basic example and you can see that for a high volume app the state will quickly become out of sync and introduce potential duplications.
It would be nice to cache as much as possible from the posts already loaded in the app and try to figure out where/how in the existing list of paginated ids I can reconcile. The easy solution is to wipe the state and start again, I'm just wondering if anyone has any experience of this and how they solved it?
great question, for my part, at each refresh, i would use Array.sort and give it my compareFunction, so the element of my 10 posts will be sort as i wish.
Take a look at http://devdocs.io/javascript/global_objects/array/sort
I have faced similar kind of difficulty. So basically, you modify your state in 2 possible ways: 1. pagination and 2. pull to refresh.
Let's say you have 2 different actions for both of them: FETCH_POSTS_SUCCESS for pagination and FETCH_POST_REFRESH for pull to refresh.
Whenever you fire FETCH_POSTS_SUCCESS action, you should append the next 10 post IDs and when FETCH_POST_REFRESH action is fired, you flush the state array and append first 10 post ids which are there on the server itself. You don't need to keep the paginated ids when you refresh, you just need first 10 IDs only at the time of initialisation and anytime you refresh.
I'm going to attempt to post my own solution and seek some constructive criticism on it :) For the purpose of making my solution easy to follow I'm going to use a page size of 4 posts instead of 10.
Let's say we have a list of 10 posts (so 3 page loads in this example)
id | points |
-------------
a | 100
b | 90
c | 87
d | 43
-------------
e | 30
f | 12
g | 5
h | 4
-------------
i | 3
j | 3
Now let's say I pull down to refresh and I get another 4 posts with the following results (some of which are already cached, but obviously with stale points)
id | points |
-------------
g | 120
z | 115
h | 113
e | 112
I know that my these results are sorted and I know that my cached results are sorted so all I need to do is pluck any common keys from my cached set (I can even query my posts hash from my question to build a list of search candidates without iterating for every item). When these ids are plucked then my cached entries should look like this.
id | points |
-------------
a | 100
b | 90
c | 87
d | 43
f | 12
i | 3
j | 3
Now I know my new results set are higher in points than my cached set so I simply stack them on top to give me
id | points |
-------------
g | 120
z | 115
h | 113
e | 112
a | 100
b | 90
c | 87
d | 43
f | 12
i | 3
j | 3
So the only issue I now have is determining if the new number of results that differ from the cached results are greater than the page size and under what criteria to I do another page fetch until I sync everything up. I could naively keep fetching until the sequence of my new results set matches a sequence in my cached results set
I know there's loads of edge cases here, just wanted to do a brain dump :)
In Specflow, although I know about the Scenario Outline / Examples feature, I was wondering if there is a more elegant way to generate ranges and combinations to be used in test cases?
For example, in vanilla NUnit, I can use a TestCaseSource or Theory to build a generator which I can feed in a large number of test cases into a test.
private static readonly IEnumerable<int> Numbers = Enumerable.Range(1, 50);
[TestCaseSource(nameof(Numbers))]
public void TestFoo(int number)
{
// Test goes here.
}
At present, in my tests, I need to manually create all permutations in my Examples, which can be hard to read, and potentially error prone.
Scenario Outline: Count things
Given I'm playing a game of counting
When I count to <number>
Then the highest number I should have counted to should be <number>
Examples:
| number|
| 1 |
| 2 |
| 3 |
...
| 50 |
What I would really like to be able to do would be
Examples:
| number| : Range 1 to 20
And even better, create the cartesian product of two sets, i.e.:
Examples:
| number1| : Range 1 to 20
| number2| : Range 5 to 10
// i.e. 20 x 5 = 100 combinations of the tuple (number1, number2)
Is there anyway for me to approach this more elegantly in Specflow?
You can dynamically generate the range of numbers from two inputs as a step.
For example:
Scenario Outline: Count things
Given I'm playing a game of counting
When I count from <First Number> to <Last Number>
Then the highest number I should have counted to should be <Last Number>
Examples:
| Description | First Number| Last Number |
| Count from 1 to 20 | 1 | 20 |
| Count from 5 to 10 | 5 | 10 |
And then the When step can be defined as something like this:
[When("I count from (\d+) to (\d+)")]
public void ICountFromFirstNumberToLastNumber(int firstNumber, int lastNumber)
{
IEnumerable<int> numbers = Enumerable.Range(firstNumber, lastNumber);
this.countResult = this.Count(numbers);
}
Cucumber is not designed to for doing this sort of testing. When you are cuking each scenario is going to have a runtime which is one or more orders of magnitude slower than a well written unit test. So generating large numbers of scenarios makes your test suite unusable.
Cucumber is all about using scenarios to create a few basic interactions to drive the development of some functionality. Its not a test tool!
To test exhaustively some aspect of functionality keep on using unit tests.
I wan't really sure how to title this one, but I'll try and explain this the best I can.
I've got a workbook and on my Dashboard I have a table that lists the stats I want to provide. It's all about helpdesk tickets, so I want to know how many tickets each group has raised. In my data though, each ticket is listed by the persons name, not group.
What I have done is created a table in my 'Data' sheet where the name is next to the group. For example:
| A1 | A2 |
|:-----------------|------------:|
| John Smith | Helpdesk |
| Ben Jones | Helpdesk |
| Will Smith | Management |
What I want to do is say:
On my 'Tickets' sheet, give me the total number of rows where the name is equal to that of the group I want to check.
The results would be something like:
| Group | Tickets |
|:-----------------|------------:|
| Helpdesk | 5|
| Management | 2|
Im a little unsure on where to even start with this one
so I want to know how many tickets each group has raised.
Do you need the total Count of tickets raised by group?
Try this formula to calculate the number of tickets per department, in the second column of the resulttable (starting at B2 and copy down). In the first column are the department names, starting at A2.
=SUMPRODUCT(--(LOOKUP(Tickets!A1:A100,UserDeparment!A1:B20)=Results!A2))
Tickets!A1:A100 are the users for every ticket (ticketData). UserDeparment!A1:B20 holds the department (Column B) for each User (Column A).
I'm trying to add a custom 'discount' list to my spreadsheet.
I've got a table that contains all the data, and has costs for the standard 'used' value, then also the values at a 5% discount and a 10% discount.
Example:
+---------+-------------------+------+------------+-------------+
| Code | Role | Used | Used - 5% | Used - 10% |
+=========+===================+======+============+=============+
| Test001 | Employee | 5.67 | | |
+---------+-------------------+------+------------+-------------+
| Test002 | Junior Technician | 9.80 | 9.31 | 8.38 |
+---------+-------------------+------+------------+-------------+
| Test003 | Project Manager | 15 | | |
+---------+-------------------+------+------------+-------------+
| Test004 | Engineer | 20 | 19 | 17.10 |
+---------+-------------------+------+------------+-------------+
I've then got a Data validation list which returns all other the 'Roles' to select from. On the back of this this populates the Cost cell.
Example:
+----------+----------+----------+-------+
| Role | VLOOKUP | Discount | Cost |
+==========+==========+==========+=======+
| Employee | | | 5.67 |
+----------+----------+----------+-------+
| Engineer | 5%,10% | 10% | 15.10 |
+----------+----------+----------+-------+
What I want to do is have a list to be populated with 5%, 10% if there is that option. I'd like to achieve this without vba (I could easily achieve this with vba but trying to keep it all in the worksheet)
My VLOOKUP Column is populated using:
=CONCATENATE(IF(VLOOKUP(A2,INDIRECT("Test[[Role]:[Used - 10%]]"), 3, FALSE) <> "", "5%", ""),
IF(VLOOKUP(A2,INDIRECT("Test[[Role]:[Used - 10%]]"), 4, FALSE) <> "", ",10%", ""))
The issue comes when trying to do the data validation. It accepts the formula (tried using the above to no avail in the data validation) but populates the drop down list with just the one value of 5%,10% instead of interpreting it as a csv.
I'm currently using this to attempt to populate the Discount Drop Down
=OFFSET(INDIRECT(ADDRESS(ROW(), COLUMN())),0, -1)
It is possible assuming your version of Excel has access to the dynamic functions FILTER and UNIQUE. Let's go through a couple of things, and here is a google doc where this is demonstrated. I also included an online excel file*.
It isn't necessary to calculate the cost in the setup table (A:E). You can just use a character to mark availability (and in some versions it was difficult to make the FILTER work with comparisons like <>"", etc, when ="x" worked fine).
You can get an array of available discounts by using FILTER, INDEX and MATCH. See Col P. You use INDEX/MATCH to return a single row of the array containing the discounts (in this case D:E), and then use that row to filter the top row (D1:E1) which has the friendly discount names and return it as an array.
It isn't necessary to concat the discount list the way you're doing. You can use TEXTJOIN, FILTER, INDEX and MATCH. See Col I. You just wrap the calculation that generates the array of discount names (step 2) in TEXTJOIN to get a string.
The validation is accomplished by referencing the output of step 2. I don't think that the data validation dialog can handle the full formula, so I pointed it to Cols O:Q. Col O is included in the validation so that you can get an empty spot at the top of the list, but Google Docs seems to strip it out.
You can just calculate the discounted cost from the selected option. See Col K. I included the original cost in Col L so you can see it.
you will need a microsoft account to view
having a tough time figuring out how to model the expected product behavior.
Basically, the customer's inventory is managed along products and skus.
A product has many skus, but a single sku accounts for several product attributes.
Let me give an example.
Let's say i'm selling you a shirt. "Shirt" is the product with some product ID. If it comes in small, medium, large, then each of those sizes would be associated with a sku #.
easy enough so far, but if the shirt also comes in multiple colors, let's say red, yellow, and green, then there will be nine skus (red/small, red/medium, red/large, yellow/small, and so on).
Add to that the challenge that the types of attributes can be different for different products. A shirt might have sizes and colors, a handbag might have different handle styles or patterns, and I won't know ahead of time, these are things that the customer needs to be able to input in an adhoc fashion.
Any ideas on how to approach this from a DDD perspective? I"ve been baking my noodle on it for a few days now.
Thanks.
First of all you have to regard each sku as a single product attribute and not combine them. If a product can have a color and a size, these are two distinct attributes, not one (as in red/small, red/medium, etc). Suppose a product has five attributes, each with 4 possible values. You would then have 4^5=1024 skus. This quickly becomes a maintenance nightmare.
So, the first two objects in your domain model should be ProductDefinition and Attribute. The reason I choose ProductDefinition as a name and not Product is that this is just a label for some product type, a shirt for example. It is not yet a small yellow shirt.
Attributes can have possible values, so this makes for a third domain object: AttributeValue. The relation between Attribute and AttributeValue is 1:n. An attribute has multiple values, a value only belongs to one attribute.
Note that AttributeValue contains all possible values for an attribute, not the actual value for a single product. This actual value becomes a relation between ProductDefinition, Attribute and AttributeValue: ProductAttributeValue. Up for the shirt example in a database model:
ProductDefinition Attribute AttributeValue
1 | Shirt 1 | Color 1 | 1 | Red
2 | Size 2 | 1 | Yellow
3 | 1 | Green
4 | 2 | Small
5 | 2 | Medium
6 | 2 | Large
We have now modeled one product definition, two attributes and three attribute values per attribute. Suppose now we want to model three shirts: a small red one, a small green one and a large yellow one. This results in the following ProductAttributeValue content (ProductId, ProductDefinitionId, AttributeId, AttributeValueId):
ProductAttributeValue
1 | 1 | 1 | 1
1 | 1 | 2 | 4
2 | 1 | 1 | 3
2 | 1 | 2 | 4
3 | 1 | 1 | 2
3 | 1 | 2 | 2
We did a system like this..
ProductDefinition
has Type (Shirt, Handbag)
has many ProductFieldDefinition
ProductFieldDefinition
has Type (Color, size, pattern)
Product
has ProductDefinition
has SKU
has many ProductField
has ProductFieldDefinition
has Value
The one thing I would change in our system is I would use a Document Database to store everything but in our case the graph actually went much deeper with each level having it's own fields.